1 Overview
A relay can be slow, offline, or different from what it advertises. Its NIP-11 document describes its policy, but nothing checks that the document is true. This NIP adds an outside observer: the monitor.
A monitor is a normal Nostr identity that probes relays. It measures response times, checks supported NIPs, and records network type and location. It publishes one relay discovery event (kind 30166) per relay. Clients query these events to find live relays that match their needs.
A monitor may also publish a relay monitor announcement (kind 10166). This event advertises the monitor's intent to publish kind 30166 events at a regular, predictable frequency. It also lists the checks the monitor performs.
Think of a monitor as a weather station for relays. It does not run the relay. It only reports the conditions it observed. Anyone can run one, so read the forecast from more than one station.
2 Relay Discovery Events - Kind 30166
A kind 30166 event documents the characteristics of one relay. The monitor infers them from the relay's NIP-11 document, from probing, or from both. It is an addressable event under the NIP-01 storage rules: a relay keeps only the latest event per monitor pubkey and d value.
The tags may contradict the relay's own NIP-11 document. That is intentional. A monitor reports the policy it observed, not the policy the relay advertises.
The content field may hold the stringified JSON of the relay's NIP-11 informational document. It may also be empty.
{
"kind": 30166,
"pubkey": <monitor's pubkey>,
"content": <optional stringified NIP-11 document>,
"tags": [
["d", "wss://some.relay/"], <- required, normalized URL
["n", "clearnet"],
["N", "40"], ["N", "33"],
["R", "!payment"], ["R", "auth"],
["g", "ww8p1r4t8"],
["t", "nsfw"],
["rtt-open", "234"]
]
}
The only required tag is d. Set it to the relay's URL, normalized per RFC 3986 §6. For a relay that has no URL, a hex-encoded pubkey may stand in as the d value instead.
| Tag | Value | Rule |
|---|---|---|
| d | normalized relay URL | Required. Identifies the relay. A hex pubkey may replace the URL for relays without one. |
| rtt-open | milliseconds | The relay's open round-trip time. |
| rtt-read | milliseconds | The relay's read round-trip time. |
| rtt-write | milliseconds | The relay's write round-trip time. |
| n | network type | Should be one of clearnet, tor, i2p, loki. |
| T | relay type | An enumerated relay type in PascalCase, for example PrivateInbox. |
| N | NIP number | A NIP the relay supports. Repeat the tag for each NIP. |
| R | requirement key | A key from the NIP-11 limitations object: auth, writes, pow, payment. Prefix false values with !, for example !auth. |
| t | topic | A topic associated with the relay. |
| k | kind number | An accepted kind. Prefix unaccepted kinds with !. |
| g | geohash | A NIP-52 geohash for the relay's location. |
One value per tag. When a tag has several values, repeat the tag: [["t","cats"],["t","dogs"]]. Do not pack values into one tag like [["t","cats","dogs"]]. Relays index only the first value, so packed values become unqueryable.
Two loose ends in the source spec. First, its example event carries an ["l","en","ISO-639-1"] language tag that the tag list never defines. Second, the T relay-type enumeration lives in a GitHub issue (nostr-protocol/nips #1282), not in any NIP, so there is no normative list of relay types.
3 Relay Monitor Announcements - Kind 10166
A kind 10166 event advertises the author's intent to publish kind 30166 events. It is optional. Publish it when the monitor provides monitoring at a regular and predictable frequency. As a replaceable event, one announcement per monitor pubkey survives.
| Tag | Value | Rule |
|---|---|---|
| frequency | seconds | How often the monitor publishes events. |
| timeout | milliseconds, check | Optional. Index 1 is the monitor's timeout in milliseconds. Index 2 names the test it applies to. Without index 2, the timeout applies to all tests. |
| c | check name | A lowercase string naming one check the monitor conducts. Examples: open, read, write, auth, nip11, dns, geo. |
| g | geohash | A NIP-52 geohash tag for the monitor's location. |
A monitor should also publish a kind 0 profile (NIP-01) and a kind 10002 relay selections event (NIP-65). Together they tell clients who the monitor is and where its events live.
{
"kind": 10166,
"pubkey": <monitor's pubkey>,
"content": "",
"tags": [
["timeout", "5000", "open"],
["timeout", "3000", "read"],
["timeout", "3000", "write"],
["frequency", "3600"],
["c", "open"], ["c", "nip11"],
["c", "dns"], ["c", "geo"],
["g", "ww8p1r4t8"]
]
}
The source spec's own kind 10166 example contradicts its prose. The prose puts milliseconds at index 1 and the check name at index 2, but the example writes ["timeout","open","5000"] - reversed. The example is also invalid JSON (a missing comma before the g tag), omits the kind field, uses a "signature" field instead of "sig", and lists checks ws and ssl that the prose never names. The block above follows the prose.
4 Risk Mitigation
Monitoring data is advice, not authority. The spec sets three defensive rules:
- Clients must not require kind
30166events to function. Absence of monitoring data must not prevent relay connections. - A monitor may publish erroneous kind
30166events, through misconfiguration or malicious intent. Plan for bad data. - Clients should not trust a single source. Defenses include web-of-trust filtering, querying multiple monitors, and discarding filter results that would remove an unreasonable proportion of relays.
A hostile monitor can make good relays look dead and bad relays look healthy. If one monitor's data would cut most of your relay list, throw that data away, not your relays.
5 Worked Example
A monitor probes wss://some.relay/ and publishes its findings. Later, a client asks an index relay for fast clearnet relays. Orange lines go to the relay. Blue lines come from the relay.
-- monitor publishes one discovery event per probed relay -- → ["EVENT", {"kind":30166,"pubkey":"a3f1c2d4…","created_at":1749762600, "content":"{\"name\":\"Some Relay\",\"limitation\":{\"auth_required\":true}}", "tags":[["d","wss://some.relay/"],["n","clearnet"],["N","40"],["N","33"], ["R","auth"],["R","!payment"],["g","ww8p1r4t8"],["t","nsfw"], ["rtt-open","234"],["rtt-read","112"],["rtt-write","198"]], "id":"7cc21e04…","sig":"9b41aa07…"}] ← ["OK", "7cc21e04…", true, ""] -- a client looks for live clearnet relays seen by this monitor -- → ["REQ", "relays", {"kinds":[30166], "authors":["a3f1c2d4…"], "#n":["clearnet"], "since":1749759000}] ← ["EVENT", "relays", {"kind":30166, "tags":[["d","wss://some.relay/"], …], …}] ← ["EOSE", "relays"] → ["CLOSE", "relays"]
The since filter is the liveness test. A monitor with frequency 3600 republishes every hour. A relay with no fresh kind 30166 event was down when the monitor last checked, or the monitor itself stopped.
6 Version History
NIP-66 circulated as a draft for years before it merged in 2025 as "Draft 7". Notable changes, newest first:
- 20262026-05Sanity fixes to the spec text by fiatjaf.
- 20262026-03Added the Risk Mitigation section: clients must not depend on monitoring data or trust a single monitor.
- 20252025-12Added the relay-type tag material; fixed typos and broken links.
- 20252025-10Tag values became strings only - integers removed from tag examples.
- 20252025-09Fixed fundamentally incorrect assertions in the spec text.
- 20252025-08General cleanup pass by hodlbod.
- 20252025-03/04Title, description, and terminology fixes ("addressable event").
- Origin2025-03Sandwich merged "Relay Discovery and Liveness Monitoring (Draft 7)" after a long review in PR #230.
Original Proposal - Credits
| Author | Sandwich |
| First commit | 2025-03-03 — “NIP-66 Relay Discovery and Liveness Monitoring (Draft 7)” - PR #230 |
| Status | draft - optional — for monitors and the clients that read them |
| Source | 66.md on GitHub - full change history |
7 See Also
- NIP-01 — the event format, addressable and replaceable storage, and the
kind 0profile monitors should publish. - NIP-11 — the relay information document that kind
30166events summarize and verify. - NIP-65 — the
kind 10002relay selections event monitors should publish. - NIP-52 — defines the geohash format used by the
gtag.