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

Custom Emoji

Put your own emoji images into notes, names, reactions, and statuses with one simple tag and a :shortcode:.

1 Overview

Standard Unicode emoji are the same everywhere. Custom emoji are images that a user picks. This NIP lets an event carry its own emoji images. The author writes a shortcode like :soapbox: in the text. A tag maps the shortcode to an image URL.

The mechanism is one tag: emoji. Any client can read it. A client that supports this NIP replaces each :shortcode: with the image. A client that does not support it shows the plain :shortcode: text. Nothing breaks.

Custom emoji work in five event kinds: user metadata, text notes, reactions, comments, and user statuses. Section 4 lists them. An optional fourth tag element can point to the emoji set the emoji comes from.

Hint!

Users of Slack, Discord, or the fediverse already know this pattern. The :shortcode: syntax is the same. The difference on Nostr: each event carries its own shortcode-to-image map, so no server has to host a shared emoji list.

2 The emoji Tag

Add one emoji tag per custom emoji that the event uses. An event may include one or more of these tags. The tag has this form:

Wire format - emoji tag
["emoji", <shortcode>, <image-url>, <emoji-set-address>]
Tag element reference
ElementRequiredRule
shortcodeyesThe name of the emoji. It must contain only alphanumeric characters, hyphens, and underscores.
image-urlyesA URL to the image file of the emoji.
emoji-set-addressnoAn address pointer in the form kind:pubkey:d-tag. It points to the kind 30030 emoji set (NIP-51) that the emoji belongs to.

In the text of the event, the author writes the shortcode between two colons: :shortcode:. The colons are markers only. They do not appear in the tag.

Warning!

Validate shortcodes. A shortcode with spaces, colons, or other symbols is invalid. Only letters, digits, -, and _ are allowed. A loose parser can misread normal text such as timestamps (12:30:00) as emoji.

3 Emojification

To emojify means to replace shortcodes with images. For each emoji tag, a client should parse :shortcode: patterns in the event and display the custom emoji image in their place. Shortcodes without a matching tag stay as plain text. Regular Unicode emoji in the same text are untouched.

Clients may also help authors write custom emoji. A client may let the user insert a :shortcode: identifier in the event. The client then adds the matching emoji tags before it signs and publishes the event.

content "gm :soapbox:" emoji tags soapbox → https://…png Emojify match :name: Rendered note gm [img]
Fig. 30-1 — The emojify pipeline. The client joins the text with the tag map and renders each shortcode as an inline image.

The optional fourth element links an emoji back to its source collection. An emoji set is an addressable kind 30030 event defined in NIP-51. The address lets a client offer "add this set" to the reader:

emoji tag 4th element: 30030:pubkey:blobcats kind 30030 event emoji set "blobcats" (NIP-51) resolves to
Fig. 30-2 — Emoji set pointer. The address kind:pubkey:d-tag names the set the emoji belongs to.

4 Supported Kinds

This NIP defines no new kind. It adds the emoji tag to five existing kinds. Each kind emojifies specific fields:

Kinds that support custom emoji
KindDefined inEmojified fields
0NIP-01 user metadataThe name and about fields inside the JSON content.
1NIP-10 text noteThe content string.
7NIP-25 reactionThe content string. A reaction can be one custom emoji.
1111NIP-22 commentThe content string.
30315NIP-38 user statusThe status text in content.
Tech Note

The source spec lists kind 30315 as supported but gives it no section and no example. The other four kinds each get one. Assume the same rule as kind 1: emojify the content string.

5 Worked Examples

The four events below come from the source spec. Each shows one supported kind. Long hex keys are shortened for print.

Kind 0 — metadata. The display name ends with :soapbox:. A supporting client renders the name with the image after the text:

Example - kind 0 with an emojified name
{
  "kind": 0,
  "content": "{\"name\":\"Alex Gleason :soapbox:\"}",
  "tags": [
    ["emoji", "soapbox", "https://gleasonator.com/emoji/Gleasonator/soapbox.png"]
  ],
  "pubkey": "79c2cae1…b820ff6",
  "created_at": 1682790000
}

Kind 1 — text note. Three custom emoji mix with one Unicode emoji. The ablobcatrainbow tag carries the optional emoji-set address; the other two do not:

Example - kind 1 with three custom emoji
{
  "kind": 1,
  "content": "Hello :gleasonator: 😂 :ablobcatrainbow: :disputed: yolo",
  "tags": [
    ["emoji", "ablobcatrainbow",
      "https://gleasonator.com/emoji/blobcat/ablobcatrainbow.png",
      "30030:79c2cae1…b820ff6:blobcats"],
    ["emoji", "disputed", "https://gleasonator.com/emoji/Fun/disputed.png"],
    ["emoji", "gleasonator", "https://gleasonator.com/emoji/Gleasonator/gleasonator.png"]
  ],
  "pubkey": "79c2cae1…b820ff6",
  "created_at": 1682630000
}

Kind 1111 — comment. A shortcode may contain underscores. The tag points to the "Hyves" emoji set:

Example - kind 1111 with an emoji-set address
{
  "kind": 1111,
  "content": "Let's party! :hyves_banaan:",
  "tags": [
    ["emoji", "hyves_banaan",
      "https://relay.nyves.nl/8408b236…bd2ebf.gif",
      "30030:9919981d…a306b9:Hyves"]
  ],
  "pubkey": "79c2cae1…b820ff6",
  "created_at": 1682630000
}

Kind 7 — reaction. The whole content is a single shortcode. The reaction renders as one image:

Example - kind 7 reaction as one custom emoji
{
  "kind": 7,
  "content": ":dezh:",
  "tags": [
    ["emoji", "dezh", "https://raw.githubusercontent.com/dezh-tech/brand-assets/main/dezh/logo/black-normal.svg"]
  ],
  "pubkey": "79c2cae1…b820ff6",
  "created_at": 1682630000
}

6 Version History

The number 30 was used twice. A short "Event Copy" proposal held this slot in March 2023 and was dropped within a day. Alex Gleason then claimed the number for Custom Emoji. Notable changes, newest first:

  • 20262026-08Added kind 1111 comments (NIP-22) to the supported kinds.
  • 20262026-03Shortcode rule now allows hyphens. The optional emoji-set address became the 4th tag element.
  • 20242024-09Added kind 7 reactions (NIP-25): a reaction can be a custom emoji.
  • 20242024-01The supported-kinds list became explicit: 0, 1, 30315 at the time.
  • 20232023Underscores allowed in shortcodes; author names removed from all NIP files.
  • Origin2023-04Alex Gleason published "NIP-30: Custom Emoji", replacing the dropped Event Copy draft.
Tech Note

The manifest lists 2023-03-29 as the creation date. That commit belongs to the dropped Event Copy proposal, not to Custom Emoji. The first Custom Emoji commit is dated 2023-04-29. This page uses the later date.

Original Proposal - Credits

AuthorAlex Gleason
First commit2023-04-29 — “NIP-30: Custom Emoji”
Statusdraft - optional — clients choose whether to render custom emoji
Source30.md on GitHub - full change history

7 See Also

  • NIP-01 — the event and tag structure that the emoji tag builds on; kind 0 metadata.
  • NIP-51 — kind 30030 emoji sets, the collections the optional address points to.
  • NIP-25 — kind 7 reactions, which can be a single custom emoji.
  • NIP-22 — kind 1111 comments, emojified like text notes.
  • NIP-38 — kind 30315 user statuses, emojified status text.
  • NIP-10 — kind 1 text notes, the most common home for custom emoji.