Summary
This PR proposes additions to NIP-66 to standardize the output format for checks that are already declarable in kind 10166 but lack defined result tags in kind 30166. It also fixes several inconsistencies in the current specification.
Part 1: Bug Fixes
1.1 Fix timeout tag format documentation
The current specification text contradicts the example:
Index 1 is the monitor's timeout in milliseconds. Index 2 describes what test the timeout is used for.
But the example shows:
[ "timeout", "open", "5000" ]
Here index 1 is the test type and index 2 is milliseconds. The example is correct, the text should be updated to match:
-- Index `1` is the monitor's timeout in milliseconds. Index `2` describes what test the timeout is used for.
+- Index `1` is the test type (e.g., `open`, `read`, `write`). Index `2` is the timeout in milliseconds.
1.2 Document the l (language) tag
The example includes ["l", "en", "ISO-639-1"] but the l tag is not documented. Add to the tags list:
+- `l` - Language tag. Index `1` is the ISO-639-1 language code, index `2` is the standard identifier (`ISO-639-1`).
1.3 Clarify c tag check values
The specification lists check examples as open, read, write, auth, nip11, dns, geo, but the example uses ws instead of open/read/write.
Clarify that:
open - Tests WebSocket connection establishment
read - Tests subscription/read capability
write - Tests event publishing capability
ssl - Tests SSL/TLS certificate (should be added to spec text)
Update the example to use consistent values:
-[ "c", "ws" ],
+[ "c", "open" ],
+[ "c", "read" ],
+[ "c", "write" ],
Part 2: New Output Tags
Current state
NIP-66 currently allows monitors to declare checks via the c tag, but while open, read, and write have corresponding output tags (rtt-open, rtt-read, rtt-write), the checks ssl, geo, and dns have no standardized output format.
2.1 Add SSL/TLS tags
Define output tags for the ssl check (clearnet wss:// relays only):
+- `ssl` - Certificate validity status: `valid` or `!valid`
+- `ssl-expires` - Certificate expiration as Unix timestamp in seconds
+- `ssl-issuer` - Certificate Authority (CA) organization name
2.2 Add Network tags
Define output tags for a new net check:
+- `net-ip` - Resolved IPv4 address of the relay
+- `net-ipv6` - Resolved IPv6 address of the relay (if available)
+- `net-asn` - Autonomous System Number
+- `net-asn-org` - ASN organization name
2.3 Add Geographic tags
Define output tags for the geo check, complementing the existing g (geohash) tag:
+- `geo-country` - ISO 3166-1 alpha-2 country code
+- `geo-city` - City name
+- `geo-lat` - Latitude coordinate as decimal string
+- `geo-lon` - Longitude coordinate as decimal string
+- `geo-tz` - IANA timezone identifier
2.4 Add net check type
Add net (network/ASN lookup) to the list of check types in kind 10166.
2.5 Formal check-to-output mapping
Replace the informal list of check examples with a formal table:
| Check |
Description |
Output Tags |
open |
Connection test |
rtt-open |
read |
Read/subscription test |
rtt-read |
write |
Write/publish test |
rtt-write |
nip11 |
NIP-11 document fetch |
content |
ssl |
SSL/TLS certificate check |
ssl, ssl-expires, ssl-issuer |
geo |
Geographic location lookup |
g, geo-country, geo-city, geo-lat, geo-lon, geo-tz |
net |
Network/ASN lookup |
net-ip, net-ipv6, net-asn, net-asn-org |
2.6 Reorganize tag documentation
Group tags by category for clarity:
- Basic Tags:
d, n, T, N, R, t, k, l
- RTT Tags:
rtt-open, rtt-read, rtt-write
- SSL/TLS Tags:
ssl, ssl-expires, ssl-issuer
- Network Tags:
net-ip, net-ipv6, net-asn, net-asn-org
- Geographic Tags:
g, geo-country, geo-city, geo-lat, geo-lon, geo-tz
Design Decisions
Why separate net-* from geo-*?
ASN and IP are network identifiers, not geographic locations. A relay in Amsterdam hosted on Cloudflare would have:
geo-city: Amsterdam (physical server location)
net-asn-org: Cloudflare (network provider)
These are semantically different concepts derived from different data sources (GeoIP City vs GeoIP ASN databases).
Why include net-ipv6?
IPv6 adoption continues to grow. Some users/networks are IPv6-only or prefer IPv6 for direct connectivity (less NAT traversal). Knowing if a relay supports IPv6 helps clients make informed routing decisions.
Why include geo-lat/geo-lon when g (geohash) exists?
For convenience. Clients can read coordinates directly without implementing geohash decoding. The g tag remains the canonical location identifier for filtering.
Why only three SSL fields?
Minimalism. Only fields useful for client decision-making are included:
ssl - Filter relays by certificate validity
ssl-expires - Alert before expiration
ssl-issuer - Trust assessment based on CA
Detailed SSL data (cipher, fingerprint, protocol version) is better suited for specialized security audit tools.
Examples
Kind 30166 (Relay Discovery Event)
{
"kind": 30166,
"tags": [
["d", "wss://relay.example.com/"],
["n", "clearnet"],
["N", "1"],
["R", "!payment"],
["l", "en", "ISO-639-1"],
["rtt-open", "89"],
["rtt-read", "123"],
["rtt-write", "156"],
["ssl", "valid"],
["ssl-expires", "1735689600"],
["ssl-issuer", "Let's Encrypt"],
["net-ip", "93.184.216.34"],
["net-ipv6", "2606:2800:220:1:248:1893:25c8:1946"],
["net-asn", "15169"],
["net-asn-org", "Google LLC"],
["g", "u173zq37x"],
["geo-country", "NL"],
["geo-city", "Amsterdam"],
["geo-lat", "52.3676"],
["geo-lon", "4.9041"],
["geo-tz", "Europe/Amsterdam"]
]
}
Kind 10166 (Monitor Announcement)
{
"kind": 10166,
"tags": [
["frequency", "3600"],
["timeout", "open", "5000"],
["timeout", "read", "3000"],
["timeout", "write", "3000"],
["timeout", "ssl", "5000"],
["c", "open"],
["c", "read"],
["c", "write"],
["c", "nip11"],
["c", "ssl"],
["c", "geo"],
["c", "net"],
["g", "u173zq37x"]
]
}
Backwards Compatibility
- All proposed tags are optional
- Existing clients can safely ignore unknown tags
- No changes to required fields or existing tag semantics
- Follows existing NIP-66 conventions (e.g.,
! prefix for false values)
- Bug fixes clarify existing behavior without breaking changes
Summary
This PR proposes additions to NIP-66 to standardize the output format for checks that are already declarable in kind
10166but lack defined result tags in kind30166. It also fixes several inconsistencies in the current specification.Part 1: Bug Fixes
1.1 Fix
timeouttag format documentationThe current specification text contradicts the example:
But the example shows:
Here index
1is the test type and index2is milliseconds. The example is correct, the text should be updated to match:1.2 Document the
l(language) tagThe example includes
["l", "en", "ISO-639-1"]but theltag is not documented. Add to the tags list:+- `l` - Language tag. Index `1` is the ISO-639-1 language code, index `2` is the standard identifier (`ISO-639-1`).1.3 Clarify
ctag check valuesThe specification lists check examples as
open,read,write,auth,nip11,dns,geo, but the example useswsinstead ofopen/read/write.Clarify that:
open- Tests WebSocket connection establishmentread- Tests subscription/read capabilitywrite- Tests event publishing capabilityssl- Tests SSL/TLS certificate (should be added to spec text)Update the example to use consistent values:
Part 2: New Output Tags
Current state
NIP-66 currently allows monitors to declare checks via the
ctag, but whileopen,read, andwritehave corresponding output tags (rtt-open,rtt-read,rtt-write), the checksssl,geo, anddnshave no standardized output format.2.1 Add SSL/TLS tags
Define output tags for the
sslcheck (clearnetwss://relays only):2.2 Add Network tags
Define output tags for a new
netcheck:2.3 Add Geographic tags
Define output tags for the
geocheck, complementing the existingg(geohash) tag:2.4 Add
netcheck typeAdd
net(network/ASN lookup) to the list of check types in kind10166.2.5 Formal check-to-output mapping
Replace the informal list of check examples with a formal table:
openrtt-openreadrtt-readwritertt-writenip11contentsslssl,ssl-expires,ssl-issuergeog,geo-country,geo-city,geo-lat,geo-lon,geo-tznetnet-ip,net-ipv6,net-asn,net-asn-org2.6 Reorganize tag documentation
Group tags by category for clarity:
d,n,T,N,R,t,k,lrtt-open,rtt-read,rtt-writessl,ssl-expires,ssl-issuernet-ip,net-ipv6,net-asn,net-asn-orgg,geo-country,geo-city,geo-lat,geo-lon,geo-tzDesign Decisions
Why separate
net-*fromgeo-*?ASN and IP are network identifiers, not geographic locations. A relay in Amsterdam hosted on Cloudflare would have:
geo-city:Amsterdam(physical server location)net-asn-org:Cloudflare(network provider)These are semantically different concepts derived from different data sources (GeoIP City vs GeoIP ASN databases).
Why include
net-ipv6?IPv6 adoption continues to grow. Some users/networks are IPv6-only or prefer IPv6 for direct connectivity (less NAT traversal). Knowing if a relay supports IPv6 helps clients make informed routing decisions.
Why include
geo-lat/geo-lonwheng(geohash) exists?For convenience. Clients can read coordinates directly without implementing geohash decoding. The
gtag remains the canonical location identifier for filtering.Why only three SSL fields?
Minimalism. Only fields useful for client decision-making are included:
ssl- Filter relays by certificate validityssl-expires- Alert before expirationssl-issuer- Trust assessment based on CADetailed SSL data (cipher, fingerprint, protocol version) is better suited for specialized security audit tools.
Examples
Kind 30166 (Relay Discovery Event)
{ "kind": 30166, "tags": [ ["d", "wss://relay.example.com/"], ["n", "clearnet"], ["N", "1"], ["R", "!payment"], ["l", "en", "ISO-639-1"], ["rtt-open", "89"], ["rtt-read", "123"], ["rtt-write", "156"], ["ssl", "valid"], ["ssl-expires", "1735689600"], ["ssl-issuer", "Let's Encrypt"], ["net-ip", "93.184.216.34"], ["net-ipv6", "2606:2800:220:1:248:1893:25c8:1946"], ["net-asn", "15169"], ["net-asn-org", "Google LLC"], ["g", "u173zq37x"], ["geo-country", "NL"], ["geo-city", "Amsterdam"], ["geo-lat", "52.3676"], ["geo-lon", "4.9041"], ["geo-tz", "Europe/Amsterdam"] ] }Kind 10166 (Monitor Announcement)
{ "kind": 10166, "tags": [ ["frequency", "3600"], ["timeout", "open", "5000"], ["timeout", "read", "3000"], ["timeout", "write", "3000"], ["timeout", "ssl", "5000"], ["c", "open"], ["c", "read"], ["c", "write"], ["c", "nip11"], ["c", "ssl"], ["c", "geo"], ["c", "net"], ["g", "u173zq37x"] ] }Backwards Compatibility
!prefix for false values)