Chapter C7 - Messaging
C7
Nostr Implementation Possibility - Hex № C7

Chats

A minimal chat message format: one kind, one reply tag, and one strict rule for what a chat view may fetch.

1 Overview

A chat is a stream of short messages in time order. This NIP defines the event format for one chat message. It uses a dedicated kind so that chat messages never mix with NIP-10 text notes.

The format is small on purpose. A chat message is a kind 9 event. A reply is another kind 9 event that quotes its parent with a q tag. There is no other structure.

This NIP began as part of NIP-29, the relay-based groups spec. In late 2024 the chat message format moved into its own document. Group chats still use kind 9; NIP-29 adds the group scoping on top.

Hint!

Chats are flat and fast. For long, branching discussions use NIP-7D forum threads instead. Both NIPs were split out of NIP-29 in the same change.

2 The Chat Message

A chat message is a kind 9 event as defined by NIP-01. The content field carries the message text. No tags are required.

Wire format - chat message (kind 9)
{
  "kind": 9,
  "content": "GM",
  "tags": []
}
Chat message reference
FieldValueRule
kind9Marks the event as a chat message. Kind 9 is a regular event: relays store all of them.
contentstringThe message text.
tagsarrayEmpty for a top-level message. A reply adds one q tag. See §3.

3 Replies

A reply to a kind 9 event is an additional kind 9 event. The reply quotes the parent in two places at once. The content embeds a NIP-21 nostr:nevent1… pointer to the parent, then the reply text. The tags array carries a q tag with the parent's data.

Wire format - reply (kind 9 quoting kind 9)
{
  "kind": 9,
  "content": "nostr:nevent1...\nyes",
  "tags": [
    ["q", <event-id>, <relay-url>, <pubkey>]
  ]
}
The q tag
PositionElementMeaning
0qTag name. Marks a quote of the parent event.
1<event-id>The id of the parent event, in hex.
2<relay-url>A relay where the parent event can be found.
3<pubkey>The pubkey of the parent event's author.
kind 9 - parent content: "GM" kind 9 - reply content: "nostr:nevent1...\nyes" tags: [["q", id, relay, pubkey]] q tag
Fig. C7-1 — Reply structure. The reply is a normal kind 9 event. Its q tag and its nostr: pointer both reference the parent.

4 Chat Views and Quoting

Some clients render a "chat view": a stream of events in time order. A client that renders a chat view MUST fetch only kind 9 events for that stream. This rule keeps every implementation on the same page. If one client mixed other kinds into the stream, users of other clients would miss context.

Other content types MAY still appear in a chat. To include one, quote it inside a kind 9 event. The quoting mechanism follows NIP-18: put a nostr: pointer in the content and a q tag in the tags. The kind 9 wrapper enters the stream; the quoted event rides inside it.

Relay kind 9, kind 9, kind 1, kind 30023 Filter {"kinds":[9]} Chat view kind 9 "GM" kind 9 "yes" kind 9 quoting the kind 1 note REQ kind 9 only
Fig. C7-2 — The chat view rule. Only kind 9 events enter the stream. Other kinds arrive wrapped in a quoting kind 9 event.
Warning!

Do not render kind 1 notes, reposts, or any other kind directly in an ordered chat stream. The MUST rule exists because a mixed stream on one client leaves holes in the same chat on every other client.

Tech Note

The source spec is minimal and leaves gaps. It defines no tag that scopes a chat message to a room, group, or peer; scoping comes from other NIPs, such as the NIP-29 h tag. It also does not say whether the <relay-url> and <pubkey> elements of the q tag are optional. Treat them as recommended hints, as in NIP-18.

5 Worked Example

Alice greets a group chat. Bob replies to her message. The session below shows both full events on the wire. Orange lines go to the relay. Blue lines come from the relay.

Session transcript - wss://groups.example.com
-- Alice sends a chat message --
→ ["EVENT", {"id":"a41f9dc6…","pubkey":"aa11ce22…","created_at":1750000000,
     "kind":9,"tags":[],"content":"GM","sig":"7be2f0a1…"}]
← ["OK", "a41f9dc6…", true, ""]

-- Bob replies, quoting Alice's event --
→ ["EVENT", {"id":"b52e8ab7…","pubkey":"b0bb0b33…","created_at":1750000060,
     "kind":9,
     "tags":[["q","a41f9dc6…","wss://groups.example.com","aa11ce22…"]],
     "content":"nostr:nevent1qqs2g…\nyes","sig":"91c4d7e2…"}]
← ["OK", "b52e8ab7…", true, ""]

-- Carol opens the chat view: kind 9 only --
→ ["REQ", "chat", {"kinds":[9], "limit":50}]
← ["EVENT", "chat", {"id":"b52e8ab7…", "kind":9, "content":"nostr:nevent1qqs2g…\nyes", …}]
← ["EVENT", "chat", {"id":"a41f9dc6…", "kind":9, "content":"GM", …}]
← ["EOSE", "chat"]

Carol's client renders the two kind 9 events in time order. It resolves Bob's nostr:nevent1… pointer and shows Alice's message as an inline quote above his reply.

6 Version History

NIP-C7 is young and short. Its full life fits in two entries, newest first:

  • 20262026-05Tightened the chat view rule: clients that render an ordered chat stream must fetch only kind 9 events. Other content types may be quoted inside a kind 9 per NIP-18.
  • Origin2024-11hodlbod broke chats and threads out of NIP-29. Kind 9 chat messages became this NIP; threads became NIP-7D.

Original Proposal - Credits

Authorhodlbod
First commit2024-11-21 — “Break out chat and threads from nip 29” (PR #1591)
Statusdraft - optional — implement it for chat features
SourceC7.md on GitHub - full change history

7 See Also

  • NIP-01 — the base event format and the client-relay flow that kind 9 rides on.
  • NIP-29 — relay-based groups; the original home of kind 9 and the source of group scoping.
  • NIP-7D — forum threads; the sibling NIP split out in the same change.
  • NIP-18 — reposts and the quoting mechanism used to embed other kinds in a chat.
  • NIP-21 — the nostr: URI scheme used in reply content.
  • NIP-19 — the nevent encoding inside those pointers.
  • NIP-10 — kind 1 text notes; the format chats deliberately avoid.