Skip to content

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:

FieldTypeDescription
idstring32-bytes lowercase hex-encoded sha256 hash of the serialized event data
pubkeystring32-bytes lowercase hex-encoded public key of the event creator
created_atintegerUnix timestamp (seconds) when the event was created
kindintegerInteger between 0 and 65535 identifying the event type
tagsarrayArray of arrays of strings, representing the event's tags
contentstringArbitrary string content, format depends on event kind
sigstring64-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:

  1. 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>
    ]
  2. 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
  3. Calculate the SHA-256 hash of this serialized string

  4. 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 pubkey and kind, only the latest event is stored
    • Used for profile metadata, contact lists, etc.
  • 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, and d tag value
    • For each unique combination, only the latest event is stored

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>"]
  • p-tag: References a pubkey (user)

    • Format: ["p", "<pubkey>", "<optional-relay-url>", "<optional-petname>"]
  • a-tag: References an addressable/replaceable event

    • Addressable: ["a", "<kind>:<pubkey>:<d-tag-value>", "<optional-relay-url>"]
    • Replaceable: ["a", "<kind>:<pubkey>:", "<optional-relay-url>"]

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"
}

References ​