Chapter 28 - Chat
28
Nostr Implementation Possibility - Hex № 28

Public Chat

Telegram-style public chat rooms built from five event kinds, with moderation done by clients instead of relays.

Deprecated

1 Overview

Deprecated

The source spec carries an unrecommended warning: try NIP-29 instead. NIP-29 gives groups relay-side management, membership, and real moderation. Read this chapter to support legacy channels, not to build new ones.

This NIP defines public chat channels on top of plain NIP-01 events. A channel is a public room. Anyone can create one. Anyone can post to one. There are no members and no admission control.

The NIP reserves five event kinds, 40 to 44, for immediate use. Kind 40 creates a channel. Kind 41 updates channel metadata. Kind 42 carries a chat message. Kinds 43 and 44 hide a message or mute a user.

Moderation is client-centric. A client developer decides what content to show in their app. Relays get no new duties from this NIP. The stated motivation: if Nostr solves censorship-resistant social media, it can also solve Telegram-style messaging and bring that conversation into a public square open to all.

Reserved kinds (40-44)
KindNamePurpose
40channel createOpen a new public chat channel.
41channel metadataUpdate a channel's name, about, picture, relays, and category.
42channel messagePost a root message or a reply in a channel.
43hide messageHide one kind-42 message from your own view.
44mute userHide all messages from one pubkey in your own view.
Kind 40 channel create Kind 41 metadata update Kind 42 chat message Kind 42 reply e root e root e reply
Fig. 28-1 — Channel anatomy. The kind-40 event ID is the channel ID. Metadata and messages point back to it with e tags.

2 Kind 40: Create Channel

Publish a kind-40 event to create a public chat channel. The event ID of this kind-40 event becomes the channel identifier. All later channel events reference it.

In the creation event's content field, the client should include basic channel metadata: name, about, picture, and relays, with the same meaning as in kind 41. The metadata is a stringified JSON object.

Kind 40 - channel create
{
  "kind": 40,
  "content": "{\"name\": \"Demo Channel\",
     \"about\": \"A test channel.\",
     \"picture\": \"https://placekitten.com/200/200\",
     \"relays\": [\"wss://nos.lol\", \"wss://nostr.mom\"]}",
  // other fields per NIP-01...
}

3 Kind 41: Set Channel Metadata

Publish a kind-41 event to update a channel's public metadata. Kind 41 changes the metadata without changing the channel's event ID. Only the most recent kind 41 per e tag value may be available.

Two rules protect the channel:

  • Clients should ignore kind-41 events from any pubkey other than the kind-40 creator's pubkey.
  • Clients should use NIP-10 marked e tags to recommend a relay.

Clients should support four basic metadata fields. Clients may add more fields.

Channel metadata fields (kinds 40 and 41)
FieldTypeMeaning
namestringChannel name.
aboutstringChannel description.
picturestringURL of the channel picture.
relaysarrayList of relays to download and broadcast channel events to.

A kind-41 event can also set a category name with t tags. Clients can search and filter on the category name.

Kind 41 - metadata update
{
  "kind": 41,
  "content": "{\"name\": \"Updated Demo Channel\",
     \"about\": \"Updating a test channel.\",
     \"picture\": \"https://placekitten.com/201/201\",
     \"relays\": [\"wss://nos.lol\", \"wss://nostr.mom\"]}",
  "tags": [
    ["e", <channel_create_event_id>, <relay-url>, "root"],
    ["t", <category_name-1>],
    ["t", <category_name-2>],
    ["t", <category_name-3>]
  ],
  // other fields per NIP-01...
}
Tech Note

Kinds 40-44 sit in the regular storage range of NIP-01, so relays store every kind-41 event. The "only the most recent kind 41 may be available" rule is therefore a client duty, not a relay guarantee. Clients must select the newest kind 41 per channel themselves. The spec does not say what to do when two kind-41 updates tie on created_at.

4 Kind 42: Channel Message

Publish a kind-42 event to send a text message to a channel. The message text goes in content as a plain string.

Clients should use NIP-10 marked e tags to recommend a relay and to mark the message as a root or a reply. Clients should append NIP-10 p tags to replies.

A root message tags only the kind-40 channel creation event, with the root marker:

Kind 42 - root message
{
  "kind": 42,
  "content": <string>,
  "tags": [["e", <kind_40_event_id>, <relay-url>, "root"]],
  // other fields per NIP-01...
}

A reply keeps the root tag, adds the parent message with the reply marker, and tags the parent's author:

Kind 42 - reply
{
  "kind": 42,
  "content": <string>,
  "tags": [
    ["e", <kind_40_event_id>, <relay-url>, "root"],
    ["e", <kind_42_event_id>, <relay-url>, "reply"],
    ["p", <pubkey>, <relay-url>]
    // rest of tags...
  ],
  // other fields per NIP-01...
}

5 Kinds 43 and 44: Client-Side Moderation

Moderation in NIP-28 never deletes anything. A user publishes a small event that says "do not show me this". Each client decides how far to honor it.

Kind 43 — hide message. The user no longer wants to see one specific message. The event carries an e tag with the kind-42 event ID. The content may optionally include metadata such as a reason.

  • Clients should hide a kind-42 event from a given user if that user published a kind 43 matching the kind-42 id.
  • Clients may also hide that kind 42 for other users, not only the user who sent the kind 43. Example: three users hide a message with a reason that contains the word "pornography". An iOS client may then choose to hide that message for all of its iOS users.
Kind 43 - hide message
{
  "kind": 43,
  "content": "{\"reason\": \"spam\"}",
  "tags": [["e", <kind_42_event_id>]],
  // other fields per NIP-01...
}

Kind 44 — mute user. The user no longer wants to see any messages from another user. The event carries a p tag with the muted pubkey. The content may optionally include metadata such as a reason.

  • Clients should hide kind-42 events from a given user if that user published a kind 44 matching the kind-42 pubkey.
  • Clients may also hide those kind-42 events for users other than the user who sent the kind 44.
Kind 44 - mute user
{
  "kind": 44,
  "content": "{\"reason\": \"spam\"}",
  "tags": [["p", <pubkey>]],
  // other fields per NIP-01...
}
Relay stores all 42s Client filter apply 43 + 44 Chat view visible 42s all kind 42 filtered user's own kind 43 (hide) and kind 44 (mute) events
Fig. 28-2 — Client-side moderation. The relay keeps everything. The client drops hidden and muted messages before it renders the room.

6 Relay Recommendations

Clients should use the relay URLs listed in the metadata events, kinds 40 and 41. Clients may use any relay URL instead. Example: the relay that hosts the original kind-40 event goes offline. Clients can then fetch channel data from a backup relay, or from a relay they trust more than the original one.

Hint!

The channel ID is the kind-40 event ID, not a relay address. The channel survives as long as any relay still serves its events. Copy channel events to several relays early.

Tech Note

The source's "Additional info" section links a chat demo pull request (ArcadeCity/arcade#28) and a Telegram thread about NIP-16. Both are external context, not spec. The spec also once reserved a larger kind range; that reservation was removed in March 2023 and only kinds 40-44 remain.

7 Worked Example

The transcript below opens a channel, posts a root message, and answers it with a reply. A second user then mutes the replier. Orange lines go to the relay. Blue lines come from the relay.

Session transcript - wss://nos.lol
-- Alice creates the channel --
→ ["EVENT", {"id":"11aa22bb…","pubkey":"a1a1a1a1…","kind":40,"created_at":1749800000,
     "tags":[],"content":"{\"name\": \"Demo Channel\", \"about\": \"A test channel.\",
     \"picture\": \"https://placekitten.com/200/200\",
     \"relays\": [\"wss://nos.lol\", \"wss://nostr.mom\"]}","sig":"9c31ffe2…"}]
← ["OK", "11aa22bb…", true, ""]

-- Alice posts a root message --
→ ["EVENT", {"id":"33cc44dd…","pubkey":"a1a1a1a1…","kind":42,
     "tags":[["e","11aa22bb…","wss://nos.lol","root"]],
     "content":"Welcome to the demo channel.","sig":"41be07aa…"}]
← ["OK", "33cc44dd…", true, ""]

-- Bob replies to Alice --
→ ["EVENT", {"id":"55ee66ff…","pubkey":"b2b2b2b2…","kind":42,
     "tags":[["e","11aa22bb…","wss://nos.lol","root"],
             ["e","33cc44dd…","wss://nos.lol","reply"],
             ["p","a1a1a1a1…","wss://nos.lol"]],
     "content":"Glad to be here.","sig":"c04d19b7…"}]
← ["OK", "55ee66ff…", true, ""]

-- Carol loads the channel --
→ ["REQ", "chan", {"kinds":[42], "#e":["11aa22bb…"], "limit":50}]
← ["EVENT", "chan", {"id":"55ee66ff…", "kind":42, "content":"Glad to be here.", …}]
← ["EVENT", "chan", {"id":"33cc44dd…", "kind":42, "content":"Welcome to the demo channel.", …}]
← ["EOSE", "chan"]

-- Carol mutes Bob; her client stops rendering his kind 42s --
→ ["EVENT", {"id":"77aa88bb…","pubkey":"c3c3c3c3…","kind":44,
     "tags":[["p","b2b2b2b2…"]],"content":"{\"reason\": \"spam\"}","sig":"e2f80c11…"}]
← ["OK", "77aa88bb…", true, ""]

8 Version History

NIP-28 arrived in 2022 with the first wave of chat clients. It changed little after 2023 and now carries a deprecation warning. Notable changes, newest first:

  • 20262026-05Marked unrecommended with a warning in the spec body: try NIP-29 instead.
  • 20252025-01Added t tags to kind 41 so channels can carry searchable category names.
  • 20242024-06Simplified and fixed the kind-41 rules; clarified which relays clients should use for channel events.
  • 20232023-05Made the hide and mute rules more explicit: kind 43 matches the kind-42 id, kind 44 matches the kind-42 pubkey.
  • 20232023-03Made the root event tag compulsory; removed the reserved kind range, leaving only kinds 40-44.
  • 20232023-2024Formatting passes: tag commas, JSON reformatting, author list removed from the body.
  • Origin2022-09Christopher David proposed NIP-28: Public Chat in PR #38.

Original Proposal - Credits

AuthorChristopher David
First commit2022-09-10 — “NIP-28: Public Chat” (PR #38)
Statusdraftunrecommendedoptional
Source28.md on GitHub - full change history

9 See Also

  • NIP-29 — relay-based groups; the recommended replacement for this NIP.
  • NIP-01 — the event object, kinds, and storage classes that all five chat kinds rely on.
  • NIP-10 — the marked e tags (root, reply) and p tags used by kinds 41 and 42.
  • NIP-17 — private direct messages, for chat that should not be public.