12<html lang="en">3<head>4<meta charset="utf-8">5<meta name="viewport" content="width=device-width, initial-scale=1">6<title>NIP-28 - Public Chat — Nostr Instruction Manual</title>7<meta name="description" content="NIP-28: public chat channels with kinds 40-44. Channel creation, metadata, messages, and client-side moderation. Deprecated in favor of NIP-29.">8<link rel="preload" href="../assets/fonts/michroma-400-latin.woff2" as="font" type="font/woff2" crossorigin>9<link rel="preload" href="../assets/fonts/exo2-var-latin.woff2" as="font" type="font/woff2" crossorigin>10<link rel="preload" href="../assets/fonts/sairacondensed-600-latin.woff2" as="font" type="font/woff2" crossorigin>11<link rel="preload" href="../assets/fonts/sairacondensed-700-latin.woff2" as="font" type="font/woff2" crossorigin>12<link rel="preload" href="../assets/fonts/sairacondensed-500-latin.woff2" as="font" type="font/woff2" crossorigin>13<link rel="preload" href="../assets/fonts/sharetechmono-400-latin.woff2" as="font" type="font/woff2" crossorigin>14<link rel="preload" href="../assets/fonts/exo2-400i-latin.woff2" as="font" type="font/woff2" crossorigin>15<link rel="icon" href="../assets/favicon.svg" type="image/svg+xml">16<link rel="stylesheet" href="../assets/manual.css">17</head>18<body>1920<svg width="0" height="0" style="position:absolute">21 <defs>22 <marker id="arr" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto">23 <path d="M1,1 L8,4.5 L1,8 Z" fill="#f26a00"/>24 </marker>25 <marker id="arrb" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto">26 <path d="M1,1 L8,4.5 L1,8 Z" fill="#2e5f9e"/>27 </marker>28 </defs>29</svg>3031<div class="page">32 <span class="staple s1"></span><span class="staple s2"></span>3334 <header class="band">35 <a class="logo" href="../index.html">NOSTR<b>▸</b>PROTOCOL MANUAL</a>36 <span class="booklet-note">Chapter 28 - Chat</span>37 </header>38 <nav class="tabs">39 <a href="../index.html">Contents</a>40 <a href="#overview" class="on">Overview</a>41 <a href="#spec">Spec</a>42 <a href="#examples">Examples</a>43 <a href="#history">History</a>44 </nav>4546 <div class="chapter">47 <div class="nipno" data-n="28">28</div>48 <div class="titles">49 <div class="kicker">Nostr Implementation Possibility - Hex № 28</div>50 <h1>Public Chat</h1>51 <p class="sub">Telegram-style public chat rooms built from five event kinds, with moderation done by clients instead of relays.</p>52 </div>53 <div class="stamp">Deprecated</div>54 </div>5556 <main class="spread">57 <div class="main">5859 <h2 class="bar" id="overview"><span class="num">1</span> Overview</h2>6061 <div class="box danger">62 <span class="tag">Deprecated</span>63 <p>The source spec carries an <span class="chip unrecommended">unrecommended</span> warning: try <a href="29.html">NIP-29</a> instead. NIP-29 gives groups relay-side management, membership, and real moderation. Read this chapter to support legacy channels, not to build new ones.</p>64 </div>6566 <p>This NIP defines public chat channels on top of plain <a href="01.html">NIP-01</a> events. A channel is a public room. Anyone can create one. Anyone can post to one. There are no members and no admission control.</p>67 <p>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.</p>68 <p>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.</p>6970 <div class="tscroll"><table class="ref">71 <caption>Reserved kinds (40-44)</caption>72 <tr><th>Kind</th><th>Name</th><th>Purpose</th></tr>73 <tr><td class="btn">40</td><td>channel create</td><td>Open a new public chat channel.</td></tr>74 <tr><td class="btn">41</td><td>channel metadata</td><td>Update a channel's name, about, picture, relays, and category.</td></tr>75 <tr><td class="btn">42</td><td>channel message</td><td>Post a root message or a reply in a channel.</td></tr>76 <tr><td class="btn">43</td><td>hide message</td><td>Hide one kind-42 message from your own view.</td></tr>77 <tr><td class="btn">44</td><td>mute user</td><td>Hide all messages from one pubkey in your own view.</td></tr>78 </table></div>7980 <figure class="diagram">81 <div class="frame">82 <svg viewBox="0 0 560 190" role="img" aria-label="Channel lifecycle: a kind 40 event creates the channel, kind 41 events update its metadata, and kind 42 messages tag the kind 40 event as root">83 <rect class="d-actor" x="10" y="70" width="130" height="50" rx="8"/>84 <text class="d-actor-label" x="75" y="92" text-anchor="middle">Kind 40</text>85 <text class="d-note" x="75" y="109" text-anchor="middle">channel create</text>86 <rect class="d-actor" x="225" y="14" width="130" height="50" rx="8"/>87 <text class="d-actor-label" x="290" y="36" text-anchor="middle">Kind 41</text>88 <text class="d-note" x="290" y="53" text-anchor="middle">metadata update</text>89 <rect class="d-actor" x="225" y="126" width="130" height="50" rx="8"/>90 <text class="d-actor-label" x="290" y="148" text-anchor="middle">Kind 42</text>91 <text class="d-note" x="290" y="165" text-anchor="middle">chat message</text>92 <rect class="d-actor" x="420" y="126" width="130" height="50" rx="8"/>93 <text class="d-actor-label" x="485" y="148" text-anchor="middle">Kind 42</text>94 <text class="d-note" x="485" y="165" text-anchor="middle">reply</text>95 <path class="d-msg d-flow" d="M227,52 C185,60 175,72 142,82"/>96 <path class="d-msg d-flow" d="M227,138 C185,130 175,118 142,108"/>97 <path class="d-msg blue d-flow" d="M418,140 L357,140"/>98 <text class="d-label" x="168" y="46" text-anchor="middle">e root</text>99 <text class="d-label" x="168" y="152" text-anchor="middle">e root</text>100 <text class="d-label" x="388" y="132" text-anchor="middle">e reply</text>101 <circle r="4" fill="#f26a00">102 <animateMotion dur="2.6s" repeatCount="indefinite" path="M227,138 C185,130 175,118 142,108"/>103 </circle>104 </svg>105 </div>106 <figcaption>Fig. 28-1 — <b>Channel anatomy.</b> The kind-40 event ID is the channel ID. Metadata and messages point back to it with <code>e</code> tags.</figcaption>107 </figure>108109 <h2 class="bar" id="spec"><span class="num">2</span> Kind 40: Create Channel</h2>110 <p>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.</p>111 <p>In the creation event's <code>content</code> field, the client should include basic channel metadata: <code>name</code>, <code>about</code>, <code>picture</code>, and <code>relays</code>, with the same meaning as in kind 41. The metadata is a stringified JSON object.</p>112113 <div class="crt">114 <div class="titlebar">Kind 40 - channel create</div>115<pre>{116 <span class="k">"kind"</span>: 40,117 <span class="k">"content"</span>: <span class="s">"{\"name\": \"Demo Channel\",118 \"about\": \"A test channel.\",119 \"picture\": \"https://placekitten.com/200/200\",120 \"relays\": [\"wss://nos.lol\", \"wss://nostr.mom\"]}"</span>,121 <span class="c">// other fields per NIP-01...</span>122}</pre>123 </div>124125 <h2 class="bar"><span class="num">3</span> Kind 41: Set Channel Metadata</h2>126 <p>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 <code>e</code> tag value may be available.</p>127 <p>Two rules protect the channel:</p>128 <ul>129 <li>Clients should ignore kind-41 events from any pubkey other than the kind-40 creator's pubkey.</li>130 <li>Clients should use <a href="10.html">NIP-10</a> marked <code>e</code> tags to recommend a relay.</li>131 </ul>132 <p>Clients should support four basic metadata fields. Clients may add more fields.</p>133134 <div class="tscroll"><table class="ref">135 <caption>Channel metadata fields (kinds 40 and 41)</caption>136 <tr><th>Field</th><th>Type</th><th>Meaning</th></tr>137 <tr><td class="btn">name</td><td>string</td><td>Channel name.</td></tr>138 <tr><td class="btn">about</td><td>string</td><td>Channel description.</td></tr>139 <tr><td class="btn">picture</td><td>string</td><td>URL of the channel picture.</td></tr>140 <tr><td class="btn">relays</td><td>array</td><td>List of relays to download and broadcast channel events to.</td></tr>141 </table></div>142143 <p>A kind-41 event can also set a category name with <code>t</code> tags. Clients can search and filter on the category name.</p>144145 <div class="crt">146 <div class="titlebar">Kind 41 - metadata update</div>147<pre>{148 <span class="k">"kind"</span>: 41,149 <span class="k">"content"</span>: <span class="s">"{\"name\": \"Updated Demo Channel\",150 \"about\": \"Updating a test channel.\",151 \"picture\": \"https://placekitten.com/201/201\",152 \"relays\": [\"wss://nos.lol\", \"wss://nostr.mom\"]}"</span>,153 <span class="k">"tags"</span>: [154 [<span class="s">"e"</span>, <span class="c"><channel_create_event_id></span>, <span class="c"><relay-url></span>, <span class="s">"root"</span>],155 [<span class="s">"t"</span>, <span class="c"><category_name-1></span>],156 [<span class="s">"t"</span>, <span class="c"><category_name-2></span>],157 [<span class="s">"t"</span>, <span class="c"><category_name-3></span>]158 ],159 <span class="c">// other fields per NIP-01...</span>160}</pre>161 </div>162163 <div class="box tech">164 <span class="tag">Tech Note</span>165 <p>Kinds 40-44 sit in the <em>regular</em> storage range of <a href="01.html">NIP-01</a>, 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 <code>created_at</code>.</p>166 </div>167168 <h2 class="bar"><span class="num">4</span> Kind 42: Channel Message</h2>169 <p>Publish a kind-42 event to send a text message to a channel. The message text goes in <code>content</code> as a plain string.</p>170 <p>Clients should use <a href="10.html">NIP-10</a> marked <code>e</code> tags to recommend a relay and to mark the message as a root or a reply. Clients should append <a href="10.html">NIP-10</a> <code>p</code> tags to replies.</p>171 <p>A <strong>root message</strong> tags only the kind-40 channel creation event, with the <code>root</code> marker:</p>172173 <div class="crt">174 <div class="titlebar">Kind 42 - root message</div>175<pre>{176 <span class="k">"kind"</span>: 42,177 <span class="k">"content"</span>: <span class="c"><string></span>,178 <span class="k">"tags"</span>: [[<span class="s">"e"</span>, <span class="c"><kind_40_event_id></span>, <span class="c"><relay-url></span>, <span class="s">"root"</span>]],179 <span class="c">// other fields per NIP-01...</span>180}</pre>181 </div>182183 <p>A <strong>reply</strong> keeps the root tag, adds the parent message with the <code>reply</code> marker, and tags the parent's author:</p>184185 <div class="crt">186 <div class="titlebar">Kind 42 - reply</div>187<pre>{188 <span class="k">"kind"</span>: 42,189 <span class="k">"content"</span>: <span class="c"><string></span>,190 <span class="k">"tags"</span>: [191 [<span class="s">"e"</span>, <span class="c"><kind_40_event_id></span>, <span class="c"><relay-url></span>, <span class="s">"root"</span>],192 [<span class="s">"e"</span>, <span class="c"><kind_42_event_id></span>, <span class="c"><relay-url></span>, <span class="s">"reply"</span>],193 [<span class="s">"p"</span>, <span class="c"><pubkey></span>, <span class="c"><relay-url></span>]194 <span class="c">// rest of tags...</span>195 ],196 <span class="c">// other fields per NIP-01...</span>197}</pre>198 </div>199200 <h2 class="bar"><span class="num">5</span> Kinds 43 and 44: Client-Side Moderation</h2>201 <p>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.</p>202203 <p><strong>Kind 43 — hide message.</strong> The user no longer wants to see one specific message. The event carries an <code>e</code> tag with the kind-42 event ID. The <code>content</code> may optionally include metadata such as a <code>reason</code>.</p>204 <ul>205 <li>Clients should hide a kind-42 event from a given user if that user published a kind 43 matching the kind-42 <code>id</code>.</li>206 <li>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.</li>207 </ul>208209 <div class="crt">210 <div class="titlebar">Kind 43 - hide message</div>211<pre>{212 <span class="k">"kind"</span>: 43,213 <span class="k">"content"</span>: <span class="s">"{\"reason\": \"spam\"}"</span>,214 <span class="k">"tags"</span>: [[<span class="s">"e"</span>, <span class="c"><kind_42_event_id></span>]],215 <span class="c">// other fields per NIP-01...</span>216}</pre>217 </div>218219 <p><strong>Kind 44 — mute user.</strong> The user no longer wants to see any messages from another user. The event carries a <code>p</code> tag with the muted pubkey. The <code>content</code> may optionally include metadata such as a <code>reason</code>.</p>220 <ul>221 <li>Clients should hide kind-42 events from a given user if that user published a kind 44 matching the kind-42 <code>pubkey</code>.</li>222 <li>Clients may also hide those kind-42 events for users other than the user who sent the kind 44.</li>223 </ul>224225 <div class="crt">226 <div class="titlebar">Kind 44 - mute user</div>227<pre>{228 <span class="k">"kind"</span>: 44,229 <span class="k">"content"</span>: <span class="s">"{\"reason\": \"spam\"}"</span>,230 <span class="k">"tags"</span>: [[<span class="s">"p"</span>, <span class="c"><pubkey></span>]],231 <span class="c">// other fields per NIP-01...</span>232}</pre>233 </div>234235 <figure class="diagram">236 <div class="frame">237 <svg viewBox="0 0 560 200" role="img" aria-label="Relay stores all channel messages; the client filters out messages matched by the user's kind 43 hide events and kind 44 mute events before rendering the chat view">238 <rect class="d-actor" x="10" y="60" width="110" height="60" rx="8"/>239 <text class="d-actor-label" x="65" y="86" text-anchor="middle">Relay</text>240 <text class="d-note" x="65" y="104" text-anchor="middle">stores all 42s</text>241 <rect class="d-actor" x="225" y="60" width="130" height="60" rx="8"/>242 <text class="d-actor-label" x="290" y="86" text-anchor="middle">Client filter</text>243 <text class="d-note" x="290" y="104" text-anchor="middle">apply 43 + 44</text>244 <rect class="d-actor" x="440" y="60" width="110" height="60" rx="8"/>245 <text class="d-actor-label" x="495" y="86" text-anchor="middle">Chat view</text>246 <text class="d-note" x="495" y="104" text-anchor="middle">visible 42s</text>247 <path class="d-msg blue d-flow" d="M122,90 L222,90"/>248 <path class="d-msg d-flow" d="M357,90 L437,90"/>249 <path class="d-msg" d="M290,160 L290,124"/>250 <text class="d-label" x="172" y="82" text-anchor="middle">all kind 42</text>251 <text class="d-label" x="397" y="82" text-anchor="middle">filtered</text>252 <text class="d-note" x="290" y="180" text-anchor="middle">user's own kind 43 (hide) and kind 44 (mute) events</text>253 <circle r="4" fill="#2e5f9e">254 <animateMotion dur="2.6s" repeatCount="indefinite" path="M122,90 L222,90"/>255 </circle>256 </svg>257 </div>258 <figcaption>Fig. 28-2 — <b>Client-side moderation.</b> The relay keeps everything. The client drops hidden and muted messages before it renders the room.</figcaption>259 </figure>260261 <h2 class="bar"><span class="num">6</span> Relay Recommendations</h2>262 <p>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.</p>263264 <div class="box hint">265 <span class="tag">Hint!</span>266 <p>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.</p>267 </div>268269 <div class="box tech">270 <span class="tag">Tech Note</span>271 <p>The source's "Additional info" section links a chat demo pull request (<code>ArcadeCity/arcade#28</code>) 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.</p>272 </div>273274 <h2 class="bar" id="examples"><span class="num">7</span> Worked Example</h2>275 <p>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.</p>276 <div class="crt">277 <div class="titlebar">Session transcript - wss://nos.lol</div>278<pre><span class="c">-- Alice creates the channel --</span>279<span class="send">→ ["EVENT", {"id":"11aa22bb…","pubkey":"a1a1a1a1…","kind":40,"created_at":1749800000,280 "tags":[],"content":"{\"name\": \"Demo Channel\", \"about\": \"A test channel.\",281 \"picture\": \"https://placekitten.com/200/200\",282 \"relays\": [\"wss://nos.lol\", \"wss://nostr.mom\"]}","sig":"9c31ffe2…"}]</span>283<span class="recv">← ["OK", "11aa22bb…", true, ""]</span>284285<span class="c">-- Alice posts a root message --</span>286<span class="send">→ ["EVENT", {"id":"33cc44dd…","pubkey":"a1a1a1a1…","kind":42,287 "tags":[["e","11aa22bb…","wss://nos.lol","root"]],288 "content":"Welcome to the demo channel.","sig":"41be07aa…"}]</span>289<span class="recv">← ["OK", "33cc44dd…", true, ""]</span>290291<span class="c">-- Bob replies to Alice --</span>292<span class="send">→ ["EVENT", {"id":"55ee66ff…","pubkey":"b2b2b2b2…","kind":42,293 "tags":[["e","11aa22bb…","wss://nos.lol","root"],294 ["e","33cc44dd…","wss://nos.lol","reply"],295 ["p","a1a1a1a1…","wss://nos.lol"]],296 "content":"Glad to be here.","sig":"c04d19b7…"}]</span>297<span class="recv">← ["OK", "55ee66ff…", true, ""]</span>298299<span class="c">-- Carol loads the channel --</span>300<span class="send">→ ["REQ", "chan", {"kinds":[42], "#e":["11aa22bb…"], "limit":50}]</span>301<span class="recv">← ["EVENT", "chan", {"id":"55ee66ff…", "kind":42, "content":"Glad to be here.", …}]</span>302<span class="recv">← ["EVENT", "chan", {"id":"33cc44dd…", "kind":42, "content":"Welcome to the demo channel.", …}]</span>303<span class="recv">← ["EOSE", "chan"]</span>304305<span class="c">-- Carol mutes Bob; her client stops rendering his kind 42s --</span>306<span class="send">→ ["EVENT", {"id":"77aa88bb…","pubkey":"c3c3c3c3…","kind":44,307 "tags":[["p","b2b2b2b2…"]],"content":"{\"reason\": \"spam\"}","sig":"e2f80c11…"}]</span>308<span class="recv">← ["OK", "77aa88bb…", true, ""]</span></pre>309 </div>310311 <h2 class="bar" id="history"><span class="num">8</span> Version History</h2>312 <p>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:</p>313 <ul class="patchnotes">314 <li><span class="ver">2026</span><span class="when">2026-05</span>Marked <code>unrecommended</code> with a warning in the spec body: try <a href="29.html">NIP-29</a> instead.</li>315 <li><span class="ver">2025</span><span class="when">2025-01</span>Added <code>t</code> tags to kind 41 so channels can carry searchable category names.</li>316 <li><span class="ver">2024</span><span class="when">2024-06</span>Simplified and fixed the kind-41 rules; clarified which relays clients should use for channel events.</li>317 <li><span class="ver">2023</span><span class="when">2023-05</span>Made the hide and mute rules more explicit: kind 43 matches the kind-42 <code>id</code>, kind 44 matches the kind-42 <code>pubkey</code>.</li>318 <li><span class="ver">2023</span><span class="when">2023-03</span>Made the <code>root</code> event tag compulsory; removed the reserved kind range, leaving only kinds 40-44.</li>319 <li class="minor"><span class="ver">2023</span><span class="when">2023-2024</span>Formatting passes: tag commas, JSON reformatting, author list removed from the body.</li>320 <li><span class="ver">Origin</span><span class="when">2022-09</span>Christopher David proposed NIP-28: Public Chat in PR #38.</li>321 </ul>322323 <div class="credits">324 <h3 class="cardhead">Original Proposal - Credits</h3>325 <table>326 <tr><td>Author</td><td>Christopher David</td></tr>327 <tr><td>First commit</td><td>2022-09-10 — “NIP-28: Public Chat” (<a href="https://github.com/nostr-protocol/nips/pull/38">PR #38</a>)</td></tr>328 <tr><td>Status</td><td><span class="chip draft">draft</span><span class="chip unrecommended">unrecommended</span><span class="chip optional">optional</span></td></tr>329 <tr><td>Source</td><td><a href="https://github.com/nostr-protocol/nips/blob/master/28.md">28.md on GitHub</a> - <a href="https://github.com/nostr-protocol/nips/commits/master/28.md">full change history</a></td></tr>330 </table>331 </div>332333 <h2 class="bar"><span class="num">9</span> See Also</h2>334 <ul>335 <li><a href="29.html">NIP-29</a> — relay-based groups; the recommended replacement for this NIP.</li>336 <li><a href="01.html">NIP-01</a> — the event object, kinds, and storage classes that all five chat kinds rely on.</li>337 <li><a href="10.html">NIP-10</a> — the marked <code>e</code> tags (<code>root</code>, <code>reply</code>) and <code>p</code> tags used by kinds 41 and 42.</li>338 <li><a href="17.html">NIP-17</a> — private direct messages, for chat that should not be public.</li>339 </ul>340 </div>341342 <aside>343 <div class="cartridge">344 <div class="inner">345 <h3 class="cardhead">Spec Card</h3>346 <div class="lights"><span class="led err"></span><span class="led err"></span><span class="led err"></span></div>347 <dl>348 <dt>Status</dt><dd><span class="chip draft">draft</span><span class="chip unrecommended">unrecommended</span><span class="chip optional">optional</span></dd>349 <dt>Defines</dt><dd>public chat channels - client-side moderation</dd>350 <dt>Kinds</dt><dd>40 (create) - 41 (metadata) - 42 (message) - 43 (hide) - 44 (mute)</dd>351 <dt>Requires</dt><dd><a href="01.html">NIP-01</a> - <a href="10.html">NIP-10</a> markers</dd>352 <dt>Replaced by</dt><dd><a href="29.html">NIP-29</a> relay-based groups</dd>353 <dt>Transport</dt><dd>WebSocket - JSON arrays</dd>354 <dt>First commit</dt><dd>2022-09-10</dd>355 <dt>Last updated</dt><dd>2026-06-13</dd>356 </dl>357 </div>358 </div>359 </aside>360 </main>361362 <nav class="navbtns">363 <a href="27.html">◀ NIP-27: Text Note References</a>364 <a href="29.html">NIP-29: Relay-based Groups ▶</a>365 </nav>366367 <footer class="pagefoot">368 <a href="../index.html">Nostr Protocol Manual</a>369 <span class="pageno">NIP 28 / F4</span>370 </footer>371</div>372373<script src="../assets/webmcp.js" defer></script>374</body>375</html>