1 Overview
NIP-17 defines private direct messages. It hides the content of a message. It also hides who sent it, who received it, and when. NIP-17 does not invent new cryptography. It combines two existing NIPs: NIP-44 for encryption and NIP-59 for gift wrapping.
A conversation happens inside a chat room. By convention, three kinds of content flow through a chat room: kind 14 chat messages, kind 15 file messages, and kind 7 reactions, defined in NIP-25. This page calls all three message rumors.
Every message rumor is unsigned. A client seals it, then gift-wraps it, before it ever reaches a relay. Section 3 covers this chain in full. A separate event kind, 10050, tells other clients which relays to use for delivery.
NIP-17 replaces NIP-04 encrypted direct messages, which is now deprecated. NIP-04 leaked the sender, the receiver, and the timestamp of every message in plain sight. NIP-17 hides all three.
2 Chat Rooms
The most common chat room has two members. NIP-17 also supports rooms with more members, though Section 8 recommends a different scheme past ten participants.
The sender's pubkey, plus every pubkey in a p tag, defines the room. Add one p tag, or remove one, and the result is a new room. The new room starts with a clean, empty history.
An optional subject tag names the room. Any member can rename the room by sending a new message with a new subject tag. Clients use the newest subject tag as the current name. A client does not need to repeat the subject tag on every message.
3 The Encryption Chain
NIP-17 wraps a message rumor three layers deep. Each layer hides information that the layer around it does not need to know.
- Rumor — the message itself: a
kind 14,kind 15, orkind 7event, built and hashed like any other event, but never signed. - Seal — a
kind 13event. Itscontentholds the NIP-44-encrypted rumor. Itstagsarray is always empty. The sender signs the seal with their real key, so the seal proves who wrote the rumor, but nobody can read the rumor without a private key. - Gift wrap — a
kind 1059event. Itscontentholds the NIP-44-encrypted seal. It carries oneptag, naming the receiver. A brand-new, random, one-time keypair signs the gift wrap, so the gift wrap does not reveal the real sender.
{
"id": <usual sha256 hash, per NIP-01>
"pubkey": <sender pubkey>
"created_at": <current time>
"kind": 14
"tags": [
["p", <receiver-1 pubkey>, <relay-url>],
["p", <receiver-2 pubkey>, <relay-url>],
["subject", <conversation title>]
],
"content": <message, plain text>
-- no "sig" field. This object is never published as-is. --
}
{
"id": <usual hash>,
"pubkey": wrapperPublicKey, -- random, one-time key
"created_at": randomTimeUpTo2DaysInThePast,
"kind": 1059, -- gift wrap
"tags": [
["p", receiverPublicKey, <relay-url>] -- receiver
],
"content": nip44.encrypt(
{
"id": <usual hash>,
"pubkey": senderPublicKey, -- real sender
"created_at": randomTimeUpTo2DaysInThePast,
"kind": 13, -- seal
"tags": [], -- always empty
"content": nip44.encrypt(
unsignedMessageRumor, -- kind 14, 15, or 7
nip44.compute_conversation_key(senderPrivateKey, receiverPublicKey)
),
"sig": <signed by senderPrivateKey>
},
nip44.compute_conversation_key(wrapperPrivateKey, receiverPublicKey)
),
"sig": <signed by wrapperPrivateKey>
}
Clients MUST verify that the pubkey on the kind:13 seal matches the pubkey inside the sealed rumor. Without this check, any sender can impersonate any other sender by editing the rumor's pubkey field before sealing it.
wrapperPrivateKey is a new keypair. A client generates one fresh, random keypair for every single message it wraps. A sender creates one gift wrap per receiver. It usually also creates one more gift wrap addressed to itself, so its own client can recover the conversation later.
Clients SHOULD randomize created_at by up to two days in the past, in both the seal and the gift wrap. Real message time stays hidden in the rumor. This stops a relay from grouping messages by timestamp and inferring who is talking to whom.
4 Message Kinds: Chat and File
Kind 14 — chat message. Its content MUST be plain text: no markup, no encoding. The id and created_at fields are required, computed the normal way even though the event stays unsigned.
| Tag | Form | Rule |
|---|---|---|
| p | ["p", <receiver pubkey>, <relay-url>] | One per receiver. One or more required. |
| e | ["e", <parent kind-14 id>, <relay-url>] | Present only on a reply. Names the direct parent message. |
| subject | ["subject", <conversation title>] | Optional. Renames the room. See Section 2. |
| q | ["q", <event id or address>, <relay-url>, <pubkey, if a regular event>] | Optional. Cites an event quoted inside content, using the NIP-21 nostr: scheme. |
Kind 15 — file message. It sends an encrypted file by reference. The content field holds only the file's URL; the file itself is encrypted and hosted separately.
| Tag | Meaning |
|---|---|
| p | One per receiver, same as kind 14. |
| e | Direct parent message, if this is a reply. |
| subject | Optional room name, same as kind 14. |
| file-type | MIME type of the file before encryption, for example image/jpeg. |
| encryption-algorithm | Algorithm used to encrypt the file. Only aes-gcm is defined today. |
| decryption-key | The key the receiver needs to decrypt the file. |
| decryption-nonce | The nonce the receiver needs to decrypt the file. |
| x | sha256 hash, hex-encoded, of the encrypted file. |
| ox | sha256 hash, hex-encoded, of the file before encryption. |
| size | Optional. Size of the encrypted file, in bytes. |
| dim | Optional. Pixel size, as <width>x<height>. |
| thumbhash | Optional. A thumbhash to show while the file loads. |
| blurhash | Optional. A blurhash to show while the file loads. |
| thumb | Optional. URL of a thumbnail, same aspect ratio, encrypted with the same key and nonce. |
| fallback | Optional. Zero or more backup URLs for the file, in case the main URL fails. |
Source inconsistency: the kind 14 example's reply e tag has three elements, no marker: ["e", <id>, <relay-url>]. The kind 15 example's reply e tag has a fourth element, a "reply" marker: ["e", <id>, <relay-url>, "reply"]. This page restates both examples as written in source-nips/17.md. One 2025 change to this NIP is titled "removes the need for markers," which makes the kind 15 example's leftover marker look like an unfixed copy-paste artifact rather than an intended rule. Treat the unmarked, three-element form as current.
5 Publishing and DM Relay Lists
Kind 10050 tells other clients where to deliver DMs. It is a small, replaceable event that lists a user's preferred inbox relays.
{
"kind": 10050,
"tags": [
["relay", "wss://inbox.nostr.wine"],
["relay", "wss://myrelay.nostr1.com"]
],
"content": ""
-- other fields, id/pubkey/created_at/sig, are the usual event fields --
}
The event MUST include one or more relay tags. Clients MUST publish gift wraps only to relays listed in the receiver's kind 10050 event. If a receiver has no such list, that receiver is not ready to receive messages. Clients should not try to send to them.
#p filter and unwraps locally.6 Relay Recommendations
Relays SHOULD protect metadata: serve kind:1059 events only to the pubkey named in the event's p tag. Relays enforce this with NIP-42 AUTH, requiring the requesting client to prove it controls that pubkey before the relay returns any results.
Clients SHOULD guide users to keep their kind:10050 list small, one to three relays. Clients SHOULD also spread that small list across as many separate relay operators as is practical, to avoid a single relay seeing every message.
7 Delete, Edit, and Disappearing Messages
NIP-59 already lets the p-tagged recipient of a gift wrap delete it. NIP-17 adds one more option: a client MAY wrap a kind:5 delete request in its own kind:1059 gift wrap, and send it to the recipient as part of the conversation. Clients SHOULD remove a deleted message from the conversation view, or mark it as deleted.
Clients MAY implement editing as a delete, followed by a new message published with the same timestamp as the original.
Clients MAY offer disappearing messages two ways: add an expiration tag (NIP-40) to each receiver's gift wrap, or simply skip generating a gift wrap addressed to the sender's own key. The expiration tag SHOULD also be set on the kind:13 seal, in case the seal ever leaks on its own.
8 Benefits, Limitations, and Spam
NIP-17's three-layer design buys real privacy properties. It also has real costs. Both matter when choosing this scheme.
| Property | What it means |
|---|---|
| No metadata leak | Identities, real timestamps, kinds, and tags stay hidden from public view. Public data alone cannot link a sender to a receiver. |
| No public group identifiers | No shared queue, channel, or ID lets an outsider count or correlate all messages in one room. |
| No moderation | No admins, invitations, or bans exist at the protocol level. |
| No shared secrets | No secret needs to be known by every member, so no secret can leak from a careless member. |
| Fully recoverable | Any client holding the user's private key can recover the full message history. |
| Optional forward secrecy | Users and clients may opt in to disappearing messages, described in Section 7. |
| Works on public relays | Messages flow through public relays without losing privacy. Private relays help further, but are not required. |
| Cold storage | Users may unilaterally share their messages with a separate key, kept only for DM backup and recovery. |
The main limitation: a sender must send a separate gift wrap to every single receiver. A group chat with more than ten participants should use a scheme built for groups instead.
Gift wraps sign with random, throwaway keys. A relay cannot apply the usual anti-spam tools, reputation, web-of-trust, or per-key rate limits, because every gift wrap arrives from a new, unknown key. The recommended fix is the NIP-42 AUTH-based relay policy described in NIP-59's spam protection section: require a real, authenticated identity before the relay accepts or serves gift wraps.
9 Worked Example
Alice sends "Hola, que tal?" to Bob. Below is a full round trip: the plain rumor, and the two real gift wraps this NIP produces, one addressed to Bob and one addressed back to Alice, exactly as published in the NIP-17 source text (long ciphertext blobs shortened with "…").
{
"pubkey": "6e468422dfb74a5738702a8823b9b28168abab8655faacb6853cd0ee15deee93",
"created_at": 1703015180,
"kind": 14,
"tags": [
["p", "918e2da906df4ccd12c8ac672d8335add131a4cf9d27ce42b3bb3625755f0788"]
],
"content": "Hola, que tal?"
}
{
"pubkey": "6e468422dfb74a5738702a8823b9b28168abab8655faacb6853cd0ee15deee93",
"created_at": 1703015180,
"kind": 13,
"tags": [],
"content": nip44.encrypt(rumor, conversation_key(sender, receiver)),
"sig": <signed by sender>
}
{
"id": "2886780f7349afc1344047524540ee716f7bdc1b64191699855662330bf235d8",
"pubkey": "8f8a7ec43b77d25799281207e1a47f7a654755055788f7482653f9c9661c6d51",
"created_at": 1703128320,
"kind": 1059,
"tags": [
["p", "918e2da906df4ccd12c8ac672d8335add131a4cf9d27ce42b3bb3625755f0788"]
],
"content": "AsqzdlMsG304G8h08bE67dhAR1gFTzTckUUyuvndZ8L…U1Ob9fEJv/ibNuSfqL6E4BnN",
"sig": "a3c6ce632b145c0869423c1afaff4a6d764a9b64dedaf15f170b944ead67227…c22bab"
}
{
"id": "162b0611a1911cfcb30f8a5502792b346e535a45658b3a31ae5c178465509721",
"pubkey": "626be2af274b29ea4816ad672ee452b7cf96bbb4836815a55699ae402183f512",
"created_at": 1702711587,
"kind": 1059,
"tags": [
["p", "44900586091b284416a0c001f677f9c49f7639a55c3f1e2ec130a8e1a7998e1b"]
],
"content": "AsTClTzr0gzXXji7uye5UB6LYrx3HDjWGdkNaBS6BAX…lTLHiHMlTbarFOd6J/ybIb",
"sig": "c94e74533b482aa8eeeb54ae72a5303e0b21f62909ca43c8ef06b0357412d6f…22bab"
}
Two gift wraps, near-identical in shape, carry the same rumor to two different keys: the receiver's, and the sender's own. A relay watching the wire sees two unrelated events, signed by two unrelated random keys. It cannot tell they are the same conversation.
10 Version History
NIP-17 has grown since 2024, from a two-party text chat into a scheme that also carries files and reactions. Notable changes, newest first:
- 20262026-06Repo-wide cosmetic pass: code fences switched from
jsonctoyaml; sections reordered for clarity. No rule changes. - 20262026-05Added the deletion section (a
kind:5delete wrapped in akind:1059gift wrap), and recommended NIP-42 AUTH as the standard fix for gift-wrap spam. - 20262026-04Added
thumbhashas an optional preview field, alongside the existingblurhash. - 20252025-12Tagged the NIP as a
relay-relevant document. - 20252025-10Refined wording throughout, and confirmed
kind 7reactions as a message rumor type alongside kind 14 and kind 15. A second change the same month clarified that clients must publish only to the receiver's kind 10050 relays. - 20252025-02Dropped the old reply-marker convention in favor of a plain
etag, and addedqtags for citing events incontent. Days earlier,kind 15file messages were added. - 20242024-08 to 2024-12Small fixes: object formatting, JSON-to-JSONC code fences, and a clarification on field order.
- 20242024-04fiatjaf added relay considerations and implementation notes, the same day the NIP landed.
- Origin2024-04-24Vitor Pamplona published the seal-and-gift-wrap DM scheme as NIP-17, renumbered from an earlier draft that had circulated as NIP-24 (PR #686). The filename existed since the August 2023 repo-wide "nips over nostr" import, but held no NIP-17 content until this commit.
Original Proposal - Credits
| Author | Vitor Pamplona |
| First commit | 2024-04-24 — “NIP-17 (old 24) Sealed Gift-Wrapped Messages for Private DMs and Small Group Chats” (PR #686) |
| Status | draft optional relay |
| Source | 17.md on GitHub - full change history |
11 See Also
- NIP-01 — the base event format that every rumor, seal, and gift wrap builds on.
- NIP-04 — the older, deprecated encrypted DM scheme that NIP-17 replaces.
- NIP-44 — the versioned encryption used at both the seal and the gift-wrap layer.
- NIP-59 — defines the rumor, seal, and gift-wrap kinds themselves, and their deletion and spam-protection rules.
- NIP-40 — the
expirationtag used for disappearing messages. - NIP-42 — relay AUTH, used to restrict gift-wrap delivery and to mitigate spam.
- NIP-09 — event deletion, the base mechanism a wrapped
kind:5request relies on. - NIP-25 — defines
kind 7reactions, one of the three message rumor types.