Chapter 22 - Social
22
Nostr Implementation Possibility - Hex № 22

Comment

One universal comment event that can thread under any Nostr event — or under any URL, hashtag, geohash, or podcast episode.

1 Overview

A comment is a threading note. It is always scoped to a root: either a root event or an external identifier from NIP-73. This NIP defines the comment as kind:1111.

Every comment carries two sets of pointers. Uppercase tag names point to the root scope. Lowercase tag names point to the parent item, the thing the comment answers directly. For a top-level comment, root and parent are the same item. For a reply to a comment, the root stays fixed and the parent is the earlier comment.

The two-level design lets a client fetch a whole thread with one filter on the uppercase tags. It also lets the client rebuild the reply tree from the lowercase tags. Blog posts, files, live events, websites, and podcast episodes all use the same comment kind.

Hint!

Memory aid: BIG letters point to the BIG picture (the root of the thread). Small letters point to the small step (the direct parent). A top-level comment repeats the same target in both cases.

Root event e.g. kind 30023 Comment kind 1111 Reply kind 1111 A/E K P a/e k p e k p A/E K P
Fig. 22-1 — Root vs parent. Orange uppercase pointers always reach the root. Blue lowercase pointers reach the direct parent.

2 The Comment Event

A comment uses kind:1111. The content field is plaintext. Do not put HTML, Markdown, or any other formatting in it. The template below shows the full tag layout:

Wire format - kind 1111 comment
{
  "kind": 1111,
  "content": <comment, plaintext>,
  "tags": [
    -- root scope: event address, event id, or I-value --
    [<"A", "E" or "I">, <address, id or I-value>, <relay or web page hint>, <root pubkey, if an E tag>],
    ["K", <root kind>],
    ["P", <root pubkey>, <relay-url-hint>],

    -- parent item: event address, event id, or i-value --
    [<"a", "e" or "i">, <address, id or i-value>, <relay or web page hint>, <parent pubkey, if an e tag>],
    ["k", <parent kind>],
    ["p", <parent pubkey>, <relay-url-hint>]
  ]
  -- other fields per NIP-01 --
}

Three rules are mandatory:

  • A comment MUST point to the root scope with uppercase tag names: K, E, A, or I.
  • A comment MUST point to the parent item with lowercase tag names: k, e, a, or i.
  • A comment MUST point to the authors when one is available, that is, when it tags a Nostr event. Use P for the root author and p for the parent author.

The tags K and k MUST be present. They define the event kind of the root item and of the parent item.

Tag reference
TagLevelPoints toExtra elements
Arootthe root event address (addressable event)relay hint
Erootthe root event idrelay hint, then the root event's pubkey
Irootan external identifier (NIP-73)web page hint
Krootthe root item kind. Mandatory.—
Prootthe pubkey of the root event's authorrelay URL hint
aparentthe parent event addressrelay hint
eparentthe parent event idrelay hint, then the parent event's pubkey
iparentan external identifier (NIP-73)web page hint
kparentthe parent item kind. Mandatory.—
pparentthe pubkey of the parent item's authorrelay URL hint
Tech Note

The first example in the source states a rule that the normative text does not: when the parent event is replaceable or addressable, also include an e tag with its event id next to the a tag. Follow it — it pins the exact version you answered. The same example also has a JSON slip: a missing comma after the P tag line.

3 External Scopes

Comments can thread under things that are not Nostr events. The I and i tags create scopes for hashtags, geohashes, URLs, and other external identifiers.

NIP-73 lists the possible values for i tags. It also lists the k values that go with an external identity, such as web or podcast:item:guid. The uppercase versions I and K use the same type of values, but they relate to the root item instead of the parent one.

An external scope has no Nostr author. In that case the comment carries no P or p tag for it.

Root scope what is it? Nostr event ["A" or "E"] + ["K"] + ["P"] External identifier ["I"] + ["K"] - no "P" tag id or address url, hashtag, ...
Fig. 22-2 — Two scope families. Nostr roots get author tags. External roots use NIP-73 identifiers and have none.

4 Citations and Mentions

A comment body can reference other events and users through NIP-21 nostr: URIs. Two extra tags mirror those references:

  • q tags MAY be used when the content cites an event with NIP-21.
  • p tags SHOULD be used when the content mentions a pubkey with NIP-21.
Citation tag - q
["q", <event-id> or <event-address>, <relay-url>, <pubkey-if-a-regular-event>]

5 Worked Examples

The source spec walks through six cases. All six follow, with the fields that matter. A top-level comment repeats the root target in the lowercase parent tags.

Comment on a blog post

The root is a NIP-23 long-form article, an addressable event of kind 30023. The parent is addressable, so the comment carries both an a tag and an e tag that pins the exact event id.

Top-level comment on kind 30023
{
  "kind": 1111,
  "content": "Great blog post!",
  "tags": [
    ["A", "30023:3c9849…ec11289:f9347ca7", "wss://example.relay"],
    ["K", "30023"],
    ["P", "3c9849…ec11289", "wss://example.relay"],

    ["a", "30023:3c9849…ec11289:f9347ca7", "wss://example.relay"],
    ["e", "5b4fc7…e07651", "wss://example.relay"],  -- pins the exact version
    ["k", "30023"],
    ["p", "3c9849…ec11289", "wss://example.relay"]
  ]
}

Comment on a file, and a reply to it

The root is a NIP-94 file event of kind 1063. It is a regular event, so E is used with the root pubkey as the fourth element. The reply keeps the same root tags and swaps the parent tags to the first comment. The parent kind becomes 1111.

Comment, then reply - kind 1063 root
-- top-level comment --
{
  "kind": 1111, "content": "Great file!",
  "tags": [
    ["E", "768ac8…42f5e6", "wss://example.relay", "3721e0…bbe5bb"],
    ["K", "1063"],
    ["P", "3721e0…bbe5bb"],
    ["e", "768ac8…42f5e6", "wss://example.relay", "3721e0…bbe5bb"],
    ["k", "1063"],
    ["p", "3721e0…bbe5bb"]
  ]
}

-- reply to that comment: root unchanged, parent = the comment --
{
  "kind": 1111, "content": "This is a reply to \"Great file!\"",
  "tags": [
    ["E", "768ac8…42f5e6", "wss://example.relay", "fd913c…54cc9a"],
    ["K", "1063"],
    ["P", "fd913c…54cc9a"],
    ["e", "5c83da…7226f36", "wss://example.relay", "93ef2e…3e7f546"],
    ["k", "1111"],
    ["p", "93ef2e…3e7f546"]
  ]
}

Comment on a website URL

The root is a plain web page. The scope is an I tag with the URL, and the "kind" is the string web. There is no Nostr author, so there are no P or p tags.

Top-level comment on a URL
{
  "kind": 1111, "content": "Nice article!",
  "tags": [
    ["I", "https://abc.com/articles/1"],
    ["K", "web"],
    ["i", "https://abc.com/articles/1"],
    ["k", "web"]
  ]
}

Comment on a podcast episode, and a reply to it

The root is a podcast episode GUID from NIP-73. The I tag carries a web page hint as its third element. The reply keeps the external root and points its lowercase tags at the first comment, which is a Nostr event with an author.

Podcast comment, then reply
-- top-level comment --
{
  "id": "80c48d…bdac05", "pubkey": "252f10…2d9f111",
  "kind": 1111, "content": "This was a great episode!",
  "tags": [
    ["I", "podcast:item:guid:d98d18…690f31f", "https://fountain.fm/episode/z1y9TM…QRuqXl"],
    ["K", "podcast:item:guid"],
    ["i", "podcast:item:guid:d98d18…690f31f", "https://fountain.fm/episode/z1y9TM…QRuqXl"],
    ["k", "podcast:item:guid"]
  ]
}

-- reply: external root stays, parent = the comment above --
{
  "kind": 1111, "content": "I'm replying to the above comment.",
  "tags": [
    ["I", "podcast:item:guid:d98d18…690f31f", "https://fountain.fm/episode/z1y9TM…QRuqXl"],
    ["K", "podcast:item:guid"],
    ["e", "80c48d…bdac05", "wss://example.relay", "252f10…2d9f111"],
    ["k", "1111"],
    ["p", "252f10…2d9f111"]
  ]
}
Hint!

To load a full thread, subscribe with one filter on the uppercase tags: {"kinds":[1111], "#E":[<root id>]} (or #A / #I). Then rebuild the tree from each comment's lowercase e tag.

6 Version History

The number 22 has lived two lives. The Comment spec arrived in late 2024, in a slot left empty by a deleted NIP. Notable changes, newest first:

  • 20262026-08Allowed kind:1111 replies to kind-1 notes, reversing the 2025 warning against it.
  • 20252025-02Clarified what an I-tag is and how external scopes work.
  • 20252025-01Added a warning against replying to kind-1 notes with comments (removed again in 2026).
  • 20242024-12Added the P and p author tags.
  • 20242024-11arthurfranca introduced the Comment spec as the new NIP-22 (#1233).
  • 20232023-12The old NIP-22 was deleted (#897); the number became vacant.
  • 2025-262025-26Typo, JSON format, and code-fence fixes.
  • Origin2022-07Jeff Thibault created the original NIP-22, an unrelated spec on created_at limits.
Tech Note

The file's git history before 2024-11 belongs to the deleted "event created_at limits" spec, not to Comment. External references to "NIP-22" from 2022-2023 mean that older, unrelated spec.

Original Proposal - Credits

Authorarthurfranca (the Comment spec; the earlier, unrelated NIP-22 was by Jeff Thibault)
First commit2024-11-07 — “NIP-22 - Comment” (PR #1233); the file itself dates to 2022-07-22
Statusdraft - optional — clients choose whether to implement comments
Source22.md on GitHub - full change history

7 See Also

  • NIP-01 — the base event format, tags, and the a/e/p tag shapes reused here.
  • NIP-73 — the external content identifiers used in I/i tags and their k values.
  • NIP-21 — nostr: URIs for the citations and mentions that q and p tags mirror.
  • NIP-10 — the older threading scheme for kind-1 text notes.
  • NIP-23 — long-form articles, a common root for comments.
  • NIP-94 — file metadata events, used in the worked example.