NIP-11 for relay operators: what your relay says about itself

What the relay information document must contain, why CORS matters for web clients, and how to check that your relay keeps the promises in its limitation block.

Before a client sends a single event, it often asks the relay a simple question: who are you, and what do you support? The answer is the relay information document defined in NIP-11. It is small, easy to get wrong, and many clients rely on it. This article walks through what NIP-11 asks for and how to check your own relay.

Part 1 of a series on the NIPs every relay operator touches.

How clients fetch it

The document lives at the same URL as the relay, just over HTTP(S) instead of WebSocket. A client requests it with the header Accept: application/nostr+json. If your relay is wss://relay.example.com, the document comes from https://relay.example.com with that header.

You can look at your own in one line:

curl -H 'Accept: application/nostr+json' https://relay.example.com

CORS is not optional

Web clients run in the browser, and the browser only lets them read the document if the response carries CORS headers, above all Access-Control-Allow-Origin. NIP-11 requires relays to accept CORS requests. Without the header the relay may work fine for native apps and still look empty to every web client: no name, no supported NIPs, no limits.

Quick self-test, with an Origin header the way a browser sends it:

curl -i -H 'Accept: application/nostr+json' -H 'Origin: https://example.com' https://relay.example.com

Look for Access-Control-Allow-Origin in the response headers.

The fields and their types

Any field may be omitted, but if a field is there, its type should be right:

  • name, description, contact: plain strings, keep the name short.
  • pubkey: the operator’s public key as 64 hex characters (not an npub).
  • supported_nips: a list of integers, for example [1, 11, 42]. A relay should at least declare NIP-1.
  • software: a URL pointing to the relay software.
  • version: a string.
  • limitation: an object, see below.

Typical mistakes are NIP numbers as strings ("11" instead of 11), an npub in pubkey, or a document served with an unusual content type.

limitation: promises clients act on

The limitation object tells clients how to behave so they do not run into walls. Common fields:

  • max_limit: the largest limit a filter may request.
  • max_subscriptions: how many subscriptions one connection may hold open.
  • max_subid_length and max_message_length: size limits for subscription ids and messages.
  • auth_required: whether NIP-42 authentication is needed before the relay serves requests.
  • restricted_writes: whether only some users may publish.
  • created_at_lower_limit / created_at_upper_limit: the accepted time window for events.
  • min_pow_difficulty: required proof of work.

These are statements your relay makes about itself. A client that trusts max_subscriptions: 20 will open 20 and expect them to work. If the real limit is 10, or there is none at all, the document is wrong, and users see odd behaviour that is hard to trace.

Advertised vs observed

The useful question is not only “is the document valid?” but “does the relay do what the document says?”. A few checks you can do by hand:

  • Open one subscription more than max_subscriptions and see whether the relay refuses it.
  • Send a subscription id just above max_subid_length.
  • If auth_required is true, try a read without authenticating.
  • Publish an event with a created_at outside the declared window.
  • If you list NIP-45, send a COUNT; if you list NIP-50, try a search filter.

When a test and the document disagree, fix one of them. Often the document was copied from a default config and never updated after the limits changed.

Checking it with labs

This is the kind of work labs.relayted.de automates. The Quick Check fetches your NIP-11 document the way a browser does (including Origin), checks CORS, field types and the declared NIPs, and measures the connection phases (DNS, TCP, TLS, WebSocket upgrade) along the way. The Conformance check then compares the limitation promises and the declared NIPs against actual behaviour, gently, and lists each item as advertised, observed and verdict.

No account, payment with Lightning. If your relay requires NIP-42, labs answers the challenge with a throwaway key; if a meaningful test is not possible, the run stops.

https://labs.relayted.de

Next in this series: NIP-01, the basics of EVENT, REQ, EOSE, CLOSE and OK, and the small details clients depend on.


Write a comment