Skip to content

Relay-to-Client Messages ​

This document describes the message formats that Nostr relays send to clients. These messages are sent over the same WebSocket connection established between the client and relay.

Overview ​

Relays send JSON arrays to clients through the WebSocket connection. Each message starts with a verb that identifies the type of message being sent. According to NIP-01, there are five primary message types that relays send to clients:

  1. EVENT - Delivering events to clients
  2. OK - Confirming receipt of a published event
  3. EOSE - Signaling the end of stored events
  4. CLOSED - Notifying that a subscription was closed
  5. NOTICE - Sending human-readable messages

Message Format Details ​

EVENT Message ​

The EVENT message is used to deliver events to clients that match a subscription.

Format:

json
["EVENT", <subscription_id>, <event JSON object>]

Example:

json
["EVENT", "my-sub", {
  "id": "4376c65d2f232afbe9b882a35baa4f6fe8667c4e684749af565f981833ed3eed",
  "pubkey": "6e468422dfb74a5738702a8823b9b28168abab8655faacb6853cd0ee15deee93",
  "created_at": 1673557174,
  "kind": 1,
  "tags": [["e", "3da979448d9ba263864c4d6f14984c423a3838364ec255f03c7904b1ae77f206"], ["p", "bf2376e17ba4ec269d10fcc996a4746b451152be9031fa48e74553dde5526bce"]],
  "content": "Hello, Nostr!",
  "sig": "908a15e46fb4d8675bab026fc230a0e3542bfade63da02d542fb78b2a8513fcd0092619a2c8c1221e581946e0191f2af505dfdf8657a414dbca329186f009262"
}]

The <subscription_id> refers to a previously created subscription requested by the client using a REQ message. This allows clients to associate incoming events with their corresponding subscriptions.

OK Message ​

The OK message is used to acknowledge the receipt of an event published by a client.

Format:

json
["OK", <event_id>, <success>, <message>]

Example (successful):

json
["OK", "4376c65d2f232afbe9b882a35baa4f6fe8667c4e684749af565f981833ed3eed", true, ""]

Example (successful with info):

json
["OK", "4376c65d2f232afbe9b882a35baa4f6fe8667c4e684749af565f981833ed3eed", true, "duplicate: already have this event"]

Example (unsuccessful):

json
["OK", "4376c65d2f232afbe9b882a35baa4f6fe8667c4e684749af565f981833ed3eed", false, "invalid: event creation date is too far off from the current time"]

Key components of the OK message:

  • <event_id> is the ID of the event that was submitted by the client.
  • <success> is a boolean indicating whether the event was accepted (true) or rejected (false).
  • <message> is an optional message providing more details about the outcome. For successful operations, it may be empty or provide additional information. For unsuccessful operations, it should include an error message.

NIP-01 defines standard prefixes for relay messages:

  • duplicate: - Event has been seen before
  • pow: - Information or errors related to proof of work
  • blocked: - Client is blocked or requires registration
  • rate-limited: - Too many requests or events
  • invalid: - Event violates protocol rules
  • restricted: - Permissions issue
  • error: - General error message

EOSE Message ​

The EOSE (End Of Stored Events) message indicates that a relay has finished sending all stored events that match a subscription and will now only send new events as they come in.

Format:

json
["EOSE", <subscription_id>]

Example:

json
["EOSE", "my-sub"]

This message is important for clients to know when they've received all historical data and can now process real-time updates.

CLOSED Message ​

The CLOSED message indicates that a subscription has been terminated by the relay.

Format:

json
["CLOSED", <subscription_id>, <message>]

Example:

json
["CLOSED", "my-sub", "error: shutting down idle subscription"]

This message may be sent if:

  • The relay refuses to fulfill a subscription request
  • The relay decides to terminate a subscription for internal reasons
  • The relay is shutting down

The <message> follows the same format as the OK message, with a machine-readable prefix and human-readable explanation.

NOTICE Message ​

The NOTICE message is used to send human-readable informational or error messages to clients.

Format:

json
["NOTICE", <message>]

Example:

json
["NOTICE", "This relay will be restarting for maintenance in 5 minutes"]

Notices are not connected to any specific subscription and are meant for displaying information to users or for debugging purposes.

COUNT Message ​

The COUNT message (defined in NIP-45) is sent in response to a COUNT request from a client.

Format:

json
["COUNT", <subscription_id>, {"count": <integer>}]

Example:

json
["COUNT", "counter-1", {"count": 42}]

The message contains the number of events that match the filters provided in the corresponding COUNT request.

Relay Implementation Considerations ​

Event Storage and Filtering ​

  • Relays should implement efficient event storage and querying systems to handle complex filters
  • Different kinds of events have different storage requirements:
    • Regular events (kinds 1-44, 1000-9999): Should be stored indefinitely
    • Replaceable events (kinds 0, 3, 10000-19999): Only the latest event per pubkey/kind combination needs to be stored
    • Ephemeral events (kinds 20000-29999): May not be stored at all
    • Addressable events (kinds 30000-39999): Only the latest event per pubkey/kind/d-tag combination needs to be stored

Connection Management ​

  • Relays should implement fair resource allocation across connected clients
  • Consider implementing connection limits per IP to prevent abuse
  • WebSocket ping/pong mechanisms should be used to detect stale connections

Subscription Management ​

  • Relays should track which subscriptions are active for each client
  • Consider implementing timeout mechanisms for idle subscriptions
  • For high-traffic relays, implement efficient filtering to avoid unnecessary processing

Performance Considerations ​

  • Implement rate limiting to prevent abuse
  • Consider batching events when sending to clients to reduce overhead
  • Use efficient database indexing for common query patterns
  • For popular relays, consider implementing caching mechanisms

Authentication and Access Control ​

  • While the basic Nostr protocol is open, relays may implement authentication mechanisms
  • NIP-42 defines a method for client authentication using the client's keypair
  • Relays may choose to implement whitelisting, blacklisting, or paid access models

Durability and Backup ​

  • Relays should implement regular database backups
  • Consider implementing event replication between trusted relays
  • Document your relay's data retention policies transparently