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-B0 - Web Bookmarking — Nostr Instruction Manual</title>7<meta name="description" content="NIP-B0: editable web bookmarks as kind 39701 events. URI-based d tags, metadata tags, and NIP-22 comments. Complete manual page.">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 B0 - Web Content</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="B0">B0</div>48 <div class="titles">49 <div class="kicker">Nostr Implementation Possibility - Hex № B0</div>50 <h1>Web Bookmarking</h1>51 <p class="sub">Save any web page as an editable, addressable Nostr event that anyone can find by its URI.</p>52 </div>53 </div>5455 <main class="spread">56 <div class="main">5758 <h2 class="bar" id="overview"><span class="num">1</span> Overview</h2>59 <p>A <strong>web bookmark</strong> is a saved reference to one web page. This NIP defines <code>kind:39701</code> for web bookmarks. Each bookmark is one event. The bookmarked URI lives in the event's <code>d</code> tag.</p>60 <p>Kind <code>39701</code> sits in the addressable range of <a href="01.html">NIP-01</a>. A relay keeps only the latest event per <code>pubkey</code> + <code>kind</code> + <code>d</code> value. A user can therefore edit a bookmark. The user publishes a new event with the same <code>d</code> value, and the old version goes away.</p>61 <p>Because the <code>d</code> value is the URI itself, clients can query bookmarks by URI. One <code>#d</code> filter returns every user's bookmark of the same page. This turns private bookmarking into a shared, social index of the web.</p>6263 <div class="box hint">64 <span class="tag">Hint!</span>65 <p>Do not confuse this NIP with the bookmark <em>lists</em> of <a href="51.html">NIP-51</a>. A NIP-51 list stores many references inside one event. A NIP-B0 bookmark is one standalone event per URI, with its own description, topics, and comments.</p>66 </div>6768 <figure class="diagram">69 <div class="frame">70 <svg viewBox="0 0 560 190" role="img" aria-label="Two users bookmark the same page; a reader queries relays by the d tag and receives both bookmarks">71 <rect class="d-actor" x="10" y="20" width="110" height="44" rx="8"/>72 <text class="d-actor-label" x="65" y="47" text-anchor="middle">Alice</text>73 <rect class="d-actor" x="10" y="126" width="110" height="44" rx="8"/>74 <text class="d-actor-label" x="65" y="153" text-anchor="middle">Bob</text>75 <rect class="d-actor" x="225" y="70" width="110" height="50" rx="8"/>76 <text class="d-actor-label" x="280" y="92" text-anchor="middle">Relay</text>77 <text class="d-note" x="280" y="109" text-anchor="middle">kind 39701</text>78 <rect class="d-actor" x="440" y="70" width="110" height="50" rx="8"/>79 <text class="d-actor-label" x="495" y="99" text-anchor="middle">Reader</text>80 <path class="d-msg d-flow" d="M122,44 C170,52 180,70 223,82"/>81 <path class="d-msg d-flow" d="M122,146 C170,138 180,120 223,108"/>82 <path class="d-msg blue d-flow" d="M337,95 L438,95"/>83 <text class="d-label" x="160" y="40" text-anchor="middle">EVENT</text>84 <text class="d-label" x="388" y="86" text-anchor="middle">#d query</text>85 <circle r="4" fill="#f26a00">86 <animateMotion dur="2.6s" repeatCount="indefinite" path="M122,44 C170,52 180,70 223,82"/>87 </circle>88 <circle r="4" fill="#2e5f9e">89 <animateMotion dur="2.6s" begin="1.3s" repeatCount="indefinite" path="M337,95 L438,95"/>90 </circle>91 </svg>92 </div>93 <figcaption>Fig. B0-1 — <b>Bookmarks as a shared index.</b> Alice and Bob each publish a bookmark of the same page. A reader queries the <code>d</code> value and gets both.</figcaption>94 </figure>9596 <h2 class="bar" id="spec"><span class="num">2</span> The Bookmark Event</h2>97 <p>A web bookmark is a normal signed event with <code>kind:39701</code>. The <code>content</code> field holds a detailed description of the bookmark. The description can be an empty string. The <code>d</code> tag is required. All other tags are optional metadata.</p>9899 <div class="crt">100 <div class="titlebar">Wire format - kind 39701 web bookmark</div>101<pre>{102 <span class="k">"kind"</span>: 39701,103 <span class="k">"content"</span>: <span class="c"><description of the bookmark, may be ""></span>,104 <span class="k">"tags"</span>: [105 [<span class="s">"d"</span>, <span class="c"><URI of the bookmarked page></span>], <span class="c">// required</span>106 [<span class="s">"published_at"</span>, <span class="c"><unix seconds, string></span>], <span class="c">// optional</span>107 [<span class="s">"title"</span>, <span class="c"><title of the bookmark></span>], <span class="c">// optional</span>108 [<span class="s">"t"</span>, <span class="c"><topic></span>], ... <span class="c">// optional, repeatable</span>109 ],110 <span class="c">// plus the standard id, pubkey, created_at, sig fields</span>111}</pre>112 </div>113114 <div class="tscroll"><table class="ref">115 <caption>Field reference</caption>116 <tr><th>Field</th><th>Rule</th></tr>117 <tr><td class="btn">kind</td><td>Always <code>39701</code>. Addressable per <a href="01.html">NIP-01</a>: relays keep the latest event per <code>pubkey</code> + <code>kind</code> + <code>d</code> value.</td></tr>118 <tr><td class="btn">content</td><td>A detailed description of the web bookmark. An empty string is allowed.</td></tr>119 <tr><td class="btn">tags</td><td>Must contain one <code>d</code> tag. May contain the metadata tags of §4.</td></tr>120 </table></div>121122 <h2 class="bar" id="dtag"><span class="num">3</span> The d Tag: One URI per Bookmark</h2>123 <p>The <code>d</code> tag value is the URI of the bookmarked page. One rule shapes the value. If the scheme is <code>https</code>, omit all characters before the hostname. Drop <code>https://</code> and start the value at the hostname. For any other scheme, keep the URI as it is.</p>124 <div class="crt">125 <div class="titlebar">Deriving the d value</div>126<pre><span class="c">https://alice.blog/post</span> → <span class="s">"alice.blog/post"</span> <span class="c">// https scheme dropped</span>127<span class="c">http://old.example/page</span> → <span class="s">"http://old.example/page"</span>128<span class="c">gemini://caps.example/doc</span> → <span class="s">"gemini://caps.example/doc"</span></pre>129 </div>130 <p>This rule makes the <code>d</code> value predictable. Clients query web bookmark events by the <code>d</code> tag. A filter such as <code>{"kinds": [39701], "#d": ["alice.blog/post"]}</code> returns every bookmark of that page, from every user, on that relay.</p>131132 <figure class="diagram">133 <div class="frame">134 <svg viewBox="0 0 560 120" role="img" aria-label="A URL is normalized into a d value, signed into a kind 39701 event, and stored by the relay as the latest version for that address">135 <rect class="d-actor" x="10" y="35" width="120" height="50" rx="8"/>136 <text class="d-actor-label" x="70" y="57" text-anchor="middle">URL</text>137 <text class="d-note" x="70" y="74" text-anchor="middle">https://a.blog/post</text>138 <rect class="d-actor" x="180" y="35" width="110" height="50" rx="8"/>139 <text class="d-actor-label" x="235" y="57" text-anchor="middle">Normalize</text>140 <text class="d-note" x="235" y="74" text-anchor="middle">drop https://</text>141 <rect class="d-actor" x="340" y="35" width="90" height="50" rx="8"/>142 <text class="d-actor-label" x="385" y="57" text-anchor="middle">Sign</text>143 <text class="d-note" x="385" y="74" text-anchor="middle">kind 39701</text>144 <rect class="d-actor" x="480" y="35" width="70" height="50" rx="8"/>145 <text class="d-actor-label" x="515" y="57" text-anchor="middle">Relay</text>146 <text class="d-note" x="515" y="74" text-anchor="middle">latest wins</text>147 <path class="d-msg d-flow" d="M132,60 L177,60"/>148 <path class="d-msg d-flow" d="M292,60 L337,60"/>149 <path class="d-msg d-flow" d="M432,60 L477,60"/>150 </svg>151 </div>152 <figcaption>Fig. B0-2 — <b>The d value pipeline.</b> Normalize the URL, sign the event, publish. Republishing the same <code>d</code> value edits the bookmark.</figcaption>153 </figure>154155 <div class="box tech">156 <span class="tag">Tech Note</span>157 <p>The spec defines no URI normalization beyond dropping the <code>https://</code> prefix. It does not say how to treat trailing slashes, <code>www.</code> prefixes, query strings, or fragments. Two clients can derive different <code>d</code> values for the same page, and those bookmarks will not match in a <code>#d</code> query. The spec also does not state which HTML link attribute the <code>title</code> tag maps to.</p>158 </div>159160 <h2 class="bar" id="metadata"><span class="num">4</span> Metadata Tags</h2>161 <p>Metadata fields can be added to the event as tags when necessary. This NIP names three:</p>162 <div class="tscroll"><table class="ref">163 <caption>Metadata tags</caption>164 <tr><th>Tag</th><th>Value</th><th>Purpose</th></tr>165 <tr><td class="btn">t</td><td>topic string</td><td>A tag or hashtag: a topic about which the event might be of relevance. Repeat the tag for each topic.</td></tr>166 <tr><td class="btn">published_at</td><td>unix seconds, stringified</td><td>The timestamp of the first time the bookmark was published. Later edits keep this value.</td></tr>167 <tr><td class="btn">title</td><td>title string</td><td>A title for the bookmark. It can serve as an attribute for the HTML link element.</td></tr>168 </table></div>169170 <h2 class="bar" id="comments"><span class="num">5</span> Replies and Comments</h2>171 <p>Replies to a <code>kind:39701</code> bookmark must use <code>kind:1111</code> comment events, as defined in <a href="22.html">NIP-22</a>. Do not reply with plain kind-1 notes. The NIP-22 comment carries scope tags that point back to the bookmark's address, so threads stay attached to the bookmark even after edits.</p>172173 <h2 class="bar" id="examples"><span class="num">6</span> Worked Example</h2>174 <p>Alice bookmarks a blog post at <code>https://alice.blog/post</code>. The scheme is <code>https</code>, so the <code>d</code> value starts at the hostname. She adds a title, two topics, and a first-publication timestamp.</p>175 <div class="crt">176 <div class="titlebar">Full event - kind 39701</div>177<pre>{178 <span class="k">"kind"</span>: 39701,179 <span class="k">"id"</span>: <span class="s">"d7a92714f81d0f712e715556aee69ea6da6bfb287e6baf794a095d301d603ec7"</span>,180 <span class="k">"pubkey"</span>: <span class="s">"2729620da105979b22acfdfe9585274a78c282869b493abfa4120d3af2061298"</span>,181 <span class="k">"created_at"</span>: 1738869705,182 <span class="k">"tags"</span>: [183 <span class="c">// required tags</span>184 [<span class="s">"d"</span>, <span class="s">"alice.blog/post"</span>],185 <span class="c">// optional tags</span>186 [<span class="s">"published_at"</span>, <span class="s">"1738863000"</span>],187 [<span class="s">"title"</span>, <span class="s">"Blog insights by Alice"</span>],188 [<span class="s">"t"</span>, <span class="s">"post"</span>],189 [<span class="s">"t"</span>, <span class="s">"insight"</span>]190 ],191 <span class="k">"content"</span>: <span class="s">"A marvelous insight by Alice about the nature of blogs and posts."</span>,192 <span class="k">"sig"</span>: <span class="s">"36d34e6448fe0223e9999361c39c492a208bc423d2fcdfc2a3404e04df7c22dc65bbbd62dbe8a4373c62e4d29aac285b5aa4bb9b4b8053bd6207a8b45fbd0c98"</span>193}</pre>194 </div>195 <p>A reader now queries the relay for every bookmark of that page. Later, Alice edits her description. She republishes with the same <code>d</code> value, and the relay replaces the old event.</p>196 <div class="crt">197 <div class="titlebar">Session transcript - wss://relay.example.com</div>198<pre><span class="c">-- Alice publishes the bookmark --</span>199<span class="send">→ ["EVENT", {"kind":39701, "id":"d7a92714…", "tags":[["d","alice.blog/post"], …], …}]</span>200<span class="recv">← ["OK", "d7a92714…", true, ""]</span>201202<span class="c">-- a reader looks the page up by its d value --</span>203<span class="send">→ ["REQ", "bm", {"kinds":[39701], "#d":["alice.blog/post"]}]</span>204<span class="recv">← ["EVENT", "bm", {"kind":39701, "pubkey":"2729620d…", "content":"A marvelous insight…", …}]</span>205<span class="recv">← ["EOSE", "bm"]</span>206207<span class="c">-- Alice edits: same d value, newer created_at --</span>208<span class="send">→ ["EVENT", {"kind":39701, "id":"4c01afe2…", "created_at":1738900000,209 "tags":[["d","alice.blog/post"], ["published_at","1738863000"], …],210 "content":"Updated notes on Alice's post.", …}]</span>211<span class="recv">← ["OK", "4c01afe2…", true, ""]</span> <span class="c">// relay now serves only this version</span></pre>212 </div>213214 <h2 class="bar" id="history"><span class="num">7</span> Version History</h2>215 <p>NIP-B0 is young and small. Its one substantive revision fixed how schemes are handled in the <code>d</code> value. Notable changes, newest first:</p>216 <ul class="patchnotes">217 <li><span class="ver">2026</span><span class="when">2026-07</span>Fixed the URI scheme ambiguity: only the <code>https</code> scheme is omitted from the <code>d</code> value; other schemes stay verbatim. A misapplied suggestion from the same change was corrected the same day.</li>218 <li class="minor"><span class="ver">2025-26</span><span class="when">2025-08</span>Wording cleanup and code-fence relabeling passes.</li>219 <li><span class="ver">2025</span><span class="when">2025-04</span>Renamed to the uppercase <code>B0.md</code> filename shortly after merge.</li>220 <li><span class="ver">Origin</span><span class="when">2025-04-24</span>Sebastian Hagens proposed <code>kind:39701</code> web bookmarks in PR #1849.</li>221 </ul>222223 <div class="credits">224 <h3 class="cardhead">Original Proposal - Credits</h3>225 <table>226 <tr><td>Author</td><td>Sebastian Hagens</td></tr>227 <tr><td>First commit</td><td>2025-04-24 — “adding more info / requirements for using kind 39701 for web bookmarks (NIP-B0)” (<a href="https://github.com/nostr-protocol/nips/pull/1849">PR #1849</a>)</td></tr>228 <tr><td>Status</td><td>draft - optional</td></tr>229 <tr><td>Source</td><td><a href="https://github.com/nostr-protocol/nips/blob/master/B0.md">B0.md on GitHub</a> - <a href="https://github.com/nostr-protocol/nips/commits/master/B0.md">full change history</a></td></tr>230 </table>231 </div>232233 <h2 class="bar"><span class="num">8</span> See Also</h2>234 <ul>235 <li><a href="01.html">NIP-01</a> — addressable events, the <code>d</code> tag, and <code>#d</code> filters that this NIP relies on.</li>236 <li><a href="22.html">NIP-22</a> — <code>kind:1111</code> comments; the mandatory reply format for bookmarks.</li>237 <li><a href="51.html">NIP-51</a> — bookmark <em>lists</em> (<code>kind:10003</code>); many references in one event, instead of one event per URI.</li>238 <li><a href="73.html">NIP-73</a> — external content IDs; another way to reference web URLs from events.</li>239 </ul>240 </div>241242 <aside>243 <div class="cartridge">244 <div class="inner">245 <h3 class="cardhead">Spec Card</h3>246 <div class="lights"><span class="led on"></span><span class="led on"></span><span class="led on"></span></div>247 <dl>248 <dt>Status</dt><dd><span class="chip draft">draft</span><span class="chip">optional</span></dd>249 <dt>Defines</dt><dd>kind 39701 - d/t/published_at/title tags</dd>250 <dt>Kind</dt><dd>39701 (addressable)</dd>251 <dt>Requires</dt><dd><a href="01.html">NIP-01</a> - <a href="22.html">NIP-22</a> for comments</dd>252 <dt>Transport</dt><dd>standard events - no extra messages</dd>253 <dt>First commit</dt><dd>2025-04-24</dd>254 <dt>Last updated</dt><dd>2026-07-31</dd>255 </dl>256 </div>257 </div>258 </aside>259 </main>260261 <nav class="navbtns">262 <a href="a4.html">◀ NIP-A4: Public Messages</a>263 <a href="b7.html">NIP-B7: Blossom media ▶</a>264 </nav>265266 <footer class="pagefoot">267 <a href="../index.html">Nostr Protocol Manual</a>268 <span class="pageno">NIP B0 / F4</span>269 </footer>270</div>271272<script src="../assets/webmcp.js" defer></script>273</body>274</html>