1 Overview
Nostr has no central moderator. It also has no central catalog. This NIP gives any user a way to say something about something else. That statement is a label.
The NIP defines two new indexable tags and one new event kind. The L tag names a label namespace. The l tag holds a label value. The kind 1985 event attaches those labels to existing targets: events, pubkeys, relays, URLs, or topics.
Labels support many use cases with one mechanism. Examples: distributed moderation, collection management, license assignment, and content classification. Clients decide which labelers to trust. The protocol only carries the labels.
Think of a label event as a sticky note. Anyone can write one and stick it on any event or profile. Reading clients choose whose sticky notes to display. Nobody can stick a note that others are forced to see.
e, p, a, r, or t tags.2 The Label Event: Kind 1985
A label event is a regular event of kind 1985 (see NIP-01 for storage classes). It carries three groups of data. The L tags declare namespaces. The l tags hold label values. The target tags point at the labeled objects.
{
"kind": 1985,
"tags": [
["L", <namespace>],
["l", <label value>, <namespace mark>],
["e" | "p" | "a" | "r" | "t", <target>, <relay hint, for e/p>]
],
"content": <optional longer explanation>
// other NIP-01 fields...
}
| Tag | Holds | Rule |
|---|---|---|
| L | a label namespace | Any string. RECOMMENDED. Use a well-defined standard or reverse domain name notation. |
| l | a label value | Any string. MUST carry a mark that matches an L tag in the same event, if one exists. |
| e p a r t | the label target(s) | At least one target tag MUST be present in a kind 1985 event. |
Both L and l are single-letter tags. Relays index them under the NIP-01 rules. Clients can query labels with the filter keys {"#L": [<namespace>]} and {"#l": [<value>]}.
3 The Namespace Tag: L
An L tag value can be any string. Publishers SHOULD make namespaces unambiguous. Use a well-defined namespace, such as an ISO standard. Or use reverse domain name notation, such as com.example.ontology.
L tags are RECOMMENDED. They let clients search by namespace instead of by one specific label. A query for {"#L": ["com.example.ontology"]} finds every label in that vocabulary.
Two namespace values have special meaning:
ugc("user generated content"): MAY be used when an end user typed the label content freehand.- Values that start with
#: the target should be associated with the label's value as a standard nostr tag. Example:["L", "#t"]attaches topic tags. This attaches standard tags to events, pubkeys, relays, URLs, and other objects.
4 The Label Tag: l
An l tag's value can be any string. The second element of the tag is the mark. The mark states which namespace the label belongs to.
The mark rules are strict. Apply them in order:
- If the event has an
Ltag, eachltag MUST include a mark that matches oneLtag value. - If the event has no
Ltag, eachltag SHOULD still include a mark. - If an
ltag has no mark at all, the namespaceugcis implied.
l tag points back at an L tag value in the same event.5 Label Targets
A kind 1985 event MUST include one or more tags that represent the labeled object or objects. The allowed target tags are e, p, a, r, and t. As in NIP-01, a relay hint SHOULD be included in e and p tags.
| Tag | Target | Value |
|---|---|---|
| e | an event | event id, plus a relay hint (SHOULD) |
| p | a person | pubkey, plus a relay hint (SHOULD) |
| a | an addressable event | <kind>:<pubkey>:<d value> coordinate |
| r | a relay or URL | the URL string |
| t | a topic | the topic string |
The source text lists five target tags but says they label "events, people, relays, or topics respectively" — only four purposes. The mapping of a (addressable events) and of URLs is left implicit. The table above restores the full mapping from the tags' NIP-01 meanings.
6 Content and Self-Reporting
Content. Labels should be short, meaningful strings. Put longer discussion in the event's content field. Example: the explanation of why a target was labeled a certain way.
Self-reporting. l and L tags MAY be added to event kinds other than 1985. For any event with a kind other than 1985, the labels refer to the event itself. The author labels their own content. See Example E below.
7 Vocabulary Guidelines
Bulk labels and edits. One kind 1985 event may label many targets at once. To edit a bulk label, request deletion of the old event with NIP-09 and publish a replacement. The NIP deliberately does not use addressable or replaceable events here. Reason: no standard d tag scheme was simple enough.
One namespace per event. Publishers SHOULD limit a label event to a single namespace. This avoids ambiguity when querying.
Reuse before you invent. Before you create a vocabulary, explore existing designs for your use case. Imitate them when possible. Reverse domain name notation avoids namespace clashes. But all namespaces should be considered open for public use, not proprietary. If a namespace fits your use case, use it — even if it points to someone else's domain name.
Fully qualified labels. A vocabulary MAY qualify every label with its namespace, for example ["l", "com.example.vocabulary:my-label"]. Prefer this for formal vocabularies that must not be confused with others when queried without an L tag. In such a vocabulary, all labels SHOULD include the namespace. Do not mix qualified and unqualified labels.
Labels are categories, not values. A good heuristic: would the label ever be unique? Many events can share the label of a place, a topic, or a pubkey. But specific values like "John Doe" or "3.18743" are data, not labels. Handle them some other way.
Known ontologies. The NIP appendix lists one non-exhaustive starting point in widespread use: the social ontology categories collection.
8 Worked Examples
The six events below restate every example from the source NIP. Placeholders in angle brackets stand for real hex values.
Example A. A suggestion that multiple pubkeys be associated with the permies topic. The #t namespace attaches a standard topic tag to the two people.
{
"kind": 1985,
"tags": [
["L", "#t"],
["l", "permies", "#t"],
["p", <pubkey1>, <relay_url>],
["p", <pubkey2>, <relay_url>]
]
// other fields...
}
Example B. A report that flags violence toward a human being, as defined by the ontology at ontology.example.com.
{
"kind": 1985,
"tags": [
["L", "com.example.ontology"],
["l", "VI-hum", "com.example.ontology"],
["p", <pubkey1>, <relay_url>],
["p", <pubkey2>, <relay_url>]
]
// other fields...
}
Example C. A moderation suggestion that approves a chat event from NIP-28 (a kind 40 channel).
{
"kind": 1985,
"tags": [
["L", "nip28.moderation"],
["l", "approve", "nip28.moderation"],
["e", <kind40_event_id>, <relay_url>]
]
// other fields...
}
Example D. Assignment of a license to an event.
{
"kind": 1985,
"tags": [
["L", "license"],
["l", "MIT", "license"],
["e", <event_id>, <relay_url>]
]
// other fields...
}
Example E. Self-labeling. The author of this kind 1 note labels it as related to Milan, Italy, using ISO 3166-2. The labels sit on the note itself, not on a kind 1985 event.
{
"kind": 1,
"tags": [
["L", "ISO-3166-2"],
["l", "IT-MI", "ISO-3166-2"]
],
"content": "It's beautiful here in Milan!"
// other fields...
}
Example F. Self-labeling the note's language as English, using ISO-639-1.
{
"kind": 1,
"tags": [
["L", "ISO-639-1"],
["l", "en", "ISO-639-1"]
],
"content": "English text"
// other fields...
}
Reading labels back is a normal NIP-01 query. The session below fetches all labels in one namespace, then all labels on one event.
-- all labels in a namespace -- → ["REQ", "mods", {"kinds":[1985], "#L":["com.example.ontology"]}] ← ["EVENT", "mods", {"kind":1985, "tags":[["L","com.example.ontology"], ["l","VI-hum","com.example.ontology"], ["p","f7234bd4…"]], …}] ← ["EOSE", "mods"] -- all labels attached to one event -- → ["REQ", "onevt", {"kinds":[1985], "#e":["5c83da77…"]}] ← ["EVENT", "onevt", {"kind":1985, "tags":[["L","license"], ["l","MIT","license"], ["e","5c83da77…"]], …}] ← ["EOSE", "onevt"]
9 Version History
NIP-32 grew out of Jonathan Staab's work on distributed moderation. It replaced an earlier, narrower reporting focus with a general labeling vocabulary. Notable changes, newest first:
- 20242024-08Updated the bulk-edit guidance to follow NIP-09's rename to "deletion request".
- 20242024-07Added the ISO-639-1 language self-label example.
- 20242024-06Strengthened the mark rules:
ltags MUST match anLtag when one exists. - 20242024-03Relaxed
Ltag requirements from mandatory to RECOMMENDED; a missing mark now impliesugc. - 20232023-11Removed label annotations (JSON metadata on labels) to keep the spec lean; author lists dropped from all NIPs.
- 20232023-06Dropped replaceable label events in favor of delete-and-republish; trimmed examples; NIP-36 pointed here.
- 20232023-05Added the
Ltag, self-labeling,#-prefixed namespaces, relay hints, and qualified-name guidance in a rapid series of revisions. - Origin2023-05-15Jonathan Staab published "Add NIP-32 for labeling things in nostr".
Original Proposal - Credits
| Author | Jonathan Staab |
| First commit | 2023-05-15 — “Add NIP-32 for labeling things in nostr” |
| Status | draft - optional — implement it if your client reads or writes labels |
| Source | 32.md on GitHub - full change history |
10 See Also
- NIP-01 — the event format, single-letter tag indexing, and the
e/p/atags this NIP targets. - NIP-09 — deletion requests; the edit mechanism for bulk label events.
- NIP-28 — public chat; the channel events moderated in Example C.
- NIP-36 — sensitive content warnings; an early adopter that points to this labeling scheme.
- NIP-56 — reporting; a narrower, fixed-vocabulary sibling for abuse reports.