Appearance
📋
Ditto Nostr Reference
All Nostr event kinds that Ditto supports, including NIP extensions, community kinds, and Ditto-specific kinds.
For a complete list of all Nostr event kinds, see nostrbook.dev. The protocol is defined by NIPs (Nostr Implementation Possibilities), and community members can share custom NIP proposals on NostrHub.
📦
Supported kinds
Ditto-created kind✦ whimsy
| Kind | Name | Description |
|---|---|---|
| 0 | Profile Metadata | User profile information: name, bio, avatar, and more (NIP-01) |
| 1 | Short Text Note | The core post type on Nostr (NIP-01) |
| 3 | Follow List | The user's list of followed pubkeys (NIP-02) |
| 5 | Deletion | Delete a previously published event (NIP-09) |
| 17 | External Content Reaction | Reaction on external content like URLs or ISBNs (NIP-73) |
| 20 | Photo | Photo post displayed in the Photos feed (NIP-68) |
| 21 | Video | Video post displayed in the Videos feed (NIP-71) |
| 22 | Short Video | Short-form vertical video, Reels/TikTok-style (NIP-71) |
| 62 | Request to Vanish | Request identity deletion from relays (NIP-62) |
| 1018 | Poll Vote | Cast a vote on a kind 1068 poll |
| 1063 | File Metadata | File metadata for uploads, including Webxdc apps (NIP-94) |
| 1068 | Poll | Community poll with multiple-choice options |
| 1111 | Comment | Threaded comment on posts and external content (NIP-22) |
| 1222 | Voice Message | Root voice message post |
| 1244 | Voice Message Reply | Voice message reply to a kind 1 note |
| 1311 | Live Chat Message | Chat message in a live stream (NIP-53) |
| 1617 | Patch | Git patch for code review (NIP-34) |
| 1618 | Pull Request | Git pull request (NIP-34) |
| 1984 | Report | Flag content or users for moderation |
| 1985 | Trending Labels | Trending hashtags and posts published by the relay (NIP-32) |
| 3367 | Color Moment ✦ | Color palette post expressing a mood |
| 7516 | Found Log ✦ | Log entry recording a user finding a geocache |
| 9735 | Zap Receipt | Lightning zap receipt for payments (NIP-57) |
| 10000 | Mute List | Muted users, threads, and words (NIP-51) |
| 10001 | Pinned Notes | Pinned posts displayed on user profiles (NIP-51) |
| 10002 | Relay List | User's preferred relays for reading and writing (NIP-65) |
| 10003 | Bookmark List | Bookmarked events (NIP-51) |
| 10015 | Interests | User's followed hashtags and interests (NIP-51) |
| 10030 | Custom Emoji List | User's preferred custom emoji packs (NIP-30) |
| 10063 | Blossom Server List | User's Blossom file upload servers (BUD-03) |
| 10073 | Read Books | Books the user has finished reading (Bookstr) |
| 10074 | Currently Reading | Books the user is currently reading (Bookstr) |
| 10075 | To Be Read | Books the user wants to read (Bookstr) |
| 16767 | Active Profile Theme | The user's currently active profile theme |
| 16769 | Profile Tabs | Custom profile tab configuration |
| 30000 | People List | User-defined lists of people (NIP-51) |
| 30008 | Profile Badges | Badges a user has accepted and displayed (NIP-58) |
| 30009 | Badge Definition | Badge metadata and imagery (NIP-58) |
| 30023 | Article | Long-form blog post with Markdown content (NIP-23) |
| 30030 | Emoji Pack | Custom emoji pack definition (NIP-30) |
| 30054 | Podcast Episode | Podcast episode displayed in the Podcasts feed |
| 30055 | Podcast Trailer | Podcast trailer displayed in the Podcasts feed |
| 30063 | Software Release | App release metadata from Zapstore (NIP-82) |
| 30078 | App Settings | Encrypted per-user Ditto settings (NIP-78) |
| 30311 | Stream | Live streaming event (NIP-53) |
| 30315 | User Status | User status displayed on profiles and posts (NIP-38) |
| 30382 | User Stats | Follower and post counts from the relay stats pubkey (NIP-85) |
| 30383 | Event Stats | Engagement counts for events from the relay stats pubkey (NIP-85) |
| 30384 | Addressable Event Stats | Engagement counts for addressable events (NIP-85) |
| 30617 | Git Repository | Git repository or app submission (NIP-34) |
| 30817 | Custom NIP | Custom NIP proposal on NostrHub |
| 31922 | Date Calendar Event | Date-based calendar event (NIP-52) |
| 31923 | Time Calendar Event | Time-based calendar event (NIP-52) |
| 31925 | Calendar RSVP | RSVP response to a calendar event (NIP-52) |
| 31985 | Book Review | Book review and rating (Bookstr) |
| 32267 | App | Software application listing from Zapstore (NIP-82) |
| 34139 | Music Playlist | Music playlist displayed in the Music feed |
| 34236 | Vine ✦ | Short-form video post |
| 34550 | Community Definition | Community definition (NIP-72) |
| 36767 | Theme Definition | Shareable custom UI theme with colors, font, and background |
| 36787 | Music Track | Music track displayed in the Music feed |
| 37381 | Magic Deck ✦ | Magic: The Gathering deck list |
| 37516 | Geocache ✦ | Geocache listing for real-world treasure hunting |
| 39089 | Follow Pack | Curated follow recommendations (starter packs) |
🔷
Avatar Shape
Kind 0 profile metadata (NIP-24) is extended with a shape property. The value is any emoji, which is used as a mask over the user’s avatar to set its shape.
json
{
"kind": 0,
"content": "{\"name\":\"alex\",\"picture\":\"https://example.com/avatar.jpg\",\"shape\":\"🔷\"}"
}A NIP proposal has been submitted to standardize this field.
🎨
Ditto Profile Theme
Replaceable event representing the user’s currently active profile theme. Only one exists per user. When visiting a profile, clients query this kind to determine what theme to display.
The event uses the same c, f, and bg tags as theme definitions. An optional a tag references the source theme definition for attribution.
Event structure
json
{
"kind": 16767,
"content": "",
"tags": [
["c", "#1a1a2e", "background"],
["c", "#e0e0e0", "text"],
["c", "#6c3ce0", "primary"],
["f", "Inter", "https://example.com/inter.woff2"],
["bg", "url https://example.com/bg.jpg", "mode cover", "m image/jpeg"],
["title", "MK Dark Theme"],
["a", "36767:<source-author-pubkey>:<source-d-tag>"],
["alt", "Active profile theme"]
]
}Content
The content field is unused and MUST be an empty string ("").
Tags
| Tag | Required | Description |
|---|---|---|
c | Yes (x3) | Hex color with role marker (same format as kind 36767). |
f | No | Font declaration. |
bg | No | Background media. |
title | No | Human-readable name for the theme. |
a | No | Reference to the source kind 36767 event (kind:pubkey:d-tag). Enables attribution (“Using X’s theme”). |
alt | Yes | NIP-31 human-readable fallback |
Client behavior
- Query:
{ kinds: [16767], authors: [<pubkey>], limit: 1 }to get a user’s active theme. - Colors: Read the
ctags to extract colors,ftags for fonts, andbgtag for the background. - Attribution: The
atag lets clients display “Using MK Dark Theme by @mk” with a link to the source theme. - Set: Publish a new kind 16767 event to change the active theme (replaces the previous one).
- Clear: Publish a kind 5 deletion event targeting kind 16767 to remove the active theme.
🖌️
Ditto Theme
Addressable event for publishing shareable custom UI themes. A user can publish multiple themes, each identified by a unique d tag. Colors are stored in c tags, with optional font (f) and background (bg) tags.
Event structure
json
{
"kind": 36767,
"content": "",
"tags": [
["d", "mk-dark-theme"],
["c", "#1a1a2e", "background"],
["c", "#e0e0e0", "text"],
["c", "#6c3ce0", "primary"],
["f", "Inter", "https://example.com/inter.woff2"],
["bg", "url https://example.com/bg.jpg", "mode cover", "m image/jpeg", "dim 1920x1080"],
["title", "MK Dark Theme"],
["description", "A sleek dark theme with purple and blue accents"],
["alt", "Custom theme: MK Dark Theme"],
["t", "theme"]
]
}Content
The content field is unused and MUST be an empty string ("").
Tags
| Tag | Required | Description |
|---|---|---|
d | Yes | Unique identifier (slug) for this theme |
c | Yes (x3) | Hex color with role marker. See Color tags. |
f | No | Font declaration. See Font tag. |
bg | No | Background media. See Background tag. |
title | Yes | Human-readable theme name |
description | No | Brief description of the theme |
alt | Yes | NIP-31 human-readable fallback |
t | Yes | Set to "theme" for discoverability |
Color tags
Format: ["c", "#rrggbb", "<marker>"]
Each theme requires exactly 3 color tags with these markers:
| Marker | Description |
|---|---|
background | Page background color |
text | Primary text/foreground color |
primary | Accent color (buttons, links, focus rings) |
Colors are lowercase 6-digit hex codes including the # sign. Clients derive all other UI colors (card, muted, border, etc.) from these 3 values.
Font tag
Format: ["f", "<family>", "<url>"]
Optional. At most one per event. The font applies globally to all text. Variable font files covering multiple weights are preferred.
Background tag
Uses an imeta-style variadic format: ["bg", "url <url>", "mode <mode>", "m <mime-type>", ...]
| Key | Required | Description |
|---|---|---|
url | Yes | URL to an image or video file |
mode | Yes | Display mode: "cover" or "tile" |
m | Yes | MIME type (e.g. "image/jpeg", "video/mp4") |
dim | No | Dimensions: "<width>x<height>" |
blurhash | No | Blurhash placeholder for progressive loading |
Multiple themes per user
Since kind 36767 is addressable, a user can publish multiple themes by using different d tag values. Publishing a new event with the same d tag replaces the previous version.
⚙️
Ditto Settings
Ditto stores encrypted per-user settings in a NIP-78 application-specific data event. The d tag is always ditto-metadata and the content is NIP-44 encrypted JSON.
Event structure
json
{
"kind": 30078,
"content": "<NIP-44 encrypted JSON>",
"tags": [
["d", "ditto-metadata"],
["title", "Ditto Metadata"],
["client", "ditto.pub"]
]
}Decrypted content schema
After NIP-44 decryption with the user’s own pubkey, the content is a JSON object with these fields:
| Field | Type | Description |
|---|---|---|
theme | "light" | "dark" | "system" | "custom" | Active theme mode |
customTheme | ThemeConfig | Custom theme configuration with 3 core colors, optional font and background (see Theming) |
useAppRelays | boolean | Whether to use Ditto’s default relays alongside the user’s relay list |
feedSettings | FeedSettings | Toggles controlling which content types appear in the sidebar and feed |
contentFilters | ContentFilter[] | User-defined content filter rules |
contentWarningPolicy | "blur" | "show" | "hide" | How to handle NIP-36 content-warning events |
notificationsCursor | number | Unix timestamp (seconds) of the last viewed notification |
lastSync | number | Timestamp of the last settings sync (milliseconds) |
Example (decrypted)
json
{
"theme": "dark",
"customTheme": {
"colors": {
"background": "228 20% 10%",
"text": "210 40% 98%",
"primary": "258 70% 60%"
}
},
"useAppRelays": true,
"feedSettings": {
"feedIncludePosts": true,
"feedIncludeReposts": true,
"feedIncludeArticles": true,
"feedIncludeVines": true,
"showVines": true,
"showStreams": true,
"showPolls": false
},
"contentWarningPolicy": "blur",
"notificationsCursor": 1700000000,
"lastSync": 1700000000000
}🔍
Search
Ditto’s relay supports full-text search through NIP-50 with search extensions. The public relay is available at wss://relay.ditto.pub.
Extensions can be combined with each other and with free-text search terms. For example, "search": "bitcoin sort:hot language:en" returns trending English-language posts matching “bitcoin”.
json
{
"kinds": [1],
"search": "bitcoin sort:hot language:en",
"limit": 20
}Search extensions
Ditto-introduced extension
| Extension | Description |
|---|---|
language:<en/zh/ja/...> | Filter events by detected language (NIP-50) |
sentiment:<positive/negative/neutral> | Filter events by detected sentiment (NIP-50) |
protocol:<activitypub/atproto/nostr> | Filter by originating protocol (NIP-48). protocol:nostr returns native Nostr events only. |
media:<true/false> | Filter by presence of media attachments |
video:<true/false> | Filter by presence of video content |
sort:top | Sort by total engagement (unique engagers). Default when search text is present. |
sort:hot | Sort by engagement weighted with time decay, surfacing what's trending now |
sort:controversial | Sort by controversy score, favoring events with balanced comments and reactions |
sort:rising | Sort by engagement velocity relative to age |
sort:zaps | Sort by total zap amount |
sort:new | Sort chronologically (prevents the default sort:top behavior) |
distinct:author | Deduplicate results to one event per author |
-<term> | Exclude events matching the given term |
📊
Stats
Ditto’s relay publishes engagement stats for events using NIP-85 (kind 30383). These are addressable events authored by the relay’s stats pubkey, with the d tag set to the target event’s ID.
The stats pubkey for wss://relay.ditto.pub is:
5f68e85ee174102ca8978eef302129f081f03456c884185d5ec1c1224ab633eaEvent structure
json
{
"kind": 30383,
"pubkey": "5f68e85ee174102ca8978eef302129f081f03456c884185d5ec1c1224ab633ea",
"content": "",
"tags": [
["d", "<target-event-id>"],
["k", "1"],
["p", "<target-event-pubkey>"],
["comment_cnt", "42"],
["repost_cnt", "7"],
["reaction_cnt", "128"],
["zap_cnt", "15"]
]
}Tags
| Tag | Description |
|---|---|
d | ID of the event being described |
k | Kind of the referenced event |
p | Pubkey of the referenced event’s author |
comment_cnt | Number of replies/comments |
repost_cnt | Number of reposts |
reaction_cnt | Number of reactions |
zap_cnt | Number of zaps |
Filter example
json
{
"kinds": [30383],
"authors": ["5f68e85ee174102ca8978eef302129f081f03456c884185d5ec1c1224ab633ea"],
"#d": ["<target-event-id>"],
"limit": 1
}Clients can batch multiple event IDs into a single request by passing an array of IDs in #d.
🔥
Trends
Ditto publishes trending data as NIP-32 label events under the pub.ditto.trends namespace. A trusted relay pubkey publishes these periodically.
Trending hashtags
A label event with l: #t contains the current trending hashtags. Each t tag carries the hashtag name along with engagement counts.
json
{
"kind": 1985,
"pubkey": "15b68d319a088a9b0c6853d2232aff0d69c8c58f0dccceabfb9a82bd4fd19c58",
"content": "",
"tags": [
["L", "pub.ditto.trends"],
["l", "#t", "pub.ditto.trends"],
["t", "bitcoin", "", "142", "580"],
["t", "nostr", "", "98", "312"],
["t", "art", "", "67", "201"]
]
}t tag format: ["t", <hashtag>, "", <accounts>, <uses>]
| Index | Value | Description |
|---|---|---|
| 0 | "t" | Tag name |
| 1 | hashtag | The trending hashtag (lowercased) |
| 2 | "" | Reserved (empty) |
| 3 | accounts | Number of distinct accounts using this hashtag |
| 4 | uses | Total number of uses |
Filter structure
json
{
"kinds": [1985],
"authors": ["15b68d319a088a9b0c6853d2232aff0d69c8c58f0dccceabfb9a82bd4fd19c58"],
"#L": ["pub.ditto.trends"],
"#l": ["#t"],
"limit": 1
}