1 Overview
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.
| Kind | Name | Purpose |
|---|---|---|
| 40 | channel create | Open a new public chat channel. |
| 41 | channel metadata | Update a channel's name, about, picture, relays, and category. |
| 42 | channel message | Post a root message or a reply in a channel. |
| 43 | hide message | Hide one kind-42 message from your own view. |
| 44 | mute user | Hide all messages from one pubkey in your own view. |
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,
"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
etags to recommend a relay.
Clients should support four basic metadata fields. Clients may add more fields.
| Field | Type | Meaning |
|---|---|---|
| name | string | Channel name. |
| about | string | Channel description. |
| picture | string | URL of the channel picture. |
| relays | array | List 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,
"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...
}
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,
"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,
"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,
"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,
"content": "{\"reason\": \"spam\"}",
"tags": [["p", <pubkey>]],
// other fields per NIP-01...
}
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.
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.
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.
-- 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
unrecommendedwith a warning in the spec body: try NIP-29 instead. - 20252025-01Added
ttags 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-42pubkey. - 20232023-03Made the
rootevent 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
| Author | Christopher David |
| First commit | 2022-09-10 — “NIP-28: Public Chat” (PR #38) |
| Status | draftunrecommendedoptional |
| Source | 28.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
etags (root,reply) andptags used by kinds 41 and 42. - NIP-17 — private direct messages, for chat that should not be public.