🟢 PurpleAir AQI Notifier

Free Telegram alerts the moment air quality crosses a threshold that matters — powered by community PurpleAir sensors, corrected the way the EPA recommends.

Open the bot on Telegram →

What it does

This bot watches PurpleAir sensors for the locations people subscribe to and sends a Telegram message the moment the air quality category changes — good → moderate, moderate → unhealthy, and so on, in either direction. No app besides Telegram, no account, no cost.

Get started in under a minute:

  1. Open the bot and tap Start.
  2. Send /subscribe leadville-co — Leadville, CO ships out of the box.
  3. Want a different town? /addlocation boulder-co finds the nearest active sensor automatically.

You can subscribe to more than one location, check /status any time, and /unsubscribe whenever you want. Full walkthrough (including how to point it at a specific sensor by hand) is in the user guide.

Why the numbers may differ from PurpleAir's own map

If you check a sensor on PurpleAir's map and compare it to what this bot reports, don't be surprised if the numbers don't match — often by a meaningful margin. That's expected, not a bug. Here's why.

PurpleAir sensors are low-cost laser particle counters. They're great at detecting relative change in real time, but on their own they systematically overestimate true PM2.5 concentration compared to EPA reference-grade monitors — and the size of that overestimation gets worse in dry air and at high altitude, which describes plenty of the mountain towns this bot was built for. PurpleAir's own map, by default, shows AQI computed straight from the raw sensor reading, with no adjustment for this known bias.

This bot instead applies the correction formula published by Barkjohn, Norris & Clements (2021) — developed specifically for PurpleAir sensors, using co-located reference monitors, and the correction the US EPA itself recommends and uses on its AirNow Fire and Smoke Map. In plain terms: it takes the average of the sensor's two PM2.5 channels plus the local humidity and temperature, and produces a value closer to what a reference-grade monitor would read at that spot.

The formula

// pm25 = average of the sensor's A/B channel readings (µg/m³) // rh = relative humidity (%) temp = temperature (°F) if (pm25 < 343) { corrected = 0.541 * pm25 - 0.0618 * rh + 0.00534 * temp + 3.634 } else { // separate high-concentration fit - relevant during heavy wildfire smoke corrected = 0.46 * pm25 + 0.000393 * pm25^2 + 2.97 }

That corrected PM2.5 value then goes through the 2024-revised EPA breakpoint table (below) to get the final AQI this bot reports — which is why every AQI value it sends is labeled (EPA-corrected).

Try it yourself

This chart plots the exact formula above: raw PurpleAir AQI (uncorrected) vs. the EPA-corrected AQI this bot actually reports, across a range of PM2.5 readings. Drag the sliders — notice how the gap between the two lines grows in drier air, which is exactly the mismatch people notice when comparing this bot to PurpleAir's map in a place like Leadville, CO.

Raw vs. EPA-corrected AQI Line chart comparing uncorrected PurpleAir AQI to EPA-corrected AQI as raw PM2.5 increases.
Raw / uncorrected AQI (PurpleAir's default map display) EPA-corrected AQI (what this bot reports)
At 38 µg/m³ raw PM2.5 (Leadville's actual reading today)
EPA-corrected

A real example: Leadville, CO

We pulled live data on a dry summer afternoon from the sensor this bot uses in Leadville, plus three others within a couple hundred meters of it (conditions varied slightly sensor to sensor, so each row uses its own actual humidity/temperature reading):

SensorRaw PM2.5 (µg/m³)RHTempRaw / uncorrected AQIEPA-corrected AQI
Sloan_flex-f877 (used by this bot)38.011%83°F10779
Sloan_flex-d54e38.110%85°F10779
East 4th35.010%80°F9976
Sloan_zen-233.812%92°F9774

All four sensors agree closely with each other once corrected. The ~20-30 point gap between each sensor's raw and corrected AQI isn't sensor disagreement — it's the same known overestimation bias, showing up consistently across every nearby sensor, in exactly the dry/high-altitude conditions where it's most pronounced.

AQI levels this bot alerts on

You get a message any time a subscribed location crosses one of these boundaries, in either direction:

LevelAQI rangeWhat it means
🟢 Good0–50Air quality is fine for everyone.
🟡 Moderate51–100Fine for most people; take it easier outside if you have asthma or another breathing condition.
🟠 Unhealthy for Sensitive Groups101–150Kids, older adults, and anyone with heart or lung conditions should limit time outdoors.
🔴 Unhealthy151–200Everyone may start to notice effects. Limit outdoor activity.
🟣 Very Unhealthy201–300Health alert — avoid outdoor activity if you can.
🟤 Hazardous301+Emergency conditions — stay indoors.

More detail on any level: airnow.gov/aqi/aqi-basics

Sensor health checks

PurpleAir sensors have two independent PM2.5 channels that normally agree closely. Occasionally one channel fails (dust, insects, moisture) and reports wildly different numbers from the other — this bot checks for that disagreement before trusting a reading. If it finds a diverging sensor, it automatically looks for a nearby healthy sensor and switches the location to it, and lets subscribers know when that happens. If no healthy sensor is nearby, it says so rather than silently reporting a broken reading.

Sources & further reading