Appearance
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:
EVENT
- Delivering events to clientsOK
- Confirming receipt of a published eventEOSE
- Signaling the end of stored eventsCLOSED
- Notifying that a subscription was closedNOTICE
- 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 beforepow:
- Information or errors related to proof of workblocked:
- Client is blocked or requires registrationrate-limited:
- Too many requests or eventsinvalid:
- Event violates protocol rulesrestricted:
- Permissions issueerror:
- 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