Appearance
Nostr Events
Overview
Events are the fundamental data structure in the Nostr protocol. All information exchanged on Nostr is formatted as events. Each event is created by a user (identified by their public key), serialized, signed, and then distributed to relays.
Event Structure
A Nostr event is a JSON object with the following fields:
| Field | Type | Description |
|---|---|---|
id | string | 32-bytes lowercase hex-encoded sha256 hash of the serialized event data |
pubkey | string | 32-bytes lowercase hex-encoded public key of the event creator |
created_at | integer | Unix timestamp (seconds) when the event was created |
kind | integer | Integer between 0 and 65535 identifying the event type |
tags | array | Array of arrays of strings, representing the event's tags |
content | string | Arbitrary string content, format depends on event kind |
sig | string | 64-bytes lowercase hex of the signature |
Event Serialization and ID Generation
To obtain the id field value, the event data must be serialized and hashed:
Create an array with the following elements in order:
[ 0, <pubkey, as a lowercase hex string>, <created_at, as a number>, <kind, as a number>, <tags, as an array of arrays of non-null strings>, <content, as a string> ]Serialize this array to a JSON string with the following rules:
- Use UTF-8 encoding
- No whitespace, line breaks, or unnecessary formatting
- Proper character escaping in the content field:
- Line break (
0x0A):\n - Double quote (
0x22):\" - Backslash (
0x5C):\\ - Carriage return (
0x0D):\r - Tab character (
0x09):\t - Backspace (
0x08):\b - Form feed (
0x0C):\f
- Line break (
Calculate the SHA-256 hash of this serialized string
Encode the resulting hash as a lowercase hex string
Event Signature
After calculating the event ID, the creator signs the ID using their private key according to the Schnorr signatures standard for the curve secp256k1. The resulting signature is hex-encoded and stored in the sig field.
Event Kinds
Events are categorized by their kind value:
Regular (1 ≤ kind < 10000 || 4 ≤ kind < 45 || kind == 1 || kind == 2)
- Expected to be stored by relays
- Used for persistent content like notes, articles, etc.
Replaceable (10000 ≤ kind < 20000 || kind == 0 || kind == 3)
- For each combination of
pubkeyandkind, only the latest event is stored - Used for profile metadata, contact lists, etc.
- For each combination of
Ephemeral (20000 ≤ kind < 30000)
- Not expected to be stored by relays
- Used for temporary messages like chat
Addressable (30000 ≤ kind < 40000)
- Identified by a combination of
kind,pubkey, anddtag value - For each unique combination, only the latest event is stored
- Identified by a combination of
Tags
Tags provide additional metadata and relationships for events. They are represented as arrays of strings:
[
["<tag-name>", "<tag-value>", "...additional optional fields"],
// more tags
]Standard Tags
e-tag: References another event
- Format:
["e", "<event-id>", "<optional-relay-url>", "<optional-marker>"]
- Format:
p-tag: References a pubkey (user)
- Format:
["p", "<pubkey>", "<optional-relay-url>", "<optional-petname>"]
- Format:
a-tag: References an addressable/replaceable event
- Addressable:
["a", "<kind>:<pubkey>:<d-tag-value>", "<optional-relay-url>"] - Replaceable:
["a", "<kind>:<pubkey>:", "<optional-relay-url>"]
- Addressable:
Example Event
json
{
"id": "4376c65d2f232afbe9b882a35baa4f6fe8667c4e684749af565f981833ed6a65",
"pubkey": "79dff8f82963424e0bb02708a22e44b4980893e3a4be0fa3cb60a43b946764e3",
"created_at": 1671217411,
"kind": 1,
"tags": [
["e", "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36", "wss://nostr.example.com"],
["p", "f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca"]
],
"content": "This is a reply to another note!",
"sig": "908a15e46fb4d8675bab026fc230a0e3542bfade63da02d542fb78b2a8513fcd0092619a2c8c1221e581946e0191f2af505dfdf8657a414dbca329186f009262"
}