# How an alert reaches you

> Three independent feeds out of the National Weather Service, one deduplicated pipeline, and a broker that pushes the warning to you about forty seconds after the office issued it.

Alerts and places · Concept · https://wxalerts.org/docs/alerts/how-alerts-reach-you/

A tornado warning starts as a few hundred bytes of text typed at a Weather
Forecast Office. Everything after that is plumbing, and the plumbing is where
most of the delay in getting it to you comes from.

WxAlerts exists to make that plumbing short. We take the product from three
independent feeds at once, keep whichever copy arrives first, and push it
straight to subscribers. Median time from the office pressing send to the alert
being on the broker is about **40 seconds**.

## Where warnings come from

Every hazard product is issued by one of 122 Weather Forecast Offices. The
office writes the text, the polygon and the VTEC line: the machine-readable
code that says *which office, what phenomenon, watch or warning, which event
number, what year*. That VTEC key is what makes an alert trackable: the initial
warning, the severe weather statement ten minutes later and the cancellation are
all the same event.

From the office, the product enters national dissemination, and that is where
the paths fork.

```
                         ┌──▶ NWWS-OI  (XMPP push)  ──┐
WFO issues product ──────┼──▶ api.weather.gov (poll) ─┼──▶ WxAlerts ingest ──▶ you
                         └──▶ EMWIN via GOES-19 ──────┘     parse · dedupe ·
                                                            geometry · publish
```

## Three feeds, on purpose

Any one of these can go down, and over a long enough season all of them will.
None of them is a fallback: all three run continuously, and the pipeline keeps
whichever copy of a product shows up first.

| Feed | Transport | Median from issuance | Fails when |
| --- | --- | --- | --- |
| **NWWS-OI** | XMPP push from NOAA | 41 s | NOAA's XMPP service or our network path |
| **EMWIN** | GOES-19 satellite broadcast | 52 s | The dish, or the spacecraft |
| **api.weather.gov** | HTTPS poll, 60 s interval | 105 s | NWS API outage or rate limiting |

Warnings alone run a little faster than the all-products figures above: 37 s on
NWWS, 50 s on EMWIN, 95 s on the API.

**NWWS-OI** is the NOAA Weather Wire Service, the same push feed broadcasters
and emergency managers run on. It is the primary because it is a push: the
product is handed to us, we do not go looking for it.

**EMWIN** arrives over GOES-19: the product is broadcast from geostationary
orbit and received off a dish, with no internet between the satellite and the
receiver. Head to head on identical products, EMWIN trails NWWS by a median of
**7.5 seconds** and wins outright 3% of the time. It is a genuine second
primary, not a consolation prize, and it is the only feed that survives an
internet-side failure.

**api.weather.gov** is the slowest because polling always is: a 60-second poll
interval alone averages 30 seconds of waiting. It stays in the mix because it
carries non-VTEC products the text feeds handle differently, and because it
fails for entirely different reasons than the other two.

  The two text-feed figures are taken from the WMO header, which has minute
  resolution and truncates downward, so both are up to 60 s pessimistic. The
  head-to-head comparison between feeds uses one clock and carries no such bias.

## One alert, however many copies

A warning arriving on three feeds must not become three warnings. Deduplication
happens twice, on two different keys.

**Products** are keyed on a hash of their normalized text. The first copy to
arrive is stored; the losing copies only append to the alert's `sources` array.
That array is the evidence for which feed is actually fastest: the latency
table above is measured from it, not estimated.

**Alerts** are keyed on VTEC. Every follow-up statement for the life of a hazard
updates one row instead of piling up beside it, so what you subscribe to is the
current state of the hazard rather than a transcript of everything said about
it.

**Geometry** comes from the storm-based `LAT...LON` polygon when the product has
one. When it does not, the UGC zone codes are resolved against cached NWS zone
boundaries and unioned into a single shape, so every alert has a polygon, not
just the storm-based ones. A cancellation naming some counties subtracts those
and leaves the alert live in the rest.

## Getting it out

Two routes out, one pipeline behind them.

### MQTT, pushed

The broker is the fast path: no polling, no API in the middle, and the same
feed the [live map](/) draws from.

```
wss://mqtt.wxalerts.org/mqtt        username: wxalerts   password: wxalerts
```

The credentials are published on purpose. The account is subscribe-only and the
broker's ACL denies publishing.

Alerts are published on two trees, with an identical payload on both:

| Topic | |
| --- | --- |
| `wxalerts/nws/v1/alert/{office}/{phen}/{sig}/{etn}` | by issuing office |
| `wxalerts/nws/v1/same/{same_code}/{etn}` | by county, weather-radio style |

`{same_code}` is the six-digit SAME/FIPS code a NOAA weather radio is programmed
with, so subscribing to your county is the same act as programming a radio:

```bash
mosquitto_sub -t 'wxalerts/nws/v1/same/012113/#' -v   # Santa Rosa County, FL
```

Wildcard however you like: `alert/+/TO/W/+` is every tornado warning in the
country, `alert/+/+/W/+` is warnings with no watches or advisories.

Two behaviors matter:

- **Alert messages are retained.** Subscribing hands you every live hazard
  immediately, before any new one is issued. That opening burst is state, not
  news, so do not notify on it.
- **An empty payload is a tombstone.** When a hazard ends, a zero-length
  retained message clears every topic it appeared on. Treat it as "this alert is
  over" and drop it.

### REST, when you would rather ask

Not everything wants a persistent connection. `https://api.wxalerts.org` serves
active alerts, polygons in GeoJSON and location search over plain unauthenticated
HTTP; see the [alerts API reference](/docs/api/alerts/). It reads the same database
the broker publishes from, so the two never disagree; it is just a step behind by
however long you wait between requests.

## About that 40 seconds

The number usually quoted for a warning reaching a phone through a commercial
weather app is around **470 seconds**, a little under eight minutes from the
office pressing send.

Almost none of that is the National Weather Service. It accumulates downstream:
a vendor polling an API on a multi-minute interval, a batch job matching alerts
against saved locations, a push notification queue fanning out to millions of
devices, and a mobile OS deciding when to wake the app.

| | Issuance to delivery |
| --- | --- |
| Typical commercial weather app | ~470 s |
| WxAlerts, on the broker | **~40 s** |

We are faster for boring structural reasons, not clever ones:

- **Push, not poll.** Two of the three feeds hand us the product. There is no
  interval to wait out.
- **No batching.** A product is parsed and published as it lands. There is no
  queue to drain and no fan-out job to wait for.
- **The topic tree does the geofencing.** Filtering by county or by office
  happens in the broker's subscription matching, not in a service that has to
  walk a list of users first.
- **The broker is the last hop.** Publish to delivery is well under a second on
  a connected subscriber.

  Forty seconds is the median to the broker, not a guarantee to your device. A
  phone on a dying LTE signal, a Home Assistant instance that just restarted or
  a mesh node three hops out all add their own time, and none of this is an
  official government source. **Always follow your local officials**, and keep a
  NOAA weather radio if a warning at 3 AM matters to you.

## Where to go next

- [WXA/SA storm analysis](/docs/storm-analysis/): the other half of the picture -
  the storms themselves, tracked and scored between the products the NWS issues.
- [MQTT lightning feed](/docs/developers/mqtt/lightning/): the second, independent feed, carrying
  GOES-19 satellite lightning, geohashed.
- [Alerts API](/docs/api/alerts/): endpoints, shapes and how to color by significance.
- [Home Assistant](/docs/integrations/home-assistant/): NWS alerts and storm
  cells for your places, as entities you can automate against.
