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-02 - Follow List — Nostr Instruction Manual</title>7<meta name="description" content="NIP-02: the follow list event. Kind 3, the p tag, petnames, replace-on-publish behavior, and how clients build a social graph.">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 02 - Social</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="02">02</div>48 <div class="titles">49 <div class="kicker">Nostr Implementation Possibility - Hex № 02</div>50 <h1>Follow List</h1>51 <p class="sub">One event that lists every profile a user follows. A new list replaces the old one, so the relay always holds the latest social graph.</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 client needs a way to know who a user follows. NIP-02 defines one <strong>kind 3</strong> event for this job: the <strong>follow list</strong>.</p>60 <p>The follow list holds one <a href="01.html#tags">p tag</a> for each followed profile. A user publishes a new follow list every time their follows change. The newest kind-3 event replaces every older one from the same <code>pubkey</code>, because kind 3 is a <a href="01.html#kinds">replaceable</a> kind under <a href="01.html">NIP-01</a>.</p>61 <p>Clients use the follow list to build a feed, back up a social graph, suggest new profiles to follow, share known relays, and build local "petname" tables. This NIP is marked <code>final</code> and <code>optional</code>: its wire format will not change, but a client does not have to implement it.</p>6263 <div class="box hint">64 <span class="tag">Hint!</span>65 <p>NIP-02 was formerly named "Contact List and Petnames" and its kind-3 event was called a "contact list". Both names now mean the same event. See §6 History.</p>66 </div>6768 <h2 class="bar" id="spec"><span class="num">2</span> The Follow List Event</h2>69 <p>A follow list is an event with <code>"kind": 3</code>. It contains one <code>p</code> tag for every followed or known profile. The <code>content</code> field is not used; by convention, clients set it to an empty string.</p>7071 <div class="crt">72 <div class="titlebar">p tag - full form</div>73<pre>[<span class="s">"p"</span>, <span class="c"><32-byte hex pubkey></span>, <span class="c"><main relay URL, or "" ></span>, <span class="c"><petname, or "" ></span>]</pre>74 </div>7576 <div class="tscroll"><table class="ref">77 <caption>p tag fields</caption>78 <tr><th>Position</th><th>Field</th><th>Rule</th></tr>79 <tr><td class="btn">0</td><td>tag name</td><td>Always the literal string <code>"p"</code>.</td></tr>80 <tr><td class="btn">1</td><td>pubkey</td><td>The 32-byte hex public key of the followed profile. Required.</td></tr>81 <tr><td class="btn">2</td><td>relay URL</td><td>A relay where events from that key can be found. Set to an empty string if not needed.</td></tr>82 <tr><td class="btn">3</td><td>petname</td><td>A local nickname for that profile. Set to an empty string, or leave it out, if not needed.</td></tr>83 </table></div>8485 <figure class="diagram">86 <div class="frame">87 <svg viewBox="0 0 560 120" role="img" aria-label="Anatomy of a p tag: tag name, pubkey, relay URL, petname">88 <rect class="d-actor" x="10" y="35" width="60" height="50" rx="8"/>89 <text class="d-actor-label" x="40" y="57" text-anchor="middle">p</text>90 <text class="d-note" x="40" y="74" text-anchor="middle">tag name</text>91 <rect class="d-actor" x="100" y="35" width="180" height="50" rx="8"/>92 <text class="d-actor-label" x="190" y="57" text-anchor="middle">pubkey</text>93 <text class="d-note" x="190" y="74" text-anchor="middle">64-char hex, required</text>94 <rect class="d-actor" x="310" y="35" width="140" height="50" rx="8"/>95 <text class="d-actor-label" x="380" y="57" text-anchor="middle">relay URL</text>96 <text class="d-note" x="380" y="74" text-anchor="middle">optional, "" allowed</text>97 <rect class="d-actor" x="470" y="35" width="80" height="50" rx="8"/>98 <text class="d-actor-label" x="510" y="57" text-anchor="middle">petname</text>99 <text class="d-note" x="510" y="74" text-anchor="middle">optional</text>100 <path class="d-msg d-flow" d="M72,60 L97,60"/>101 <path class="d-msg d-flow" d="M282,60 L307,60"/>102 <path class="d-msg d-flow" d="M452,60 L467,60"/>103 </svg>104 </div>105 <figcaption>Fig. 2-1 — <b>p tag anatomy.</b> Only the tag name and the pubkey are required. The relay URL and petname may be empty strings.</figcaption>106 </figure>107108 <div class="crt">109 <div class="titlebar">Example - kind 3 follow list</div>110<pre>{111 <span class="k">"kind"</span>: <span class="c">3</span>,112 <span class="k">"tags"</span>: [113 [<span class="s">"p"</span>, <span class="s">"91cf9..4e5ca"</span>, <span class="s">"wss://alicerelay.com/"</span>, <span class="s">"alice"</span>],114 [<span class="s">"p"</span>, <span class="s">"14aeb..8dad4"</span>, <span class="s">"wss://bobrelay.com/nostr"</span>, <span class="s">"bob"</span>],115 [<span class="s">"p"</span>, <span class="s">"612ae..e610f"</span>, <span class="s">"ws://carolrelay.com/ws"</span>, <span class="s">"carol"</span>]116 ],117 <span class="k">"content"</span>: <span class="s">""</span>,118 <span class="c">// id, pubkey, created_at, sig — see NIP-01</span>119}</pre>120 </div>121122 <h2 class="bar" id="replace"><span class="num">3</span> Replacing and Updating a Follow List</h2>123 <p>Every new follow list overwrites the past ones. A published follow list must contain the full set of follows, not just the change. Relays and clients should delete past follow lists as soon as they receive a new one, because kind 3 is a replaceable kind: a relay keeps only the latest event for each <code>pubkey</code> + <code>kind</code> pair.</p>124 <p>When a user adds new follows to an existing list, clients should append the new <code>p</code> tags to the end of the list. This keeps the list in chronological order, oldest follow first.</p>125126 <figure class="diagram">127 <div class="frame">128 <svg viewBox="0 0 560 190" role="img" aria-label="Two kind-3 events reach a relay; the relay keeps only the newer one">129 <rect class="d-actor" x="10" y="20" width="150" height="50" rx="8"/>130 <text class="d-actor-label" x="85" y="42" text-anchor="middle">kind:3 event</text>131 <text class="d-note" x="85" y="59" text-anchor="middle">created_at 1000 (v1)</text>132 <rect class="d-actor" x="10" y="120" width="150" height="50" rx="8"/>133 <text class="d-actor-label" x="85" y="142" text-anchor="middle">kind:3 event</text>134 <text class="d-note" x="85" y="159" text-anchor="middle">created_at 2000 (v2)</text>135 <rect class="d-actor" x="230" y="70" width="110" height="50" rx="8"/>136 <text class="d-actor-label" x="285" y="99" text-anchor="middle">Relay</text>137 <rect class="d-actor" x="410" y="70" width="140" height="50" rx="8"/>138 <text class="d-actor-label" x="480" y="92" text-anchor="middle">Stored</text>139 <text class="d-note" x="480" y="109" text-anchor="middle">only v2 kept</text>140 <path class="d-msg" d="M162,45 C200,45 200,80 228,88"/>141 <path class="d-msg d-flow" d="M162,145 C200,145 200,110 228,102"/>142 <path class="d-msg blue d-flow" d="M342,95 L408,95"/>143 <text class="d-label" x="195" y="68" text-anchor="middle">v1 (older)</text>144 <text class="d-label" x="195" y="130" text-anchor="middle">v2 (newer)</text>145 </svg>146 </div>147 <figcaption>Fig. 2-2 — <b>Replace-on-publish.</b> The relay keeps only the newest kind-3 event per pubkey. Older follow lists are discarded.</figcaption>148 </figure>149150 <h2 class="bar" id="uses"><span class="num">4</span> Uses</h2>151152 <h3>Follow list backup</h3>153 <p>A relay may store events for a long time. A user can rely on their kind-3 event to back up their follow list. They can recover the list on a new device by fetching it from any relay that has it.</p>154155 <h3>Profile discovery and context augmentation</h3>156 <p>A client may read a kind-3 event to show which profiles a user follows. A client may also compare follow lists between users, and suggest new profiles to follow based on shared follows. A client may show this data in other contexts too.</p>157158 <h3>Relay sharing</h3>159 <p>A client may publish a follow list where each <code>p</code> tag names a good relay for that followed profile. Other clients can read these relay URLs and update their own relay lists. This spreads relay knowledge between clients and increases censorship resistance.</p>160161 <h3>Petname scheme</h3>162 <p>A client can use follow lists from other users to build a local <a href="http://www.skyhunter.com/marcs/petnames/IntroPetNames.html">petname</a> table. A petname is a local nickname a user picks for a pubkey. This removes the need for a single global human-readable name.</p>163 <p>Petnames chain together. If your follow list names a pubkey "erin", and erin's own follow list names another pubkey "david", a client may show that second pubkey as "david.erin" to you. One more hop gives "frank.david.erin".</p>164165 <div class="crt">166 <div class="titlebar">Example - petname chain</div>167<pre><span class="c">-- your follow list --</span>168[<span class="s">"p"</span>, <span class="s">"21df6d143fb96c2ec9d63726bf9edc71"</span>, <span class="s">""</span>, <span class="s">"erin"</span>]169170<span class="c">-- erin's follow list --</span>171[<span class="s">"p"</span>, <span class="s">"a8bb3d884d5d90b413d9891fe4c4e46d"</span>, <span class="s">""</span>, <span class="s">"david"</span>]172173<span class="c">-- david's follow list --</span>174[<span class="s">"p"</span>, <span class="s">"f57f54057d2a7af0efecc8b0b66f5708"</span>, <span class="s">""</span>, <span class="s">"frank"</span>]175176<span class="c">-- your client shows --</span>17721df6d14… → <span class="s">"erin"</span>178a8bb3d88… → <span class="s">"david.erin"</span>179f57f5405… → <span class="s">"frank.david.erin"</span></pre>180 </div>181182 <figure class="diagram">183 <div class="frame">184 <svg viewBox="0 0 620 160" role="img" aria-label="Petname chain: You follow erin, who follows david, who follows frank">185 <rect class="d-actor" x="10" y="55" width="100" height="50" rx="8"/>186 <text class="d-actor-label" x="60" y="84" text-anchor="middle">You</text>187 <rect class="d-actor" x="150" y="55" width="130" height="50" rx="8"/>188 <text class="d-actor-label" x="215" y="80" text-anchor="middle">erin</text>189 <text class="d-note" x="215" y="97" text-anchor="middle">21df6d1…</text>190 <rect class="d-actor" x="320" y="55" width="140" height="50" rx="8"/>191 <text class="d-actor-label" x="390" y="80" text-anchor="middle">david.erin</text>192 <text class="d-note" x="390" y="97" text-anchor="middle">a8bb3d8…</text>193 <rect class="d-actor" x="500" y="55" width="110" height="50" rx="8"/>194 <text class="d-actor-label" x="555" y="80" text-anchor="middle">frank.david.erin</text>195 <text class="d-note" x="555" y="97" text-anchor="middle">f57f540…</text>196 <path class="d-msg d-flow" d="M112,80 L147,80"/>197 <path class="d-msg d-flow" d="M282,80 L317,80"/>198 <path class="d-msg d-flow" d="M462,80 L497,80"/>199 <text class="d-label" x="130" y="73" text-anchor="middle">follows</text>200 <text class="d-label" x="300" y="73" text-anchor="middle">follows</text>201 <text class="d-label" x="480" y="73" text-anchor="middle">follows</text>202 </svg>203 </div>204 <figcaption>Fig. 2-3 — <b>Petname chain.</b> Each hop away from you adds one more name segment, built from follow lists your client already has.</figcaption>205 </figure>206207 <div class="box tech">208 <span class="tag">Tech Note</span>209 <p>The source spec defines a pubkey as a "32-byte hex key" (64 hex characters). The petname-scheme example pubkeys, such as <code>21df6d143fb96c2ec9d63726bf9edc71</code>, are only 32 hex characters (16 bytes) and are not truncated with an ellipsis like the earlier example keys. They cannot be real pubkeys as written. Treat them as illustrative placeholders only, not as a literal wire example.</p>210 </div>211212 <h2 class="bar" id="examples"><span class="num">5</span> Worked Example</h2>213 <p>The session below shows Bob publishing a follow list, then Alice fetching it. Orange lines go to the relay. Blue lines come from the relay.</p>214 <div class="crt">215 <div class="titlebar">Session transcript - wss://relay.example.com</div>216<pre><span class="c">-- Bob publishes his follow list --</span>217<span class="send">→ ["EVENT", {"id":"7c2f19ab…","pubkey":"14aeb..8dad4","created_at":1749762600,218 "kind":3,219 "tags":[220 ["p","91cf9..4e5ca","wss://alicerelay.com/","alice"],221 ["p","612ae..e610f","ws://carolrelay.com/ws","carol"]222 ],223 "content":"","sig":"9a31dd42…"}]</span>224<span class="recv">← ["OK", "7c2f19ab…", true, ""]</span>225226<span class="c">-- Alice requests Bob's follow list --</span>227<span class="send">→ ["REQ", "bob-follows", {"kinds":[3], "authors":["14aeb..8dad4"]}]</span>228<span class="recv">← ["EVENT", "bob-follows", {"id":"7c2f19ab…", "kind":3, "tags":[…], "content":"", …}]</span>229<span class="recv">← ["EOSE", "bob-follows"]</span>230<span class="send">→ ["CLOSE", "bob-follows"]</span>231232<span class="c">-- later, Bob adds one more follow and republishes --</span>233<span class="send">→ ["EVENT", {"id":"c04e88de…","pubkey":"14aeb..8dad4","created_at":1749849000,234 "kind":3,235 "tags":[236 ["p","91cf9..4e5ca","wss://alicerelay.com/","alice"],237 ["p","612ae..e610f","ws://carolrelay.com/ws","carol"],238 ["p","f57f540..5708","","frank"]239 ],240 "content":"","sig":"2be671fa…"}]</span>241<span class="recv">← ["OK", "c04e88de…", true, ""]</span>242<span class="c">-- the relay now discards the 7c2f19ab… event; c04e88de… is Bob's only follow list --</span></pre>243 </div>244245 <h2 class="bar" id="history"><span class="num">6</span> Version History</h2>246 <p>NIP-02 has kept the same kind-3 wire format since 2022. Changes have been renames and clarifications. Notable changes, newest first:</p>247 <ul class="patchnotes">248 <li class="minor"><span class="ver">2026</span><span class="when">2026-06</span>Cosmetic: the example code fence label changed from <code>jsonc</code> to <code>yaml</code>; no wire-format change.</li>249 <li><span class="ver">2024</span><span class="when">2024-01</span>Clarified that clients should append new follows to the end of the list, keeping chronological order.</li>250 <li class="minor"><span class="ver">2024</span><span class="when">2024-02 - 2024-09</span>Reworded the content rule to "not used" (from "can be anything, ignored"); minor JSON-comment formatting.</li>251 <li><span class="ver">2023</span><span class="when">2023-12</span>Renamed the NIP from "Contact List and Petnames" to "Follow List"; the kind-3 event is now called a follow list, not a contact list.</li>252 <li class="minor"><span class="ver">2023</span><span class="when">2023-11</span>Removed all per-NIP author bylines repository-wide, including <code>author:fiatjaf</code> and <code>author:arcbtc</code> on this page.</li>253 <li class="minor"><span class="ver">2023</span><span class="when">2023-01 - 2023-03</span>Typo fixes: spelling of "censorship-resistance" and a missing closing brace in the example event.</li>254 <li><span class="ver">2022</span><span class="when">2022-11</span>Status changed from <code>draft</code> to <code>final</code>: the wire format was declared stable.</li>255 <li><span class="ver">2022</span><span class="when">2022-06</span>Disallowed <code>null</code> placeholders in tag entries. Relay URL and petname must be an empty string, not <code>null</code>, when absent.</li>256 <li><span class="ver">Origin</span><span class="when">2022-05-01</span>fiatjaf published the spec as "Contact List and Petnames", co-credited with arcbtc, in the migration to the <code>nostr-protocol/nips</code> repository.</li>257 </ul>258259 <div class="credits">260 <h3 class="cardhead">Original Proposal - Credits</h3>261 <table>262 <tr><td>Author</td><td>fiatjaf (co-credited with arcbtc in the original byline)</td></tr>263 <tr><td>First commit</td><td>2022-05-01 — "migrate nips from main nostr repo."</td></tr>264 <tr><td>Status</td><td>final - optional — stable wire format, implementation not required</td></tr>265 <tr><td>Source</td><td><a href="https://github.com/nostr-protocol/nips/blob/master/02.md">02.md on GitHub</a> - <a href="https://github.com/nostr-protocol/nips/commits/master/02.md">full change history</a></td></tr>266 </table>267 </div>268269 <h2 class="bar"><span class="num">7</span> See Also</h2>270 <ul>271 <li><a href="01.html">NIP-01</a> — defines the event object, the <code>p</code> tag's basic form, and the replaceable-kind rule that this NIP depends on.</li>272 <li><a href="51.html">NIP-51</a> — generic lists. Follow lists are a fixed, single-purpose case of the more general list format.</li>273 <li><a href="65.html">NIP-65</a> — a dedicated relay list event, a more structured alternative to the relay-sharing use of the <code>p</code> tag here.</li>274 <li><a href="19.html">NIP-19</a> — bech32 <code>npub</code> encoding for the raw hex pubkeys stored in <code>p</code> tags.</li>275 <li><a href="24.html">NIP-24</a> — extra profile metadata a client can show alongside a followed pubkey.</li>276 </ul>277 </div>278279 <aside>280 <div class="cartridge">281 <div class="inner">282 <h3 class="cardhead">Spec Card</h3>283 <div class="lights"><span class="led on"></span><span class="led on"></span><span class="led on"></span></div>284 <dl>285 <dt>Status</dt><dd><span class="chip final">final</span><span class="chip">optional</span></dd>286 <dt>Defines</dt><dd>kind 3 - follow list - p tag (4-element form)</dd>287 <dt>Kind</dt><dd>3 (replaceable)</dd>288 <dt>Requires</dt><dd><a href="01.html">NIP-01</a> — event format, replaceable kinds</dd>289 <dt>Content field</dt><dd>not used</dd>290 <dt>First commit</dt><dd>2022-05-01</dd>291 <dt>Last updated</dt><dd>2026-06-13</dd>292 </dl>293 </div>294 </div>295 </aside>296 </main>297298 <nav class="navbtns">299 <a href="01.html">◀ NIP-01: Basic Protocol Flow</a>300 <a href="03.html">NIP-03: OpenTimestamps Attestations for Events ▶</a>301 </nav>302303 <footer class="pagefoot">304 <a href="../index.html">Nostr Protocol Manual</a>305 <span class="pageno">NIP 02 / F4</span>306 </footer>307</div>308309<script src="../assets/webmcp.js" defer></script>310</body>311</html>