Nostr
ActiveNostr (Notes and Other Stuff Transmitted by Relays) is a censorship-resistant decentralized protocol for social publishing. Every user has a cryptographic keypair (secp256k1); every note is a JSON event signed by the user's private key. Clients connect to multiple relays (WebSocket servers) to publish and subscribe to events. No central server, no accounts – identity is purely cryptographic.
In one line
Nostr (NIPs, community spec) is a decentralized protocol where every event is a JSON object signed with a secp256k1 private key. Clients connect to relays (WebSocket servers) to publish events (kind 1 = short text note) and subscribe with filters (authors, kinds, tags, since/until). No accounts, no federation protocol – identity is just a public key. Client-relay wire protocol is defined in NIP-01: 3 client messages (EVENT, REQ, CLOSE) and 5 relay messages (EVENT, OK, EOSE, CLOSED, NOTICE).
Quick Reference
| Field | Size | Description |
|---|---|---|
| Identity | secp256k1 keypair | A Nostr identity is just a public/private key pair. Public key is the user ID (npub encoding). Private key signs all events (nsec encoding). No accounts, no servers needed to 'register'. |
| Event | JSON object | Every piece of content is a signed JSON event: {id, pubkey, created_at, kind, tags, content, sig}. The id is SHA-256 of the serialized fields. sig is Schnorr signature over id using privkey. |
| Kind | integer | Event type. kind 0 = metadata (profile), kind 1 = short text note, kind 3 = contact list, kind 4 = encrypted DM (deprecated), kind 6 = repost, kind 7 = reaction. Range 10000–19999 for replaceable, 20000–29999 for ephemeral. |
| Relay | wss:// WebSocket | A server that accepts and serves events. Clients connect to multiple relays for redundancy. Relays may require payment (NIP-42) or invitation. wss:// is standard; ws:// for local testing. |
| NIP-01 messages | 3 + 5 message types | Client sends: EVENT (publish), REQ (subscribe with filter), CLOSE (unsubscribe). Relay sends: EVENT (matching event), OK (accepted/rejected), EOSE (end of stored events), CLOSED (subscription terminated), NOTICE (informational). |
| Filters | JSON subscription | REQ subscription filter: {ids, authors, kinds, #e (event tags), #p (pubkey tags), since, until, limit}. Multiple filters in one REQ are OR'd. Multiple REQ subscriptions on one connection are independent. |
| bech32 encoding | npub/nsec/note/naddr | NIP-19 bech32-encoded identifiers. npub = public key (for sharing profiles), nsec = private key (keep secret), note = event id, naddr = replaceable event address, nevent = event with relay hint. |
| Zaps | NIP-57 | Lightning Network Bitcoin micropayments sent as Nostr events. A zap request (kind 9734) is sent to the recipient's Lightning address, and the zap receipt (kind 9735) is published to relays. Enables tipping creators natively. |
Key Characteristics
Cryptographic identity
No account required. Generate a keypair offline. Publish anywhere. No server can revoke your identity because identity is a cryptographic key, not a server-granted account.
No guaranteed delivery
Nostr has no delivery guarantees. Publish to more relays for better reach. Relays may drop events, go offline, or reject events. Clients must manage multi-relay publishing themselves.
Bitcoin-native
Nostr was designed alongside the Bitcoin/Lightning ecosystem. Zaps (NIP-57) enable Lightning tips. LNURL-pay and Nostr Wallet Connect (NIP-47) integrate Lightning payments natively.
Relay independence
A user's events exist wherever relays have stored them. Users can migrate to new relays, republish lost events, and cannot be deplatformed unless every relay drops them simultaneously.
Message Format
// NIP-01 client messages (WebSocket JSON arrays)
// EVENT: publish a signed event
["EVENT", {
"id": "sha256-of-serialized-content",
"pubkey": "hex-public-key",
"created_at": 1700000000,
"kind": 1,
"tags": [
["e", "reply-to-event-id", "wss://relay.damus.io"],
["p", "mentioned-pubkey"]
],
"content": "Hello Nostr!",
"sig": "schnorr-signature-over-id"
}]
// REQ: subscribe with filter
["REQ", "sub-id-1", {
"authors": ["pubkey1", "pubkey2"],
"kinds": [1, 6],
"since": 1700000000,
"limit": 50
}]
// CLOSE: unsubscribe
["CLOSE", "sub-id-1"]// Relay messages
// EVENT: matching event from subscription
["EVENT", "sub-id-1", {
"id": "abc...",
"pubkey": "def...",
"created_at": 1700000001,
"kind": 1,
"content": "Reply to your note!",
"sig": "..."
}]
// OK: publish acknowledgement
["OK", "event-id", true, ""] // accepted
["OK", "event-id", false, "blocked: content policy violation"]
// EOSE: end of stored events, real-time begins
["EOSE", "sub-id-1"]
// CLOSED: relay terminated subscription
["CLOSED", "sub-id-1", "rate-limited: too many requests"]
// NOTICE: informational message
["NOTICE", "This relay requires NIP-42 authentication"]