Chapter B7 - Media
B7
Nostr Implementation Possibility - Hex № B7

Blossom media

How clients use sha256-addressed Blossom servers to store media, and how they recover a file when its original URL dies.

1 Overview

Media links on Nostr rot. A note lives forever on relays, but the image it points to sits on one HTTP server. When that server goes away, the note shows a broken picture. This NIP fixes that.

Blossom is a set of standards for media servers. Each standard is called a BUD. A Blossom server stores files and addresses each file by its sha256 hash. The same file has the same address on every Blossom server. That makes every copy interchangeable.

This NIP tells Nostr clients how to use Blossom. Clients may use all the BUDs: upload files, manage their own files, and so on. Most importantly, clients SHOULD use BUD-03 to fetch each user's kind:10063 list of Blossom servers. With that list, a client can find a lost file on the user's other servers.

Hint!

Think of the sha256 hash as a serial number stamped on the file itself. The URL only tells you which shelf to check first. If the shelf is empty, ask the owner's kind:10063 list which other shelves hold the same serial number.

Dead URL …/<64-hex>.png kind 10063 server list Retry each server Verify sha256
Fig. B7-1 — Recovery pipeline. The hash in the URL is the key. The server list supplies fallback locations.

2 The Server List: kind 10063

Each user publishes one kind:10063 event. The event lists the Blossom servers that hold the user's files. Each server appears in one server tag. The content field stays empty. The list format comes from BUD-03; clients SHOULD fetch these lists as BUD-03 describes.

Wire format - kind 10063 server list
{
  "id": "e4bee088334cb5d38cff1616e964369c37b6081be997962ab289d6c671975d71",
  "pubkey": "781208004e09102d7da3b7345e64fd193cd1bc3fce8fdae6008d77f9cabcd036",
  "content": "",
  "kind": 10063,
  "created_at": 1708774162,
  "tags": [
    ["server", "https://blossom.self.hosted"],
    ["server", "https://cdn.blossom.cloud"]
  ],
  "sig": "cc5efa74f59e80622c77cacf4dd62076bcb7581b45e9acff471e7963a1f4d8b3406adab5ee1ac9673487480e57d20e523428e60ffcc7e7a904ac882cfccfc653"
}
Kind and tag reference
ItemValueRule
kind10063The user's Blossom server list. One list per user. The kind sits in the replaceable range of NIP-01, so relays keep only the latest event per pubkey.
server["server", <server URL>]One tag per Blossom server. The value is the server's base HTTPS URL.
content""Empty string. The tags carry all the data.
Tech Note

This NIP defines almost nothing itself. Kind 10063, the server tag, and the server HTTP API are all normative in the external Blossom BUD documents, not in the NIPs repository. The event shown above is the source's only example; treat BUD-03 as the authority if the two ever disagree.

3 Recovering a Broken Media URL

A client renders an event and finds a media URL inside it. Sometimes that URL no longer works. Follow this procedure:

  1. Check the URL path. Does it end with a 64-character hex string, with or without a file extension? If yes, that string is likely a sha256 hash of the file.
  2. The event's author may have published a kind:10063 list. The client SHOULD fetch that list.
  3. For each server tag in the list, build a new URL. Use the hex string as the path, optionally with the file extension at the end: https://blossom.self.hosted/<hex-string>.png.
  4. Request each candidate URL until one returns the file.
  5. The client SHOULD verify the download: the sha256 hash of the file's contents must match the 64-character hex string.

More information about this lookup is in BUD-03.

Warning!

Do not skip the hash check. Any server can answer any path. Only the sha256 match proves you received the file the author posted. Discard a file whose hash differs.

Tech Note

The trigger is a heuristic. The source says a dead URL that ends in 64 hex characters "is likely" a sha256 hash. It defines no marker that says so for certain, and it does not say how a client decides that a URL "is not available anymore" (status codes, timeouts). Implementations must pick their own failure test. False positives are harmless: the hash check in step 5 rejects any wrong file.

Client Relay Blossom srv ["REQ","srv",{"kinds":[10063],…}] ["EVENT","srv",{server tags}] GET /<hex-string>.png 200 OK + file bytes Client computes sha256(bytes). Match with the hex string → render. Mismatch → discard.
Fig. B7-2 — Recovery sequence. The relay serves the server list. The Blossom server serves the file. The hash check closes the loop.

4 More Complex Interactions

Blossom servers expose more facilities than plain downloads. For example, a client can check that a file exists on a server without downloading it. Clients may use any of these facilities. The Blossom BUDs document them; this NIP does not restate them.

5 Worked Example

Alice posted a photo to her own Blossom server. That server is now offline. Bob's client repairs the link. Orange lines are requests the client sends. Blue lines are responses.

Recovery session - Bob's client
-- 1. The original URL in Alice's note is dead --
→ GET https://media.dead.example/b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553.jpg
← (connection refused)

-- 2. Path ends in 64 hex chars: fetch Alice's server list --
→ ["REQ", "srv", {"kinds":[10063], "authors":["781208004e09…cd036"]}]
← ["EVENT", "srv", {"kind":10063, "tags":[
     ["server","https://blossom.self.hosted"],
     ["server","https://cdn.blossom.cloud"]], …}]
← ["EOSE", "srv"]

-- 3. Try each server with the hash as the path --
→ GET https://blossom.self.hosted/b1674191a88e…f4f553.jpg
← 404 Not Found
→ GET https://cdn.blossom.cloud/b1674191a88e…f4f553.jpg
← 200 OK  (image bytes)

-- 4. Verify: sha256(bytes) == b1674191a88e…f4f553 → render the photo --

6 Version History

NIP-B7 is young and short. It replaced NIP-96 as the recommended way to host media for Nostr. Changes, newest first:

  • 20252025-04Renamed the source files to uppercase hex (b7.md became B7.md). No spec change.
  • Origin2025-04-24fiatjaf added NIP-B7 for Blossom interaction in PR #1822. The Blossom project itself predates the NIP.

Original Proposal - Credits

Authorfiatjaf
First commit2025-04-24 — “add B7 NIP for Blossom interaction (#1822)” - PR #1822
Statusdraft - optional — clients that show media SHOULD implement the recovery lookup
SourceB7.md on GitHub - full change history

7 See Also

  • NIP-01 — the event format, replaceable kinds, and the REQ flow used to fetch the server list.
  • NIP-96 — the older HTTP file storage spec, now deprecated in favor of this NIP.
  • NIP-92 — imeta tags that attach metadata (including a sha256 hash) to media URLs in events.
  • NIP-94 — file metadata events that describe hosted files.
  • NIP-51 — the standard lists catalog; it registers kind 10063 as the Blossom server list.
  • NIP-5A — static websites served from Blossom blobs; uses the same kind:10063 lookup.