Chapter 66 - Relay Ops
66
Nostr Implementation Possibility - Hex № 66

Relay Liveness Monitoring

Monitors probe relays, measure them, and publish the results as events. Clients read those events to discover relays that actually work.

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.

Hint!

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.

Relay A Relay B Monitor probes + signs Index relay Client probe 30166 REQ
Fig. 66-1 — The monitoring loop. The monitor probes relays, publishes one kind 30166 event per relay, and clients query the results.

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.

Wire format - kind 30166 relay discovery event
{
  "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.

Kind 30166 tags
TagValueRule
dnormalized relay URLRequired. Identifies the relay. A hex pubkey may replace the URL for relays without one.
rtt-openmillisecondsThe relay's open round-trip time.
rtt-readmillisecondsThe relay's read round-trip time.
rtt-writemillisecondsThe relay's write round-trip time.
nnetwork typeShould be one of clearnet, tor, i2p, loki.
Trelay typeAn enumerated relay type in PascalCase, for example PrivateInbox.
NNIP numberA NIP the relay supports. Repeat the tag for each NIP.
Rrequirement keyA key from the NIP-11 limitations object: auth, writes, pow, payment. Prefix false values with !, for example !auth.
ttopicA topic associated with the relay.
kkind numberAn accepted kind. Prefix unaccepted kinds with !.
ggeohashA NIP-52 geohash for the relay's location.
Warning!

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.

Tech Note

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.

Kind 10166 tags
TagValueRule
frequencysecondsHow often the monitor publishes events.
timeoutmilliseconds, checkOptional. 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.
ccheck nameA lowercase string naming one check the monitor conducts. Examples: open, read, write, auth, nip11, dns, geo.
ggeohashA 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.

Wire format - kind 10166 monitor announcement
{
  "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"]
  ]
}
Tech Note

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 30166 events to function. Absence of monitoring data must not prevent relay connections.
  • A monitor may publish erroneous kind 30166 events, 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.
Warning!

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.

Monitor 1 Monitor 2 Monitor 3 Client cross-check Relay list majority view 30166 events keep
Fig. 66-2 — Do not trust one station. The client compares reports from several monitors before it drops any relay.

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.

Session transcript - monitor publishes, client discovers
-- 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

AuthorSandwich
First commit2025-03-03 — “NIP-66 Relay Discovery and Liveness Monitoring (Draft 7)” - PR #230
Statusdraft - optional — for monitors and the clients that read them
Source66.md on GitHub - full change history

7 See Also

  • NIP-01 — the event format, addressable and replaceable storage, and the kind 0 profile monitors should publish.
  • NIP-11 — the relay information document that kind 30166 events summarize and verify.
  • NIP-65 — the kind 10002 relay selections event monitors should publish.
  • NIP-52 — defines the geohash format used by the g tag.