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