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-35 - Torrents — Nostr Instruction Manual</title>7<meta name="description" content="NIP-35: torrent index events. Kind 2003 stores the info hash, file list, and trackers needed to build a magnet link. Kind 2004 adds comments.">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 35 - Media</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="35">35</div>48 <div class="titles">49 <div class="kicker">Nostr Implementation Possibility - Hex № 35</div>50 <h1>Torrents</h1>51 <p class="sub">A torrent index on relays: kind 2003 carries the info hash, file list, and trackers that a client needs to build a magnet link.</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>BitTorrent indexes are usually websites. A website can go down or get seized. This NIP moves the index to Nostr. It defines <strong>kind 2003</strong>, a torrent index event.</p>60 <p>A kind-2003 event holds just enough information to search for content and to construct a magnet link. No torrent files exist on Nostr. The relay stores only metadata. Download traffic stays in the BitTorrent swarm.</p>61 <p>The NIP also defines <strong>kind 2004</strong>, a comment on a torrent event. Both kinds sit in the regular event range of <a href="01.html">NIP-01</a>, so relays store all of them.</p>6263 <div class="box hint">64 <span class="tag">Hint!</span>65 <p>A magnet link has the form <code>magnet:?xt=urn:btih:HASH</code>. The hash is the V1 BitTorrent info hash. That single value identifies the torrent in the swarm. Everything else in the event is search metadata.</p>66 </div>6768 <figure class="diagram">69 <div class="frame">70 <svg viewBox="0 0 560 200" role="img" aria-label="Publisher sends a kind 2003 index event to a relay; a searcher queries the relay, builds a magnet link, and downloads from the BitTorrent swarm">71 <rect class="d-actor" x="10" y="20" width="110" height="50" rx="8"/>72 <text class="d-actor-label" x="65" y="42" text-anchor="middle">Publisher</text>73 <text class="d-note" x="65" y="59" text-anchor="middle">client</text>74 <rect class="d-actor" x="225" y="20" width="110" height="50" rx="8"/>75 <text class="d-actor-label" x="280" y="49" text-anchor="middle">Relay</text>76 <rect class="d-actor" x="440" y="20" width="110" height="50" rx="8"/>77 <text class="d-actor-label" x="495" y="42" text-anchor="middle">Searcher</text>78 <text class="d-note" x="495" y="59" text-anchor="middle">client</text>79 <rect class="d-actor" x="440" y="130" width="110" height="50" rx="8"/>80 <text class="d-actor-label" x="495" y="152" text-anchor="middle">Swarm</text>81 <text class="d-note" x="495" y="169" text-anchor="middle">BitTorrent</text>82 <path class="d-msg d-flow" d="M122,45 L222,45"/>83 <text class="d-label" x="172" y="36" text-anchor="middle">kind 2003</text>84 <path class="d-msg blue d-flow" d="M337,45 L437,45"/>85 <text class="d-label" x="387" y="36" text-anchor="middle">REQ / EVENT</text>86 <path class="d-msg d-flow" d="M495,72 L495,127"/>87 <text class="d-label" x="480" y="103" text-anchor="end">magnet:?xt=…</text>88 <circle r="4" fill="#f26a00">89 <animateMotion dur="2.6s" repeatCount="indefinite" path="M122,45 L222,45"/>90 </circle>91 <circle r="4" fill="#2e5f9e">92 <animateMotion dur="2.6s" begin="1.3s" repeatCount="indefinite" path="M337,45 L437,45"/>93 </circle>94 </svg>95 </div>96 <figcaption>Fig. 35-1 — <b>Index on Nostr, data in the swarm.</b> The relay never sees torrent content, only the metadata event.</figcaption>97 </figure>9899 <h2 class="bar" id="spec"><span class="num">2</span> The Torrent Event (Kind 2003)</h2>100 <p>A torrent index event is a regular event with <code>kind</code> 2003. The <code>content</code> field holds a long, pre-formatted description. The tags hold the machine-readable index data:</p>101102 <div class="crt">103 <div class="titlebar">Wire format - kind 2003 torrent event</div>104<pre>{105 <span class="k">"kind"</span>: 2003,106 <span class="k">"content"</span>: <span class="c"><long description, pre-formatted></span>,107 <span class="k">"tags"</span>: [108 [<span class="s">"title"</span>, <span class="c"><torrent title></span>],109 [<span class="s">"x"</span>, <span class="c"><V1 BitTorrent info hash></span>],110 [<span class="s">"file"</span>, <span class="c"><file path></span>, <span class="c"><file size in bytes></span>],111 [<span class="s">"tracker"</span>, <span class="c"><tracker URL, optional></span>],112 [<span class="s">"i"</span>, <span class="c"><prefix>:<external reference></span>],113 [<span class="s">"t"</span>, <span class="c"><category label></span>]114 ]115}</pre>116 </div>117118 <div class="tscroll"><table class="ref">119 <caption>Tag reference - kind 2003</caption>120 <tr><th>Tag</th><th>Value</th><th>Rule</th></tr>121 <tr><td class="btn">x</td><td>V1 BitTorrent info hash</td><td>The hash from the magnet link <code>magnet:?xt=urn:btih:HASH</code> (BEP-53). Single-letter, so relays index it per <a href="01.html">NIP-01</a>.</td></tr>122 <tr><td class="btn">file</td><td>full file path</td><td>One file entry inside the torrent, with its full path, for example <code>info/example.txt</code>. The second value is the file size in bytes. Repeat the tag for each file.</td></tr>123 <tr><td class="btn">tracker</td><td>tracker URL</td><td>Optional. A tracker to use for this torrent. Repeat the tag for each tracker.</td></tr>124 <tr><td class="btn">title</td><td>torrent title</td><td>The display name of the torrent.</td></tr>125 <tr><td class="btn">i</td><td>prefixed reference</td><td>A reference to an external database. See §3.</td></tr>126 <tr><td class="btn">t</td><td>category label</td><td>A general category such as <code>movie</code>, <code>tv</code>, <code>HD</code>, or <code>UHD</code>. You SHOULD include a few of these to make the torrent searchable by category.</td></tr>127 </table></div>128129 <div class="box tech">130 <span class="tag">Tech Note</span>131 <p>The source spec is loose in two places. The <code>title</code> tag and the file-size value appear only in the example JSON, not in the tag list. And the example JSON in the source carries a trailing comma after the last tag, so it is not valid JSON as printed. The example in §5 fixes the comma.</p>132 </div>133134 <h2 class="bar" id="prefixes"><span class="num">3</span> External References: the i Tag</h2>135 <p>An <code>i</code> tag labels the content with a reference into an external database. The value is a prefix, then <code>:</code>, then the reference, for example <code>["i", "imdb:1234"]</code>. The spec defines seven prefixes:</p>136137 <div class="tscroll"><table class="ref">138 <caption>Tag prefixes for i tags</caption>139 <tr><th>Prefix</th><th>Database</th><th>Rule</th></tr>140 <tr><td class="btn">tcat</td><td>text category path</td><td>A comma-separated category path, for example <code>["i", "tcat:video,movie,4k"]</code>. It should match the <code>newznab</code> category in a best-effort way.</td></tr>141 <tr><td class="btn">newznab</td><td>newznab</td><td>The numeric category ID from the newznab standard category list.</td></tr>142 <tr><td class="btn">tmdb</td><td>The Movie Database</td><td>A themoviedb.org ID.</td></tr>143 <tr><td class="btn">ttvdb</td><td>TheTVDB</td><td>A thetvdb.com ID.</td></tr>144 <tr><td class="btn">imdb</td><td>IMDB</td><td>An imdb.com ID.</td></tr>145 <tr><td class="btn">mal</td><td>MyAnimeList</td><td>A myanimelist.net ID.</td></tr>146 <tr><td class="btn">anilist</td><td>AniList</td><td>An anilist.co ID.</td></tr>147 </table></div>148149 <h3>Second-level prefixes</h3>150 <p>Some databases hold several media types under one ID space. For those, include a second-level prefix that names the media type:</p>151 <div class="crt">152 <div class="titlebar">Second-level prefix mapping</div>153<pre><span class="k">tmdb:movie:693134</span> <span class="c">→ themoviedb.org/movie/693134</span>154<span class="k">ttvdb:movie:290272</span> <span class="c">→ thetvdb.com/movies/dune-part-two</span>155<span class="k">mal:anime:9253</span> <span class="c">→ myanimelist.net/anime/9253</span>156<span class="k">mal:manga:17517</span> <span class="c">→ myanimelist.net/manga/17517</span></pre>157 </div>158 <div class="box warn">159 <span class="tag">Warning!</span>160 <p>The URL mapping is not always direct. The <code>ttvdb</code> example above maps to a slug, not to the raw ID. Full URL mapping is out of scope for this NIP. The table is only a guide, so implementers have enough information to map the URL if they wish.</p>161 </div>162 <div class="box tech">163 <span class="tag">Tech Note</span>164 <p>The prefix intro in the source shows <code>imdb:1234</code>, but the full example uses <code>imdb:tt15239678</code>. The spec never states whether the IMDB reference carries the <code>tt</code> prefix. Implementations should accept both forms when searching.</p>165 </div>166167 <h2 class="bar" id="comments"><span class="num">4</span> Torrent Comments (Kind 2004)</h2>168 <p>A torrent comment is a <strong>kind 2004</strong> event. It replies to a torrent event. It works exactly like a <code>kind 1</code> text note. Follow <a href="10.html">NIP-10</a> for its <code>e</code> and <code>p</code> tagging.</p>169170 <figure class="diagram">171 <div class="frame">172 <svg viewBox="0 0 560 150" role="img" aria-label="A kind 2004 comment points at a kind 2003 torrent event with a NIP-10 e tag, and at the author with a p tag">173 <rect class="d-actor" x="30" y="45" width="150" height="56" rx="8"/>174 <text class="d-actor-label" x="105" y="70" text-anchor="middle">kind 2003</text>175 <text class="d-note" x="105" y="88" text-anchor="middle">torrent index</text>176 <rect class="d-actor" x="380" y="45" width="150" height="56" rx="8"/>177 <text class="d-actor-label" x="455" y="70" text-anchor="middle">kind 2004</text>178 <text class="d-note" x="455" y="88" text-anchor="middle">comment</text>179 <path class="d-msg blue d-flow" d="M377,73 L184,73"/>180 <text class="d-label" x="280" y="64" text-anchor="middle">["e", <torrent id>]</text>181 <text class="d-note" x="280" y="122" text-anchor="middle">Threading rules come from NIP-10, the same as kind-1 replies.</text>182 </svg>183 </div>184 <figcaption>Fig. 35-2 — <b>Comment threading.</b> A kind-2004 comment tags the torrent event it replies to.</figcaption>185 </figure>186187 <h2 class="bar" id="examples"><span class="num">5</span> Worked Example</h2>188 <p>A publisher indexes a 4K movie release. The event lists two files, two trackers, five external references, and two category labels:</p>189 <div class="crt">190 <div class="titlebar">Example - kind 2003 torrent index</div>191<pre>{192 <span class="k">"kind"</span>: 2003,193 <span class="k">"content"</span>: <span class="s">"Dune: Part Two (2024) 2160p UHD remux.\nAudio: TrueHD 7.1."</span>,194 <span class="k">"tags"</span>: [195 [<span class="s">"title"</span>, <span class="s">"Dune Part Two 2160p"</span>],196 [<span class="s">"x"</span>, <span class="s">"2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c"</span>],197 [<span class="s">"file"</span>, <span class="s">"Dune.Part.Two.2160p/movie.mkv"</span>, <span class="s">"58291736452"</span>],198 [<span class="s">"file"</span>, <span class="s">"Dune.Part.Two.2160p/info/example.txt"</span>, <span class="s">"1024"</span>],199 [<span class="s">"tracker"</span>, <span class="s">"udp://mytacker.com:1337"</span>],200 [<span class="s">"tracker"</span>, <span class="s">"http://1337-tracker.net/announce"</span>],201 [<span class="s">"i"</span>, <span class="s">"tcat:video,movie,4k"</span>],202 [<span class="s">"i"</span>, <span class="s">"newznab:2045"</span>],203 [<span class="s">"i"</span>, <span class="s">"imdb:tt15239678"</span>],204 [<span class="s">"i"</span>, <span class="s">"tmdb:movie:693134"</span>],205 [<span class="s">"i"</span>, <span class="s">"ttvdb:movie:290272"</span>],206 [<span class="s">"t"</span>, <span class="s">"movie"</span>],207 [<span class="s">"t"</span>, <span class="s">"4k"</span>]208 ]209}</pre>210 </div>211 <p>A searcher finds the event by category, reads the <code>x</code> tag, and builds the magnet link. The <code>x</code>, <code>i</code>, and <code>t</code> tags are single-letter, so <a href="01.html">NIP-01</a> relays index them for filter queries:</p>212 <div class="crt">213 <div class="titlebar">Session transcript - wss://relay.example.com</div>214<pre><span class="c">-- search 4k movies --</span>215<span class="send">→ ["REQ", "tor", {"kinds":[2003], "#t":["4k"], "limit":20}]</span>216<span class="recv">← ["EVENT", "tor", {"kind":2003, "tags":[…,["x","2b3c4d5e…0b1c"],…], …}]</span>217<span class="recv">← ["EOSE", "tor"]</span>218219<span class="c">-- look up one torrent by info hash --</span>220<span class="send">→ ["REQ", "hash", {"kinds":[2003], "#x":["2b3c4d5e…0b1c"]}]</span>221222<span class="c">-- client builds the magnet link from the x tag --</span>223<span class="c">magnet:?xt=urn:btih:2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c</span>224<span class="c"> &tr=udp://mytacker.com:1337&tr=http://1337-tracker.net/announce</span>225226<span class="c">-- a comment on the torrent (kind 2004, NIP-10 tags) --</span>227<span class="send">→ ["EVENT", {"kind":2004, "content":"Seeding. Thanks!",228 "tags":[["e","<torrent event id>","","root"],["p","<publisher pubkey>"]], …}]</span>229<span class="recv">← ["OK", "<comment id>", true, ""]</span></pre>230 </div>231232 <div class="box hint">233 <span class="tag">Hint!</span>234 <p>Working implementations to study: <code>dtan.xyz</code> (git.v0l.io/Kieran/dtan) and the torrents view in <code>nostrudel.ninja</code> (github.com/hzrd149/nostrudel).</p>235 </div>236237 <h2 class="bar" id="history"><span class="num">6</span> Version History</h2>238 <p>The number 35 has lived two lives. The original NIP-35, "User Discovery", merged into <a href="05.html">NIP-05</a> in 2023. kieran reused the free number for Torrents in 2024. Notable changes, newest first:</p>239 <ul class="patchnotes">240 <li class="minor"><span class="ver">2024</span><span class="when">2024-09</span>Formatting cleanup: header styles and JSON formatting normalized across the repo.</li>241 <li><span class="ver">2024</span><span class="when">2024-05</span>Tag keys updated: the index tags reached their current names.</li>242 <li><span class="ver">2024</span><span class="when">2024-04</span>Added kind-2004 comments. The info hash moved to the single-letter <code>x</code> tag so relays index it, mirroring NIP-94.</li>243 <li><span class="ver">2024</span><span class="when">2024-04-14</span>kieran published the Torrents spec, reusing the vacant number 35.</li>244 <li><span class="ver">2023</span><span class="when">2023-01</span>The previous occupant of this number, "User Discovery", merged into <a href="05.html">NIP-05</a>. The number became free.</li>245 <li><span class="ver">Origin</span><span class="when">2022-11-19</span>Michael Dilger created the file as NIP-35 "User Discovery" (#73) — an unrelated spec that only shares the number.</li>246 </ul>247248 <div class="box tech">249 <span class="tag">Tech Note</span>250 <p>Git history for <code>35.md</code> with rename detection drags in commits from "User Discovery" and from draft events (now <a href="37.html">NIP-37</a>). Only commits from 2024-04-14 onward describe the Torrents spec. The manifest "created" date, 2022-11-19, is the file's first commit, not the Torrents spec's.</p>251 </div>252253 <div class="credits">254 <h3 class="cardhead">Original Proposal - Credits</h3>255 <table>256 <tr><td>Author</td><td>kieran (Torrents spec; the 2022 file origin is the unrelated "User Discovery" by Michael Dilger)</td></tr>257 <tr><td>First commit</td><td>2024-04-14 — “torrents” (file path dates to 2022-11-19)</td></tr>258 <tr><td>Status</td><td>draft - optional — implement it only if your client indexes torrents</td></tr>259 <tr><td>Source</td><td><a href="https://github.com/nostr-protocol/nips/blob/master/35.md">35.md on GitHub</a> - <a href="https://github.com/nostr-protocol/nips/commits/master/35.md">full change history</a></td></tr>260 </table>261 </div>262263 <h2 class="bar"><span class="num">7</span> See Also</h2>264 <ul>265 <li><a href="01.html">NIP-01</a> — the event format, regular-event storage, and the single-letter tag index used by <code>x</code>, <code>i</code>, and <code>t</code> queries.</li>266 <li><a href="10.html">NIP-10</a> — the <code>e</code>/<code>p</code> threading rules that kind-2004 comments follow.</li>267 <li><a href="94.html">NIP-94</a> — file metadata events; the model for the indexed <code>x</code> info-hash tag.</li>268 <li><a href="05.html">NIP-05</a> — where the original NIP-35, "User Discovery", lives now.</li>269 </ul>270 </div>271272 <aside>273 <div class="cartridge">274 <div class="inner">275 <h3 class="cardhead">Spec Card</h3>276 <div class="lights"><span class="led on"></span><span class="led on"></span><span class="led on"></span></div>277 <dl>278 <dt>Status</dt><dd><span class="chip draft">draft</span><span class="chip">optional</span></dd>279 <dt>Defines</dt><dd>kind 2003 torrent index - kind 2004 comment - x/file/tracker/title tags - i prefixes</dd>280 <dt>Kinds</dt><dd>2003 - 2004 (regular)</dd>281 <dt>Requires</dt><dd><a href="01.html">NIP-01</a> - <a href="10.html">NIP-10</a></dd>282 <dt>Transport</dt><dd>magnet links - BitTorrent swarm (off-Nostr)</dd>283 <dt>First commit</dt><dd>2022-11-19 (Torrents: 2024-04-14)</dd>284 <dt>Last updated</dt><dd>2024-09-03</dd>285 </dl>286 </div>287 </div>288 </aside>289 </main>290291 <nav class="navbtns">292 <a href="34.html">◀ NIP-34: <code>git</code> stuff</a>293 <a href="36.html">NIP-36: Sensitive Content / Content Warning ▶</a>294 </nav>295296 <footer class="pagefoot">297 <a href="../index.html">Nostr Protocol Manual</a>298 <span class="pageno">NIP 35 / F4</span>299 </footer>300</div>301302<script src="../assets/webmcp.js" defer></script>303</body>304</html>