A Birdex is a replaceable per-author index of every bird species the author has ever confirmed via kind 2473, stored as positional i/n tag pairs in chronological first-seen order. In feeds, show a compact tile strip of the most recently-added species with a "+N" capstone when the list overflows — mirroring how kind 3 follow lists preview members as an avatar stack plus "+N more". On the post-detail page, render every species as a responsive grid so visitors can browse the author's whole life list. Each tile resolves the species' Wikidata entity through English Wikipedia to pull a thumbnail and common-name label, reusing the same fetch path as kind 2473 detection cards. The Wikidata URL is sanitized before being routed, and the paired n tag provides a scientific-name fallback while the remote lookup is in flight.
31 KiB
NIP: Custom Event Kinds
Event Kinds Overview
Ditto Kinds
| Kind | Name | Description |
|---|---|---|
| 8333 | Onchain Zap | Attestation that an on-chain BTC tx paid a target |
| 36767 | Theme Definition | Shareable, named custom UI theme |
| 16767 | Active Profile Theme | The user's currently active theme (one per user) |
| 16769 | Profile Tabs | The user's custom profile page tabs (one per user) |
Community Kinds
These event kinds were created by community contributors and are supported by Ditto. Full specifications are maintained by their respective authors.
| Kind | Name | Description | Spec |
|---|---|---|---|
| 2473 | Bird Detection | Bird-by-ear observation log (species heard in the wild) | NIP |
| 12473 | Birdex | Author's cumulative life list of confirmed bird species | NIP |
| 3367 | Color Moment | Color palette post expressing a mood | NIP |
| 4223 | Weather Reading | Sensor readings from a weather station | Draft NIP |
| 7516 | Found Log | Log entry recording a user finding a geocache | NIP-GC |
| 8211 | Encrypted Letter | Encrypted personal letter with visual stationery | NIP |
| 11125 | Blobbonaut Profile | Owner profile with coins, achievements, and inventory | NIP-BB |
| 14919 | Blobbi Interaction | Individual pet interaction (feed, play, clean, etc.) | NIP-BB |
| 14920 | Blobbi Breeding | Breeding event between two adult Blobbis | NIP-BB |
| 14921 | Blobbi Record | Immutable lifecycle record (birth, evolution, adoption) | NIP-BB |
| 16158 | Weather Station | Weather station metadata (location, sensors, connectivity) | Draft NIP |
| 31124 | Blobbi Pet State | Current state of a virtual Blobbi pet (addressable) | NIP-BB |
| 37516 | Geocache | Geocache listing for real-world treasure hunting | NIP-GC |
| 36787 | Music Track | Addressable event for a music audio file with metadata | See Music Tracks & Playlists below |
| 34139 | Music Playlist | Ordered list of music track references (also used for albums) | See Music Tracks & Playlists below |
| 30621 | Custom Constellation | User-drawn star figure with Hipparcos-numbered edges | NIP |
Kind 8333: Onchain Zap
Summary
Regular event kind that records a Bitcoin on-chain payment ("onchain zap") sent in appreciation of a Nostr event or profile. Functions as the on-chain analogue of NIP-57 zap receipts (kind 9735), but without the LNURL round-trip: the event is self-attested by the sender and references a real Bitcoin transaction that clients can verify directly on-chain.
The kind number mirrors the convention of NIP-57: kind 9735 is the Lightning P2P port (per BOLT spec), and kind 8333 is the Bitcoin mainnet P2P port — a natural semantic pairing for Lightning vs. on-chain settlement.
Because every Nostr keypair deterministically maps to a Bitcoin Taproot (P2TR) address (both use 32-byte x-only secp256k1 keys, per BIP-340/BIP-341), an on-chain zap is simply a Bitcoin transaction whose output pays the recipient's derived Taproot address. The kind 8333 event links that transaction to the Nostr event or profile being zapped.
Event Structure
{
"kind": 8333,
"pubkey": "<sender-pubkey>",
"content": "Great post!",
"tags": [
["e", "<target-event-id>", "<relay-hint>"],
["p", "<target-pubkey>"],
["i", "bitcoin:tx:<txid>"],
["amount", "<sats>"],
["alt", "On-chain zap: 25000 sats"]
]
}
Content
The content field is a human-readable comment from the sender (may be empty). It is NOT a zap request JSON (unlike NIP-57 kind 9735).
Tags
| Tag | Required | Description |
|---|---|---|
i |
Yes | NIP-73 external content identifier. MUST be bitcoin:tx:<txid> where <txid> is a 64-char lowercase hex Bitcoin transaction ID. |
p |
Yes | 32-byte hex pubkey of the zap recipient (the author being paid). |
amount |
Yes | Amount paid to the recipient in satoshis (decimal integer). This is the sum of outputs in the tx that paid the recipient's derived Taproot address — not the total tx value. |
e |
If zapping an event | 32-byte hex ID of the event being zapped. Include a relay hint as the 3rd element where possible. |
a |
If zapping an addressable event | Addressable event coordinate <kind>:<pubkey>:<d-tag>. Used instead of (or alongside) e for kinds 30000–39999. |
alt |
Yes | NIP-31 human-readable fallback. |
If neither e nor a is present, the zap targets the recipient's profile (i.e. a tip to the pubkey, not to a specific event).
Publishing Flow
- Sender builds a Bitcoin transaction paying the recipient's derived Taproot address (
nostrPubkeyToBitcoinAddress(recipientPubkey)). - Sender broadcasts the transaction to the Bitcoin network and obtains the
txid. - Sender signs and publishes a kind 8333 event referencing that
txidwith the appropriatee/a/ptags. - The event is published after broadcast; the txid is already final at that point.
Client Behavior
Querying onchain zaps for an event:
{ "kinds": [8333], "#e": ["<target-event-id>"], "limit": 100 }
For addressable events, use "#a": ["<kind>:<pubkey>:<d-tag>"] instead. For profile-level zaps, use "#p": ["<pubkey>"].
Verification (REQUIRED before trusting amounts):
Clients MUST verify a kind 8333 event on-chain before counting it toward a zap total or displaying its amount. The amount tag is self-reported by the sender and would otherwise be trivially spoofable. To verify:
- Extract the txid from the
itag. - Fetch the transaction from a Bitcoin data source (e.g. a mempool.space-compatible Esplora API).
- Derive the recipient's expected Taproot address from the
ptag pubkey. - Sum the values of all outputs in the transaction that pay that address. This is the verified amount. Change outputs paying back to the sender's derived Taproot address MUST NOT be counted toward the verified amount — only outputs to the recipient.
- If the verified amount is 0, the event SHOULD be discarded.
- If the sender's
amounttag exceeds the verified amount, clients MAY discard the event or MAY display the smaller verified amount (capping). Clients MUST NOT display or count the claimed amount when it exceeds the verified amount. - Unconfirmed transactions MAY be displayed as pending; clients MAY require confirmation before counting them toward public totals. Because unconfirmed transactions can be evicted (RBF, double-spend), clients SHOULD either exclude them from aggregate zap totals or clearly label them as pending.
Sender/recipient identity: Clients SHOULD reject events where the sender's pubkey (event.pubkey) equals the recipient pubkey from the p tag. Self-zaps are trivial to fabricate (the sender already controls the destination address) and contribute nothing meaningful to zap totals.
Deduplication: Clients SHOULD deduplicate events that reference the same txid (an attacker could publish many events pointing at one real transaction). One kind 8333 event per (txid, target) pair is canonical — when multiple events reference the same txid for the same target, the earliest is preferred.
Network scope: This specification applies to Bitcoin mainnet only. Testnet, signet, and other networks are out of scope; addresses and txids on those networks MUST NOT be used in kind 8333 events.
Comparison with NIP-57 (Lightning Zaps)
| Aspect | NIP-57 (kind 9735) | This spec (kind 8333) |
|---|---|---|
| Settlement | Lightning Network | Bitcoin L1 |
| Invoice / payment | LNURL + BOLT-11 invoice | Raw Bitcoin tx |
| Event issuer | Recipient's LNURL provider | Sender |
| Availability | Requires lud06/lud16 on recipient profile |
Always available (every Nostr pubkey has a derived Taproot addr) |
| Verification | Recipient zap-provider pubkey + bolt11 amount | On-chain tx verified against derived recipient address |
| Finality | Instant | Confirms in ~10 min (mempool first) |
| Fees | Sub-satoshi typical | Significant at low amounts |
The two zap kinds are complementary. Clients SHOULD sum verified amounts from both kinds when displaying total zap stats for a post or profile.
Kind 36767: Theme Definition
Summary
Addressable event kind for publishing shareable custom UI themes. A single user may publish multiple themes, each identified by a unique d tag.
A theme consists of colors, optional fonts, and an optional background. Colors are stored in c tags, fonts in f tags, and background in a bg tag.
Event Structure
{
"kind": 36767,
"content": "",
"tags": [
["d", "mk-dark-theme"],
["c", "#1a1a2e", "background"],
["c", "#e0e0e0", "text"],
["c", "#6c3ce0", "primary"],
["f", "Inter", "https://example.com/inter.woff2", "body"],
["f", "Playfair Display", "https://example.com/playfair.woff2", "title"],
["bg", "url https://example.com/bg.jpg", "mode cover", "m image/jpeg", "dim 1920x1080"],
["title", "MK Dark Theme"],
["alt", "Custom theme: MK Dark 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, e.g. "mk-dark-theme" |
c |
Yes (×3) | Hex color with marker. See Color Tags. |
f |
No | Font declaration. See Font Tag. |
bg |
No | Background media. See Background Tag. |
title |
Yes | Human-readable theme name |
alt |
Yes | NIP-31 human-readable fallback |
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 (this is how editing works).
Kind 16767: Active Profile Theme
Summary
Replaceable event that represents the user's currently active profile theme. Only one per user. When other users visit a profile, they query this kind to determine what theme to display.
Event Structure
{
"kind": 16767,
"content": "",
"tags": [
["c", "#1a1a2e", "background"],
["c", "#e0e0e0", "text"],
["c", "#6c3ce0", "primary"],
["f", "Inter", "https://example.com/inter.woff2", "body"],
["f", "Playfair Display", "https://example.com/playfair.woff2", "title"],
["bg", "url https://example.com/bg.jpg", "mode cover", "m image/jpeg"],
["title", "MK Dark Theme"],
["alt", "Active profile theme"]
]
}
Content
The content field is unused and MUST be an empty string ("").
Tags
| Tag | Required | Description |
|---|---|---|
c |
Yes (×3) | Hex color with marker. See Color Tags. |
f |
No | Font declaration. See Font Tag. |
bg |
No | Background media. See Background Tag. |
title |
No | Human-readable name for the theme |
alt |
Yes | NIP-31 human-readable fallback |
Client Behavior
- When visiting a profile, clients query
{ kinds: [16767], authors: [pubkey], limit: 1 }to get the active theme. - Clients read the
ctags to extract colors,ftags for fonts, andbgtag for the background. - Setting a new active theme publishes a new kind 16767 event (replacing the old one).
- To remove the active theme, publish a kind 5 deletion event targeting kind 16767.
Shared Tag Definitions
The following tag definitions apply to both kind 36767 and kind 16767.
Color Tags
Format: ["c", "#rrggbb", "<marker>"]
| Index | Required | Description |
|---|---|---|
| 0 | Yes | Tag name: "c" |
| 1 | Yes | Lowercase 6-digit hex color code including the # sign (e.g. "#ff0000") |
| 2 | Yes | Color role marker: one of "primary", "text", or "background" |
- All three markers (
"primary","text","background") MUST be present. - Only one
ctag per marker is allowed.
Font Tag
Format: ["f", "<family>", "<url>", "<role>"]
| Index | Required | Description |
|---|---|---|
| 0 | Yes | Tag name: "f" |
| 1 | Yes | CSS font-family name (e.g. "Inter") |
| 2 | Yes | Direct URL to a font file (.woff2, .ttf, .otf) |
| 3 | Yes | Font role: "body" or "title" |
Roles:
| Role | Applies to |
|---|---|
"body" |
All text globally (body, headings, UI elements) |
"title" |
The user's profile display name |
Rules:
- The
ftag is optional on the event. - At most one
ftag per role is allowed (i.e. one body font and one title font). - The
"body"font tag MUST be ordered before the"title"font tag. This ensures backward-compatible clients that only read the firstftag will pick up the body font. - If the URL fails to load, the client SHOULD fall back to a default font gracefully.
- Clients that do not recognize a role SHOULD ignore that
ftag. - Legacy events with an
ftag that has no role marker (only 3 elements) SHOULD be treated as"body". - Variable font files (covering multiple weights in a single file) are preferred.
Background Tag
The bg tag uses an imeta-style variadic format where each entry (after the tag name) is a space-delimited key/value pair.
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", "image/png", "video/mp4") |
dim |
No | Dimensions in pixels: "<width>x<height>" (e.g. "1920x1080") |
blurhash |
No | Blurhash placeholder string for progressive loading |
- At most one
bgtag is allowed per event. - Clients MAY choose not to render video backgrounds for performance or bandwidth reasons.
- Unknown keys SHOULD be ignored for forward compatibility.
Kind 16769: Profile Tabs
Summary
Replaceable event kind for publishing a user's custom profile page tabs. Exactly one event per user (no d tag). Each tab defines a Nostr filter (NIP-01) that clients execute to populate the tab's content.
Visitors who load a profile fetch this event to display the custom tabs alongside the standard Posts / Media / Likes / Wall tabs.
Event Structure
{
"kind": 16769,
"content": "",
"tags": [
["var", "$follows", "p", "a:3:$me:"],
["tab", "Bitcoin Posts", "{\"kinds\":[1],\"authors\":[\"$me\"],\"search\":\"bitcoin\"}"],
["tab", "Feed", "{\"kinds\":[1,6],\"authors\":[\"$follows\"],\"limit\":40}"],
["alt", "Custom profile tabs"]
]
}
Content
The content field is unused and MUST be an empty string ("").
Tags
| Tag | Format | Description |
|---|---|---|
tab |
["tab", "<label>", "<filterJSON>"] |
One tag per custom tab. Order defines display order. |
var |
["var", "<$name>", "<tag>", "<pointer>"] |
Variable definition. See Variable Tags. |
alt |
["alt", "Custom profile tabs"] |
NIP-31 human-readable fallback. Required. |
Tab Filter JSON
The third element of each tab tag is a JSON-encoded NIP-01 filter object, optionally extended with the NIP-50 search field. Variable placeholders (strings starting with $) may appear wherever a string value is expected.
{
"kinds": [1],
"authors": ["$me"],
"search": "bitcoin",
"limit": 20
}
Supported filter fields: ids, authors, kinds, #<tag> (e.g. #t, #e, #p), since, until, limit, search.
Variable Tags
Variable tags define named placeholders that are resolved before the filter is executed. Each var tag extracts tag values from a referenced Nostr event.
Format: ["var", "$name", "<tag-to-extract>", "<event-pointer>"]
| Index | Description |
|---|---|
| 0 | Tag name: "var" |
| 1 | Variable name, starting with $ (e.g. "$follows") |
| 2 | Tag name to extract values from in the referenced event (e.g. "p") |
| 3 | Event pointer: e:<event-id> for a specific event, or a:<kind>:<pubkey>:<d-tag> for an addressable/replaceable event coordinate. Variables like $me may appear in the pubkey position. |
Example — extract follow list pubkeys:
["var", "$follows", "p", "a:3:$me:"]
This means: fetch the kind 3 event authored by $me, extract all p tag values, and bind them to $follows.
Reserved Variable: $me
The $me variable is the only runtime-provided variable. It resolves to the profile owner's pubkey (the author of the kind 16769 event). It does not require a var tag definition.
Variable Resolution
When a variable appears in a filter field that expects an array (e.g. authors, ids, #p), the variable is expanded in-place (spliced into the array). Literal values may be mixed with variables.
["tab", "Mixed", "{\"authors\":[\"$follows\",\"abc123...\"],\"kinds\":[1]}"]
After resolution (assuming $follows = ["pk1", "pk2"]):
{"authors": ["pk1", "pk2", "abc123..."], "kinds": [1]}
Behavior
- To add or update tabs: publish a new kind 16769 event with all current
tabandvartags. - To clear all tabs: publish a kind 16769 event with no
tabtags (onlyalt). - Clients MUST filter by
authors: [pubkey]when querying to prevent spoofing. vartags are shared across alltabtags in the same event.
Kind 0 Extension: Avatar Shape
Summary
An optional shape property on kind 0 (profile metadata) that controls how the user's avatar is masked/clipped when displayed. The value is an emoji character whose silhouette is used as a mask over the avatar image. When absent, the avatar renders as the standard circle.
Metadata Field
The shape field is added to the JSON content of a kind 0 event alongside standard fields like name, picture, etc. Its value is a single emoji character (including multi-codepoint emoji such as flags, ZWJ sequences, and skin-tone variants).
{
"kind": 0,
"content": "{\"name\":\"Luna\",\"picture\":\"https://example.com/luna.jpg\",\"shape\":\"🌙\"}"
}
Client Behavior
- When
shapeis absent, clients SHOULD render the avatar as a circle (the current universal default). - When
shapeis a valid emoji, clients SHOULD use the emoji's silhouette as an alpha mask over the avatar image. The specific rendering technique is platform-dependent (see below). - When
shapeis set to an unrecognized or invalid value, clients MUST fall back to a circle. This ensures forward compatibility. - The
shapefield is purely cosmetic and has no protocol-level significance. - Clients MAY choose not to support this extension, in which case avatars render as circles as usual.
Community NIP Specifications
The following specifications are maintained by their respective authors. Ditto implements these kinds but does not own the specs. See each link for the full event structure, tags, and client behavior.
Color Moments (Kind 3367)
Author: Chad Curtis Spec: https://gitlab.com/chad.curtis/espy/-/blob/main/NIP.md App: https://espy.you
Color palette posts capturing 3-6 colors from a beautiful moment, optionally accompanied by an emoji and layout preference. Supports horizontal, vertical, grid, star, checkerboard, and diagonal stripe layouts. A form of pre-verbal visual communication through color and emotion.
Birdstar (Kinds 2473, 12473, 30621)
Author: Alex Gleason Spec: https://gitlab.com/alexgleason/birdstar/-/blob/main/NIP.md App: https://birdstar.app
Birdstar merges Birdsong Spotter (a bird-by-ear checklist) and Starpoint (an interactive sky map with community constellations) into a single client.
- Kind 2473 — Bird Detection. A regular event representing a single identified bird observation. The species is identified by a NIP-73
i/kpair pointing at the species' Wikidata entity URI (e.g.https://www.wikidata.org/entity/Q26825for the American Robin). Thecontentfield holds an optional freeform human note about the detection. Required tags: NIP-31alt, NIP-73i(Wikidata URL) +k(web). Ditto renders detections as a species card with the Wikipedia thumbnail, common/scientific name, and article summary. - Kind 12473 — Birdex. A replaceable event (one per author) indexing every distinct species the author has ever confirmed via kind 2473. Each species is a positional
i/npair — the Wikidata entity URI followed immediately by the scientific binomial name — emitted in chronological order of first detection. Ditto renders a Birdex as a tiled grid of species, each tile showing the Wikipedia thumbnail with the common name overlaid. In feeds, only the most recent few tiles are shown with a "+N" capstone mirroring how kind 3 follow lists preview members; the post-detail page shows every species. - Kind 30621 — Custom Constellation. An addressable event (
dtag) representing a single user-drawn star figure. Eachedgetag (["edge", from, to]) references two Hipparcos catalog numbers as decimal strings — e.g.["edge", "32349", "37279"]for Sirius → Procyon. Required tags:d,title,alt, and at least one validedge. Thecontentfield is a freeform description. Ditto renders constellations as a stylized SVG star-map (gnomonically projected onto a tangent plane at the figure's centroid, with stars sized by magnitude) using a bundled Hipparcos catalog that is code-split so the data only loads when a constellation is actually viewed.
Geocaching (Kinds 37516, 7516)
Author: Chad Curtis Spec: https://gitlab.com/chad.curtis/treasures/-/blob/main/NIP-GC.md App: https://treasures.to
NIP-GC defines geocaching on Nostr. Kind 37516 (addressable) is a geocache listing with location (geohash), difficulty/terrain scores, size, and type. Kind 7516 is a found log recording a successful visit. The spec also covers comment logs (kind 1111 via NIP-22), verified finds with cryptographic proof (kind 7517), and cache retirement.
Personal Letters (Kind 8211)
Author: Chad Curtis Spec: https://gitlab.com/chad.curtis/lief/-/blob/main/NIP.md App: https://lief.to
NIP-44 encrypted personal letters with visual stationery, hand-drawn stickers, decorative frames, and custom fonts. Letters render as 5:4 landscape postcards. The privacy model is intentionally postcard-like: sender/recipient metadata is visible, content is encrypted.
Weather Station (Kinds 4223, 16158)
Author: Sam Thomson Spec: https://github.com/nostr-protocol/nips/pull/2163 App: https://weather.shakespeare.wtf Firmware: https://github.com/samthomson/weather-station
Kind 16158 (replaceable) describes a weather station's configuration: name, geohash location, elevation, power source, connectivity, and sensor inventory. Kind 4223 (regular) carries individual sensor readings as 3-parameter tags [sensor_type, value, model], enabling historical queries and cross-station comparison. Each station has its own keypair.
Blobbi Virtual Pet (Kinds 31124, 14919, 14920, 14921, 11125)
Author: Danifra Spec: https://github.com/Danidfra/nostr-pet/blob/production/NIP.md App: https://nostr-pet.vercel.app See also: Blobbi tag schema (Ditto-specific integration details)
NIP-BB defines a virtual pet lifecycle on Nostr. Kind 31124 (addressable) holds the current pet state across three stages (egg, baby, adult) with stats, appearance, and personality traits. Kind 14919 logs individual interactions, kind 14920 records breeding events, kind 14921 stores immutable lifecycle records, and kind 11125 (replaceable) holds the owner's profile with coins, achievements, and inventory.
Kind 11125 content JSON — missions field
The content of kind 11125 is a JSON object. Ditto extends it with a missions field that tracks daily and evolution mission progress:
{
"missions": {
"date": "2026-04-16", // ISO date string for the current daily mission set
"daily": [ /* Mission[] */ ],
"evolution": [ /* Mission[] — active hatch/evolve tasks, cleared on stage transition */ ],
"rerolls": 2 // remaining daily mission rerolls
}
// ...other profile fields (coins, achievements, inventory, etc.)
}
Each Mission is either a TallyMission ({ id, target, count }) or an EventMission ({ id, target, events: string[] }) where events contains Nostr event IDs that satisfy the mission. Evolution missions are populated when incubation or evolution begins and cleared when the stage transition completes or is cancelled.
Music Tracks & Playlists
Kind 36787: Music Track
An addressable event containing metadata about an audio file. Full spec maintained externally.
Required tags: d, title, artist, url, t (with value "music")
Optional tags: image, video, album, track_number, released, duration, format, bitrate, sample_rate, language, explicit, zap, alt
Kind 34139: Music Playlist
An addressable event containing an ordered list of music track references.
Required tags: d, title, alt
Optional tags: description, image, a (track references), t, public, private, collaborative
Track references use a tags in the format ["a", "36787:<pubkey>:<d-tag>"].
Albums (Convention)
Albums are represented as kind 34139 playlist events with a ["t", "album"] tag. This reuses the existing playlist infrastructure while allowing clients to distinguish albums from user-curated playlists.
Additional optional tags for albums:
released— ISO 8601 release date (e.g."2024-06-15")label— Record label name
Example album event:
{
"kind": 34139,
"content": "Debut studio album featuring 12 tracks of ambient electronic music.",
"tags": [
["d", "endless-summer-2024"],
["title", "Endless Summer"],
["image", "https://cdn.blossom.example/img/album-art.jpg"],
["t", "album"],
["t", "electronic"],
["t", "ambient"],
["released", "2024-06-15"],
["label", "Sunset Records"],
["a", "36787:abc123...:track-1"],
["a", "36787:abc123...:track-2"],
["a", "36787:abc123...:track-3"],
["alt", "Album: Endless Summer by The Midnight Collective"]
]
}
Client behavior:
- Clients detect albums by checking for a
ttag with value"album"(case-insensitive) - Albums display release date and label information when available
- Track ordering follows the order of
atags in the event - The same detail view, playback, and commenting features apply to both albums and playlists