NIPs by PolleramaCommunity NIPs, surfaced by trustConnect
npub1q3sle0kvfse...

Bird Detection & Birdex

Published Jun 28, 2026
kind 2473 · Bird Detectionkind 12473 · Birdex

Bird Detection & Birdex

This NIP describes birding events on Nostr.

Kind 2473 — Bird Detection

A regular event representing a single identified bird observation. Regular events (1000 ≤ kind < 10000) are stored permanently by relays and are not deduplicated.

The schema deliberately relies on existing NIPs (NIP-31 alt, NIP-73 i) rather than inventing parallel vocabulary, so that non-birding clients can still display and aggregate detections usefully.

Rationale

A bird detection is an observation log entry: a timestamped, immutable record that "species X was heard at time T", optionally annotated with a free-form human note.

We reviewed existing NIPs before introducing a new kind:

  • NIP-52 (Calendar Events) models planned events at specific future

times, not observation logs. RSVPs and addressability make no sense for a detection.

  • NIP-32 (Labeling) labels another event — it has no standalone meaning.

A detection is a primary artifact, not a label applied to something else.

  • Kind 1 text notes can contain "I heard a robin!" but provide no

structured data, so other clients cannot aggregate or filter by species.

  • The unofficial Geocaching kinds (7516/7517) follow a similar

observation-log pattern but are tightly coupled to geocache listings.

No existing kind covers a structured, standalone observation log, so we define a new regular event kind.

content

Free-form human-readable note about the detection. MAY be empty.

Examples: "", "Heard from my balcony near the oak tree."

Structured data MUST be placed in tags, not in content.

Tags

Required
  • alt (NIP-31) — human-readable summary, e.g.

"Bird detection: American Robin (Turdus migratorius)". Lets clients that don't implement this NIP still render something meaningful.

  • i (NIP-73) — an external ID pointing at the species' **Wikidata

entity URI**. This is the canonical identity of the species, the primary aggregation key, and the only species identifier in the event:

``jsonc ["i", "https://www.wikidata.org/entity/Q26825"] ``

Wikidata is language-neutral: a single Q-id designates the species across every Wikipedia edition, taxonomy database, and localized common name. A client rendering the event in any language can follow the entity URI to get labels, images, and the sitelink to its preferred Wikipedia edition.

Requirements:

  • The URL MUST match https://www.wikidata.org/entity/Q<digits> exactly:

https scheme, host www.wikidata.org, path /entity/Q<digits>, no fragment, no query string, no trailing slash.

  • The Q-id SHOULD resolve to a taxon-like entity (a species, subspecies,

or similarly specific rank). Publishers SHOULD NOT emit a detection with a Q-id that has no corresponding taxon.

Deviation from NIP-73. NIP-73 pairs every i tag with a k tag naming the ID kind ("web", "isbn", "geo", etc.) so that clients can query "all events with any external ID of kind X". Birdstar deliberately omits the k tag: every i tag on a kind 2473 event is known by the kind contract to be a Wikidata entity URI, so a k tag would carry no information beyond what the i value's URL shape already reveals. Queries over these events filter by the specific Wikidata URI (or by kinds: [2473]), never by the generic #k: ["web"] bucket which would return every blog post, book, and podcast on the relay. The trade-off — Birdstar detections won't show up in generic NIP-73 web-content aggregators — is intentional; a species Q-id is not a webpage in the sense those aggregators care about.

  • n — the species' scientific (binomial) name as a single string,

e.g. "Turdus migratorius". Lets clients render the detection without round-tripping Wikidata just to get a species label.

``jsonc ["n", "Turdus migratorius"] ``

The scientific name is advisory, not authoritative — the i tag is the canonical species identity. If the two disagree (e.g. because a taxon was renamed between publishing and rendering), clients SHOULD trust the i tag's Q-id and treat n as a stale label.

Optional
  • g (NIP-52) — coarse geohash of where the detection was made. Opt-in

only: Birdstar publishes this tag exclusively when the user has explicitly enabled "Publish location" in Settings. Off by default.

``jsonc ["g", "dp3"] ``

Birdstar emits a length-3 geohash (~156 km × 156 km cells), which is the coarsest precision still useful for region-scale aggregation without revealing the observer's neighborhood. Clients receiving a detection MAY display it on a map, use it to filter "detections near me", or ignore it entirely; the rest of the event is self-contained without it.

The g tag value MUST match /^[0-9bcdefghjkmnpqrstuvwxyz]+$/ — the standard geohash base-32 alphabet (digits 0-9 plus the consonants b-z with a, i, l, o removed). Publishers SHOULD NOT emit geohashes finer than length 8 (~20 m) on a detection event — the act of stamping a GPS-precise coordinate onto a signed, public, permanent record is almost never what the observer intends.

Publishers SHOULD NOT attach a per-event numeric confidence to a detection. Publishing a kind 2473 event IS the publisher's confidence signal: the act of authoring and signing the event asserts that the observation was reliable enough to commit to the record.

Example

{
  "kind": 2473,
  "content": "Heard from my balcony around 7am — very clear song.",
  "tags": [
    ["alt", "Bird detection: American Robin (Turdus migratorius)"],
    ["i", "https://www.wikidata.org/entity/Q26825"],
    ["n", "Turdus migratorius"]
  ]
}

With the optional g tag, when the user has enabled location publishing in Settings:

{
  "kind": 2473,
  "content": "",
  "tags": [
    ["alt", "Bird detection: American Robin (Turdus migratorius)"],
    ["i", "https://www.wikidata.org/entity/Q26825"],
    ["n", "Turdus migratorius"],
    ["g", "dp3"]
  ]
}

Query Patterns

All detections of a given species across the network:

{
  "kinds": [2473],
  "#i": ["https://www.wikidata.org/entity/Q26825"]
}

Dropping the kinds filter broadens this to all Nostr content about the species — bird detections, comments, long-form posts, etc. — since the Wikidata entity URI is a shared NIP-73 identifier:

{ "#i": ["https://www.wikidata.org/entity/Q26825"] }

All detections by a specific observer:

{ "kinds": [2473], "authors": ["<hex-pubkey>"], "limit": 50 }

Validation

Clients SHOULD ignore an event as a bird detection if:

  • kind !== 2473
  • No i tag with a normalized https://www.wikidata.org/entity/Q<digits>

URL is present

Publishing

Birdstar publishes detections automatically for logged-in users as birds are identified, so that a user's sightings are preserved across sessions and devices via their own Nostr relays.

To avoid spamming relays when the same bird is heard repeatedly, publishers SHOULD apply a per-species cooldown: once a detection event has been published for a given i tag, no new event for that same URL should be published by the same author for at least 10 minutes.

Detections from logged-out users are never published.

Detections heard while offline are not lost. When a publish fails (no connection, relay timeout, etc.) the detection is persisted to a local queue and retried when connectivity returns, repeatedly if necessary, until the event lands on a relay. The event's created_at always carries the original heard time, so a sighting published hours or days late is still timestamped to when the bird was actually heard — readers should expect kind 2473 events whose created_at precedes their arrival by an arbitrary amount, and SHOULD order detections by created_at rather than receipt time.

Birdstar does not publish any location information on detections by default. The optional g tag is only attached when the user has explicitly enabled "Publish location" in the Birds-mode Settings sheet, and is computed from the same coarse (1°-rounded) lat/lon that drives the birdex's region filter — no additional precision is introduced at publish time.

Deletion

Users can retract a previously published detection by issuing a standard NIP-09 deletion request (kind 5) referencing the detection's event id:

{
  "kind": 5,
  "tags": [
    ["e", "<kind-2473-event-id>"],
    ["k", "2473"]
  ],
  "content": ""
}

Birdstar hides any detection whose id appears in an e tag of a kind 5 event authored by the same pubkey.


Kind 12473 — Birdex

A replaceable event (kind 12473, chosen as 1 prefixed onto the 2473 detection kind for mnemonic kinship) representing the author's Birdex: the cumulative set of every distinct bird species they have ever published a kind 2473 detection for.

Replaceable events (10000 ≤ kind < 20000) are deduplicated by relays on pubkey + kind, so each author has at most one Birdex on the network at any time. Republishing with a newer created_at replaces the prior copy.

Rationale

Kind 2473 detections are the permanent log; the Birdex is the index derived from them. The log-vs-index split is deliberate:

  • Without the Birdex, reconstructing a user's species list requires

paginating their entire kind 2473 history across all relays — expensive for clients, unreliable when some relays drop old events, and impossible to express as a single filter.

  • With it, any client can fetch one replaceable event and render the

user's full species count, first-seen ordering, and profile-page "lifer badges" in a single round-trip.

  • A new kind (rather than a generic list via NIP-51) is warranted

because the entries are tightly constrained (Wikidata taxon URIs only) and the event has domain-specific semantics (first-seen ordering, tied to the kind 2473 author's own detection history).

content

Free-form human-readable description of the Birdex. MAY be empty. Non-birding clients rendering this event SHOULD prefer the alt tag.

Tags

Required
  • alt (NIP-31) — human-readable summary, e.g.

"Birdex: 37 species". Lets clients that don't implement this NIP still render something meaningful.

Species entries

Each species on the Birdex is represented by an i tag (NIP-73) immediately followed by an n tag carrying the scientific name — the same vocabulary used on kind 2473 detections:

["i", "https://www.wikidata.org/entity/Q26825"],
["n", "Turdus migratorius"]

The same URL-shape rules as kind 2473 apply to the i value: https scheme, host www.wikidata.org, path /entity/Q<digits>, no fragment, no query string, no trailing slash. The n value is a free-form single-string scientific name (binomial), advisory only — see the kind 2473 n description for the trust model.

As with kind 2473, the Birdex deliberately omits the k tag that NIP-73 normally pairs with i. See the kind 2473 rationale — every i tag on a Birdex is known by the kind contract to be a Wikidata entity URI, and pairing with k would only add noise.

On positional pairing. Each n tag is paired with the preceding i tag by position in the event's tag array. Publishers MUST emit every species as exactly ["i", "..."] followed immediately by ["n", "..."] with no other tags interleaved between the pair. The pairing is positional rather than keyed because a Wikidata URI is not a unique-enough identifier to use as the n tag's second element without reconstructing most of the i value; positional pairing keeps the wire format terse and the "N species on my Birdex = 2N entries" invariant trivially checkable. Clients that need name-first lookups should build an index once at parse time.

Entry ordering

The i/n pairs MUST be emitted in chronological order of first detection, oldest species first. The position of a species' pair in the tag array is its ordinal rank on the Birdex ("the 7th species I ever identified"). Clients rendering a timeline of an author's birding journey rely on this ordering — it cannot be reconstructed from the replaceable event alone once the underlying kind 2473 events have aged off relays.

Each species MUST appear at most once. Republishing the event to add a newly confirmed species means appending the new i/n pair to the end of the existing tag list, preserving the historical order of all previous entries.

Example

An author whose Birdex holds three species — first a robin, then a cardinal, then a chickadee:

{
  "kind": 12473,
  "content": "",
  "tags": [
    ["alt", "Birdex: 3 species"],
    ["i", "https://www.wikidata.org/entity/Q26825"],      // American Robin
    ["n", "Turdus migratorius"],
    ["i", "https://www.wikidata.org/entity/Q27014"],      // Northern Cardinal
    ["n", "Cardinalis cardinalis"],
    ["i", "https://www.wikidata.org/entity/Q335669"],     // Black-capped Chickadee
    ["n", "Poecile atricapillus"]
  ]
}

Query Patterns

A specific user's Birdex:

{ "kinds": [12473], "authors": ["<hex-pubkey>"], "limit": 1 }

All users whose Birdex includes a given species:

{ "kinds": [12473], "#i": ["https://www.wikidata.org/entity/Q26825"] }

Validation

Clients SHOULD ignore an event as a Birdex if:

  • kind !== 12473
  • It is not authored by the pubkey whose Birdex is being queried

(replaceable events are per-author; the authors filter is the trust boundary — never trust a 12473 event on its content alone).

When parsing species entries, clients SHOULD:

  1. Walk the tag array in order.
  2. For each i tag whose value matches the canonical Wikidata entity

URI regex, take its scientific name from the next tag if that tag is ["n", "<non-empty string>"]. i tags not followed by an n tag are still accepted — the species is known by its Q-id but has no local scientific-name label.

  1. Deduplicate by Wikidata URI, keeping the first occurrence — the

chronologically earliest entry wins.

Publishing

Birdstar publishes the Birdex automatically for logged-in users. The publish flow is tied to kind 2473 detections:

  1. When a kind 2473 detection is about to be published for a species,

check whether that species' Wikidata URI is already present in the author's existing Birdex (loaded via a single kind 12473 query on login).

  1. If absent, publish the kind 2473 detection as normal, then publish a

new kind 12473 event containing every previously-known URI plus the new one appended at the end.

  1. If present, only the kind 2473 event is (re)published subject to the

usual 10-minute cooldown; the Birdex does not change.

This couples Birdex growth to confirmed detections so the Birdex can never diverge from the underlying log: every entry has a corresponding kind 2473 event from the same author.

Deletion

To retract a species from the Birdex, republish the event with that species' i/n pair removed. Because kind 12473 is replaceable, the new event supersedes the old. Separately issuing a NIP-09 deletion on the underlying kind 2473 events is also recommended if the user wants to remove the detection log, not just the Birdex entry.