← All NIPs

NIP-89

Recommended Application Handlers

DraftEvents

When your app meets an event kind it can't show, it can find an app that can: apps announce which kinds they handle (31990) and people recommend them (31989).

At a glance

Status
In use and still allowed to change.
Kinds
Tags
  • a
  • client
  • d
  • ios
  • k
  • latest
  • next
  • web
Last changed
Jun 16, 2026

Try it

Edit the form or the JSON: both stay in sync, the badge says whether the result is valid, and tapping any field explains it.

What to build

How the parts connect: Find an app for a kind

Examples
Valid 1 note

Not signed yet · Demo keys only. These personas' secret keys are public on purpose.

Form
Jan 1, 2025, 12:00 AM UTC

Content

Optional kind-0-style JSON (name, about, picture). If empty, clients use the publisher's profile.

Tags

  1. d Required

    A random or descriptive id for this handler event.

  2. k Required

    An event kind this app can handle. Repeat for several kinds.

  3. web Optional

    Web URL template for opening an entity.

  4. web Optional

    Web URL template for opening an entity.

  5. web Optional

    Web URL template for opening an entity.

  6. ios Optional

    iOS deep-link template.

Add tag

How this NIP works

Step 1 of 6

An unknown kind shows up

Your social client sees, say, a kind 30023 article it can't render. Instead of a dead end, it can look for an app that handles that kind.

In the course

Builds on

Used by

See also

Specification

Specification text is quoted in English from the nostr-protocol/nips repository. Our explanations and the interface are translated. Source on GitHub at commit 0046368

Read the spec923 words, quoted from the repository at commit 0046368.

This NIP describes kind:31989 and kind:31990: a way to discover applications that can handle unknown event-kinds.

Rationale

Nostr's discoverability and transparent event interaction is one of its most interesting/novel mechanics. This NIP provides a simple way for clients to discover applications that handle events of a specific kind to ensure smooth cross-client and cross-kind interactions.

Parties involved

There are three actors to this workflow:

  • application that handles a specific event kind (note that an application doesn't necessarily need to be a distinct entity and it could just be the same pubkey as user A)
    • Publishes kind:31990, detailing how apps should redirect to it
  • user A, who recommends an app that handles a specific event kind
    • Publishes kind:31989
  • user B, who seeks a recommendation for an app that handles a specific event kind
    • Queries for kind:31989 and, based on results, queries for kind:31990

Events

Recommendation event

{
  "kind": 31989,
  "pubkey": <recommender-user-pubkey>,
  "tags": [
    ["d", <supported-event-kind>],
    ["a", "31990:app1-pubkey:<d-identifier>", "wss://relay1", "ios"],
    ["a", "31990:app2-pubkey:<d-identifier>", "wss://relay2", "web"]
  ],
  // other fields...
}

The d tag in kind:31989 is the supported event kind this event is recommending.

Multiple a tags can appear on the same kind:31989.

The second value of the tag SHOULD be a relay hint. The third value of the tag SHOULD be the platform where this recommendation might apply.

Handler information

{
  "kind": 31990,
  "pubkey": "<application-pubkey>",
  "content": "<optional-kind:0-style-metadata>",
  "tags": [
    ["d", <random-id>],
    ["k", <supported-event-kind>],
    ["latest", "35128:<application-pubkey>:<site-d-identifier>", "wss://relay1"],
    ["next", "35128:<application-pubkey>:<next-site-d-identifier>", "wss://relay1"],
    ["web", "https://..../a/<bech32>", "nevent"],
    ["web", "https://..../p/<bech32>", "nprofile"],
    ["web", "https://..../e/<bech32>"],
    ["ios", ".../<bech32>"]
  ],
  // other fields...
}
  • content is an optional metadata-like stringified JSON object, as described in NIP-01. This content is useful when the pubkey creating the kind:31990 is not an application. If content is empty, the kind:0 of the pubkey should be used to display application information (e.g. name, picture, web, LUD16, etc.)
  • k tags' value is the event kind that is supported by this kind:31990. Using a k tag(s) (instead of having the kind of the d tag) provides:
    • Multiple k tags can exist in the same event if the application supports more than one event kind and their handler URLs are the same.
    • The same pubkey can have multiple events with different apps that handle the same event kind.
  • App descriptor events SHOULD tag or otherwise reference related site manifest events when applicable, so clients can discover the deployed site manifest for an application directly from the upstream app descriptor.
  • For web applications, kind:31990 events SHOULD include latest and next tags referencing related nsite manifests when applicable. These tags use the same shape as an a tag: the second element is <kind>:<pubkey>:<d-tag> and the third element is an optional relay hint. latest SHOULD reference the current site manifest for the application, while next SHOULD reference the next site manifest intended for rollout or upgrade.
  • bech32 in a URL MUST be replaced by clients with the NIP-19-encoded entity that should be loaded by the application.

Multiple tags might be registered by the app, following NIP-19 nomenclature as the second value of the array.

A tag without a second value in the array SHOULD be considered a generic handler for any NIP-19 entity that is not handled by a different tag.

Client tag

When publishing events, clients MAY include a client tag. Identifying the client that published the note. This tag is a tuple of name, address identifying a handler event and, a relay hint for finding the handler event. This has privacy implications for users, so clients SHOULD allow users to opt-out of using this tag.

{
  "kind": 1,
  "tags": [
    ["client", "My Client", "31990:app1-pubkey:<d-identifier>", "wss://relay1"]
  ]
  // other fields...
}

User flow

A user A who uses a non-kind:1-centric nostr app could choose to announce/recommend a certain kind-handler application.

When user B sees an unknown event kind, e.g. in a social-media centric nostr client, the client would allow user B to interact with the unknown-kind event (e.g. tapping on it).

The client MIGHT query for the user's and the user's follows handler.

Example

User A recommends a kind:31337-handler

User A might be a user of Zapstr, a kind:31337-centric client (tracks). Using Zapstr, user A publishes an event recommending Zapstr as a kind:31337-handler.

{
  "kind": 31989,
  "tags": [
    ["d", "31337"],
    ["a", "31990:1743058db7078661b94aaf4286429d97ee5257d14a86d6bfa54cb0482b876fb0:abcd", <relay-url>, "web"]
  ],
  // other fields...
}

User B interacts with a kind:31337-handler

User B might see in their timeline an event referring to a kind:31337 event (e.g. a kind:1 tagging a kind:31337).

User B's client, not knowing how to handle a kind:31337 might display the event using its alt tag (as described in NIP-31). When the user clicks on the event, the application queries for a handler for this kind:

["REQ", <id>, { "kinds": [31989], "#d": ["31337"], "authors": [<user>, <users-contact-list>] }]

User B, who follows User A, sees that kind:31989 event and fetches the a-tagged event for the app and handler information.

User B's client sees the application's kind:31990 which includes the information to redirect the user to the relevant URL with the desired entity replaced in the URL.

Alternative query bypassing kind:31989

Alternatively, users might choose to query directly for kind:31990 for an event kind. Clients SHOULD be careful doing this and use spam-prevention mechanisms or querying high-quality restricted relays to avoid directing users to malicious handlers.

["REQ", <id>, { "kinds": [31990], "#k": [<desired-event-kind>], "authors": [...] }]