# MQTT lightning feed

> Live GLM flashes over MQTT-on-WebSocket, with a geohash topic tree that doubles as the spatial index.

Developers · Reference · https://wxalerts.org/docs/developers/mqtt/lightning/

GOES-19 GLM flashes are published to a public broker as they arrive. This is
the same feed the [live map](/) draws from, and the browser subscribes
directly, with no API in the middle.

The same broker also carries NWS hazards on a separate topic tree, documented
on the [MQTT alerts feed](/docs/developers/mqtt/alerts/) page.

## Connecting

| | |
| --- | --- |
| URL | `wss://mqtt.wxalerts.org/mqtt` |
| Host and port | `mqtt.wxalerts.org`, `443` |
| Transport | MQTT over WebSocket, path `/mqtt`, TLS |
| Username | `wxalerts` |
| Password | `wxalerts` |

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

Flash batches are published at QoS 0.

## The topic tree is the index

Flashes publish to one topic level per geohash character:

```
wxalerts/glm/v1/{g}/{g}/{g}/{g}/{g}
```

So you pick your own resolution with a wildcard, and the message rate follows:

```
wxalerts/glm/v1/9/#            ~5000 km
wxalerts/glm/v1/9/x/#          ~1250 km
wxalerts/glm/v1/9/x/j/#         ~156 km
wxalerts/glm/v1/9/x/j/5/#        ~39 km
wxalerts/glm/v1/9/x/j/5/e         ~4.9 km   (the published leaf)
```

  Do not subscribe to `wxalerts/glm/v1/#`. The full GOES-East disk runs
  1,000 to 1,500 messages a minute on an ordinary day and several times that
  during an outbreak. Subscribe to the boxes you actually care about.

## The payload

Each message is a batch: every flash one 20-second GLM granule put in one
five-character geohash cell, oldest first. A busy cell is split across several
messages of at most 500 flashes each.

```json
{
  "geohash": "9vg4m",
  "satellite": "goes19",
  "window_start": "2026-11-09T19:09:20+00:00",
  "window_end": "2026-11-09T19:09:40+00:00",
  "count": 2,
  "flashes": [
    { "t": "2026-11-09T19:09:19.127184+00:00", "lat": 32.7731, "lon": -96.8075, "energy_j": 7.53e-14, "area_m2": 412000000.0 },
    { "t": "2026-11-09T19:09:31.840211+00:00", "lat": 32.7802, "lon": -96.7911, "energy_j": 2.1e-13, "area_m2": 655000000.0 }
  ]
}
```

`t` is the flash's observation time. `lat` and `lon` are rounded to four
decimals, more than the instrument's few kilometres of accuracy. `energy_j` is
the optical energy seen at the cloud top, not a measure of what reaches the
ground; the flash rate is the more honest signal of a storm's strength.

## Retention and timing

Flashes are not retained. Lightning is an event, not a state, so there is no
opening burst when you subscribe and no tombstone when a flash is over. The
status heartbeat is the only retained topic in this tree.

A batch reaches the broker about 20 seconds after its granule's window closes,
and the window itself is 20 seconds long, so a flash is typically 20 to 40
seconds old when it reaches you.

## Broker limits

There is a 20-subscription cap per client. The 21st subscribe is refused with a
failure code in the SUBACK.

## History

The flash table behind [`GET /lightning/flashes`](/docs/api/lightning/) keeps 24
hours, and one request covers at most 180 minutes of it. Per-day counts are at
[`GET /v1/stats/lightning/daily`](/docs/api/stats/), which needs an
[API key](/docs/developers/api-keys/).

## Feed health

`wxalerts/glm/v1/status` is a retained heartbeat, refreshed every 30 seconds,
so a quiet sky can be told apart from a dead feed:

```json
{
  "at": "2026-11-09T19:09:39.387311+00:00",
  "healthy": true,
  "feed": true,
  "mqtt": true,
  "last_granule_age_seconds": 19,
  "stale_after_seconds": 900,
  "satellite": "goes19",
  "geohash_precision": 5,
  "backfill": true
}
```

Judge it by `at`, not by when it arrived, because a retained message can be
old. If the publisher drops off the broker, the broker replaces it with
`{"healthy": false, "reason": "publisher disconnected"}`. The geohash wildcards
above never match this topic, so subscribe to it on its own.

To write a client for this feed, see
[Build a reliable MQTT client](/docs/developers/mqtt/best-practices/).
