Chapter 72 - Social
72
Nostr Implementation Possibility - Hex № 72

Moderated Communities (Reddit Style)

Public forums built from three event kinds: a community definition, posts that tag it, and moderator approvals.

Deprecated

1 Overview

Deprecated

The source spec marks this NIP unrecommended. Do not build new communities on it. Use NIP-29 (Relay-based Groups) instead. This page documents the full spec for existing implementations.

This NIP enables public communities in the style of a Reddit forum. A community owner publishes one addressable event, kind:34550. That event names the community and lists its moderators.

Any user can post into the community. The user tags a Nostr event with the community's a address. No permission is needed to post. Moderation happens after the fact: a moderator publishes an approval event, kind:4550, for each post they accept. Clients then show only approved posts.

The model is open by design. Posts, approvals, and the community definition are all plain events on public relays. Any relay can host them. Any client can render them.

Member posts 1111 Moderator approves 4550 Relay stores both Reader approved only kind 1111 kind 4550 post + approval
Fig. 72-1 — Post-then-approve flow. Posting is open. Moderation is a separate approval event that readers filter on.

2 Community Definition — Kind 34550

The community definition is an addressable event, kind:34550. It should include any field that helps define the community and the set of moderators. The community address is 34550:<owner pubkey>:<d value>.

The d tag may double as the community name. If a name tag is present, clients should display it instead of the d value.

Wire format - kind 34550 community definition
{
  "created_at": <unix timestamp in seconds>,
  "kind": 34550,
  "tags": [
    ["d", <community-d-identifier>],
    ["name", <community name>],
    ["description", <community description>],
    ["image", <community image url>, <width>x<height>],
    // ... other tags relevant to defining the community

    // moderators
    ["p", <32-byte hex pubkey>, <optional relay URL>, "moderator"],

    // relays used by the community (with optional marker)
    ["relay", <relay hosting author kind 0>, "author"],
    ["relay", <relay for requests>, "requests"],
    ["relay", <relay for approvals>, "approvals"],
    ["relay", <relay for both requests and approvals>]
  ]
}
Kind 34550 tags
TagValueRule
dcommunity identifierRequired for an addressable event. May double as the display name.
namecommunity nameOptional. When present, clients should display it instead of the d value.
descriptiontextOptional. Describes the community.
imageURL + <width>x<height>Optional. Community image with optional dimensions.
ppubkey, optional relay URL, moderatorOne tag per moderator. The moderator marker sits in the 4th position.
relayrelay URL, optional markerMay describe the preferred relays for downloading requests and approvals. See the marker table below.
Relay tag markers
MarkerMeaning
authorRelay that hosts the owner's kind 0 metadata event.
requestsRelay where clients send and receive post requests.
approvalsRelay where clients send and receive approval events.
(none)Relay used to post requests to and fetch approvals from.
Tech Note

The source spec calls kind:34550 a "replaceable event". Under current NIP-01 terms it is an addressable event: kind 34550 sits in the 30000-39999 range and is keyed by pubkey + kind + d value. The text predates the rename.

3 Posting to a Community

Posts should use NIP-22 kind:1111 comment events. The uppercase A tag is always scoped to the community definition. The lowercase tags follow NIP-22 threading rules.

Top-level posts

For a top-level post, the uppercase and lowercase tags both point to the community definition itself.

Wire format - kind 1111 top-level post
{
  "kind": 1111,
  "tags": [
    ["A", "34550:<community-author-pubkey>:<community-d-identifier>", <optional relay URL>],
    ["a", "34550:<community-author-pubkey>:<community-d-identifier>", <optional relay URL>],
    ["P", <community-author-pubkey>, <optional relay URL>],
    ["p", <community-author-pubkey>, <optional relay URL>],
    ["K", "34550"],
    ["k", "34550"]
  ],
  "content": "Hi everyone. It's great to be here!"
}

Nested replies

For a nested reply, the uppercase tags still point to the community definition. The lowercase tags point to the parent post or reply.

Wire format - kind 1111 nested reply
{
  "kind": 1111,
  "tags": [
    // community definition itself
    ["A", "34550:<community-author-pubkey>:<community-d-identifier>", <optional relay URL>],
    ["P", <community-author-pubkey>, <optional relay URL>],
    ["K", "34550"],

    // parent post or reply
    ["e", <parent-event-id>, <optional relay URL>],
    ["p", <parent-event-author-pubkey>, <optional relay URL>],
    ["k", <parent-event-kind>]  // most likely "1111"
  ],
  "content": "Agreed! Welcome everyone!"
}
Community kind 34550 Top post kind 1111 Reply kind 1111 A + a A / P / K e / p / k → parent
Fig. 72-2 — Tag anatomy. Uppercase tags always anchor the community. Lowercase tags anchor the parent in a reply.

Backwards compatibility

Warning!

Older clients posted kind:1 events with an a tag pointing to the community. Clients may still query for those kind 1 events. Clients should not create new posts with kind 1. Use kind 1111 with the A and a tags shown above.

4 Moderation — Kind 4550

Anyone may publish an approval event. An approval states an opinion that a post fits the community. Clients may choose which approvals to honor. Clients should at least honor approvals from the moderators listed in the community definition.

An approval event is a regular event, kind:4550. It must include:

  • One or more community a tags. A community a tag always begins with 34550. This prefix disambiguates community pointers from other addressable-event pointers.
  • An e or a tag that points to the approved post.
  • The p tag of the post author, for approval notifications.

The approval should also carry the JSON-stringified post event inside content. It should carry a k tag with the post's kind. The k tag lets clients filter approved posts by kind.

Wire format - kind 4550 post approval
{
  "pubkey": <32-byte lowercase hex pubkey of the moderator>,
  "kind": 4550,
  "tags": [
    ["a", "34550:<community-author-pubkey>:<community-d-identifier>", <optional relay URL>],
    ["e", <post-id>, <optional relay URL>],
    ["p", <post-author-pubkey>, <optional relay URL>],
    ["k", <post-request-kind>]
  ],
  "content": <the full approved event, JSON-encoded>
}

A moderator may revoke an approval at any time. To revoke, publish a NIP-09 deletion request for the approval event.

Hint!

Have several moderators approve each post. If one moderator leaves the owner's list, their approvals stop counting, and singly-approved posts vanish from the community. If the whole moderator set rotates, the new moderators must re-sign approvals for past posts, or the community restarts. The owner can also periodically copy and re-sign each moderator's approvals so posts do not disappear.

Approving replaceable events

A replaceable post can be approved in three ways:

Approval pointer options for replaceable posts
PointerEffect
eApproves one specific version. Moderators approve each change separately.
aApproves the address. The author may publish new versions without further approvals.
e + aBoth tags together. Clients can display the original and the updated version, with suitable remarks in the UI.

Relays delete old versions of a replaceable event. So an approval that uses an e tag must embed that specific version in its content. Otherwise clients may not find that version anywhere.

One approval can serve many communities. Clients should treat every non-34550:* a tag as a post approved for all of the event's 34550:* community tags.

Tech Note

Two glitches in the source's approval example. First: the p tag placeholder reads <port-author-pubkey>; the prose makes clear it means the post author's pubkey. Second: its community a tag reads 34550:<event-author-pubkey>:…, while every other example uses the community author's pubkey there; the community author is the correct value.

5 Cross-Posting

Clients may support cross-posting between communities. To cross-post, publish a NIP-18 repost: kind:6 for kind 1 notes, kind:16 for other kinds. Tag the repost with one or more community a tags, as described above. The content of the repost must be the original event, not the approval event.

6 Worked Example

Alice owns the community gardening. Bob posts a top-level note. Mod Carol approves it. A reader client fetches approvals to build the moderated feed.

Event 1 - Alice defines the community
{
  "kind": 34550, "pubkey": "a11ce9f2…", "created_at": 1750000000,
  "tags": [
    ["d", "gardening"],
    ["name", "Gardening"],
    ["description", "Grow things. Show things."],
    ["image", "https://img.example.com/gardening.png", "600x600"],
    ["p", "ca401f3e…", "wss://relay.example.com", "moderator"],
    ["relay", "wss://relay.example.com", "requests"],
    ["relay", "wss://mods.example.com", "approvals"]
  ],
  "content": "", …
}
Event 2 - Bob posts (kind 1111)
{
  "id": "b0b7e4a1…", "kind": 1111, "pubkey": "b0b12c88…",
  "tags": [
    ["A", "34550:a11ce9f2…:gardening", "wss://relay.example.com"],
    ["a", "34550:a11ce9f2…:gardening", "wss://relay.example.com"],
    ["P", "a11ce9f2…"], ["p", "a11ce9f2…"],
    ["K", "34550"], ["k", "34550"]
  ],
  "content": "My tomatoes finally turned red.", …
}
Event 3 - Carol approves (kind 4550) + reader session
{
  "kind": 4550, "pubkey": "ca401f3e…",
  "tags": [
    ["a", "34550:a11ce9f2…:gardening", "wss://relay.example.com"],
    ["e", "b0b7e4a1…", "wss://relay.example.com"],
    ["p", "b0b12c88…"],
    ["k", "1111"]
  ],
  "content": "{\"id\":\"b0b7e4a1…\",\"kind\":1111,…}", …
}

-- reader builds the moderated feed --
→ ["REQ", "mod-feed", {"kinds":[4550], "authors":["ca401f3e…"],
     "#a":["34550:a11ce9f2…:gardening"]}]
← ["EVENT", "mod-feed", {"kind":4550, "id":"ca901bb2…", …}]
← ["EOSE", "mod-feed"]
-- client renders the post embedded in each approval's content --

7 Version History

The spec began life as NIP-172 in mid-2023 and got the number 72 two months later. Notable changes, newest first:

  • 20262026-05Marked unrecommended. The body now points implementers to NIP-29.
  • 20252025-07Community posts switched from kind:1 to NIP-22 kind:1111 with A/a scoping. Kind 1 kept for backwards compatibility only.
  • 20242024-01Added a title, the cross-posting section, and clearer moderation options (Jon Staab).
  • 20232023-08Renumbered: file moved from 172.md to 72.md.
  • 20232023-07Added the third option for approving replaceable events (e + a together).
  • 20232023-06Big rewrite: relay markers, replaceable posts allowed, approval moved to a regular event, revocation via NIP-09, RFC verbs (SHOULD/MAY).
  • 2023+2023-2026Typo, formatting, and heading-level fixes grouped.
  • Origin2023-06-12Vitor Pamplona published the first draft as NIP-172: "Simple moderated communities flow".

Original Proposal - Credits

AuthorVitor Pamplona (with arthurfranca)
First commit2023-06-12 — “Simple moderated communities flow” (as 172.md)
Statusdraft - unrecommended - optional — deprecated in favor of NIP-29
Source72.md on GitHub - full change history

8 See Also

  • NIP-29 — Relay-based Groups; the recommended replacement for this NIP.
  • NIP-01 — events, tags, and the addressable-event storage class that kind 34550 uses.
  • NIP-22 — kind 1111 comments; the post format for communities.
  • NIP-09 — deletion requests; how a moderator revokes an approval.
  • NIP-18 — kind 6 and kind 16 reposts; the cross-posting vehicle.