Skip to main content

Unicode Emoji API

REAL DATA

All 3944 fully-qualified Unicode 17.0 emoji with groups, CLDR keywords and code points — plus grapheme-correct emoji counting for any text.

Authoritative reference data or standards computation

Base URL
/api/emoji
Capabilities
5 routes Seedable
Last updated
Data sources · 2

GET /api/emoji

Seeded sample of the fully-qualified set. Filters narrow the pool; seed fixes the order forever.

Live requestRuns against the public API
No key required
GET/api/emoji

Request parameters

Only emoji in this top-level Unicode group, as a URL-safe slug (smileys-emotion, people-body, animals-nature, food-drink, travel-places, activities, objects, symbols, flags). Records return Unicode's official group name.

Only emoji in this Unicode subgroup, e.g. face-smiling. 98 values; GET /api/emoji/groups lists them all. An unknown subgroup is a 400, never a silent empty list.

Only emoji introduced in exactly this emoji release.

Only emoji introduced at or before this emoji release — the practical filter for older client fonts.

Include the 2030 skin-tone variants. Off by default, which leaves the 1914 distinct emoji; on gives all 3944.

Include zero-width-joiner sequences (families, professions, flags such as 🏳️‍🌈). Set false for single-emoji sequences only.

Advanced response options7 options

Limit the number of returned records (1–100). Defaults to 20.

Deterministic output: the same seed always returns the same records. Omit for random (the used seed is echoed in meta.seed).

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Response format: json envelope, ndjson (one record per line) or csv.

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/emoji"
const res = await fetch("https://randomapi.dev/api/emoji");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/emoji").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/emoji"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 6
group enum

Only emoji in this top-level Unicode group, as a URL-safe slug (smileys-emotion, people-body, animals-nature, food-drink, travel-places, activities, objects, symbols, flags). Records return Unicode's official group name.

default: any
allowed: smileys-emotion | people-body | animals-nature | food-drink | travel-places | activities | objects | symbols | flags | any
example: group=food-drink
subgroup string

Only emoji in this Unicode subgroup, e.g. face-smiling. 98 values; GET /api/emoji/groups lists them all. An unknown subgroup is a 400, never a silent empty list.

allowed: ≤ 40
example: subgroup=animal-mammal
version enum

Only emoji introduced in exactly this emoji release.

default: any
allowed: 0.6 | 0.7 | 1.0 | 2.0 | 3.0 | 4.0 | 5.0 | 11.0 | 12.0 | 12.1 | 13.0 | 13.1 | 14.0 | 15.0 | 15.1 | 16.0 | 17.0 | any
example: version=17.0
maxVersion enum

Only emoji introduced at or before this emoji release — the practical filter for older client fonts.

allowed: 0.6 | 0.7 | 1.0 | 2.0 | 3.0 | 4.0 | 5.0 | 11.0 | 12.0 | 12.1 | 13.0 | 13.1 | 14.0 | 15.0 | 15.1 | 16.0 | 17.0
example: maxVersion=12.0
skinTones boolean

Include the 2030 skin-tone variants. Off by default, which leaves the 1914 distinct emoji; on gives all 3944.

default: false
example: skinTones=true
zwj boolean

Include zero-width-joiner sequences (families, professions, flags such as 🏳️‍🌈). Set false for single-emoji sequences only.

default: true
example: zwj=false
Universal parameters Shared response and formatting options 7
count int

Limit the number of returned records (1–100). Defaults to 20.

default: 20
allowed: 1 – 100
example: count=3
seed int

Deterministic output: the same seed always returns the same records. Omit for random (the used seed is echoed in meta.seed).

example: seed=42
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=emoji,name
exclude list

Return all fields except these (comma-separated).

example: exclude=keywords
format enum

Response format: json envelope, ndjson (one record per line) or csv.

default: json
allowed: json | ndjson | csv
example: format=csv
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 10
emoji string

The fully-qualified sequence itself, U+FE0F included where the sequence needs it.

example: 👩‍💻

name string

Unicode's name for the sequence, from emoji-test.txt.

example: woman technologist

slug string

URL-safe form of the name; unique across all sequences and accepted by /lookup.

example: woman-technologist

codePoints string[]

Every code point of the sequence in U+ notation, in order.

example: ["U+1F469","U+200D","U+1F4BB"]

group string

Unicode's top-level category, e.g. Smileys & Emotion.

example: People & Body

subgroup string

Unicode's subcategory, e.g. face-smiling.

example: person-role

unicodeVersion string

Emoji release that introduced the sequence — clients with older fonts will show tofu for newer releases.

example: 4.0

hasSkinTone boolean

True when the sequence carries a U+1F3FB–U+1F3FF skin-tone modifier.

example: false

isZwjSequence boolean

True when several emoji are joined with U+200D ZERO WIDTH JOINER.

example: true

keywords string[]

CLDR English search keywords, in CLDR's order — what /search matches on besides the name.

example: ["computer","developer","software","technologist","woman"]

Documented examples

Build-generated requests and complete responses
4
Twenty random emoji (no skin-tone variants)
GET /api/emoji
{
  "data": [
    {
      "emoji": "🤷‍♀️",
      "name": "woman shrugging",
      "slug": "woman-shrugging",
      "codePoints": [
        "U+1F937",
        "U+200D",
        "U+2640",
        "U+FE0F"
      ],
      "group": "People & Body",
      "subgroup": "person-gesture",
      "unicodeVersion": "4.0",
      "hasSkinTone": false,
      "isZwjSequence": true,
      "keywords": [
        "doubt",
        "dunno",
        "guess",
        "idk",
        "ignorance",
        "indifference",
        "knows",
        "maybe",
        "shrug",
        "shrugging",
        "whatever",
        "who",
        "woman"
      ]
    },
    {
      "emoji": "🆘",
      "name": "SOS button",
      "slug": "sos-button",
      "codePoints": [
        "U+1F198"
      ],
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
Reproducible sample of food & drink emoji
GET /api/emoji?group=food-drink&count=5&seed=42
{
  "data": [
    {
      "emoji": "🥙",
      "name": "stuffed flatbread",
      "slug": "stuffed-flatbread",
      "codePoints": [
        "U+1F959"
      ],
      "group": "Food & Drink",
      "subgroup": "food-prepared",
      "unicodeVersion": "3.0",
      "hasSkinTone": false,
      "isZwjSequence": false,
      "keywords": [
        "falafel",
        "flatbread",
        "food",
        "gyro",
        "kebab",
        "stuffed"
      ]
    },
    {
      "emoji": "🧅",
      "name": "onion",
      "slug": "onion",
      "codePoints": [
        "U+1F9C5"
      ],
      "group": "Food & Drink",
      "subgroup": "food-vegetable",
      "unicodeVersion": "12.0",
      "hasSkinTone": false,
      "isZwjSequence": false,
      "keywords": [
        "flavoring",
        "onion"
      ]
    },
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
Only emoji old devices can render
GET /api/emoji?maxVersion=5.0&zwj=false&count=10
{
  "data": [
    {
      "emoji": "🌥️",
      "name": "sun behind large cloud",
      "slug": "sun-behind-large-cloud",
      "codePoints": [
        "U+1F325",
        "U+FE0F"
      ],
      "group": "Travel & Places",
      "subgroup": "sky & weather",
      "unicodeVersion": "0.7",
      "hasSkinTone": false,
      "isZwjSequence": false,
      "keywords": [
        "behind",
        "cloud",
        "sun",
        "weather"
      ]
    },
    {
      "emoji": "🇳🇫",
      "name": "flag: Norfolk Island",
      "slug": "flag-norfolk-island",
      "codePoints": [
        "U+1F1F3",
        "U+1F1EB"
      ],
      "group": "Flags",
      "subgroup": "country-flag",
      "unicodeVersion": "2.0",
      "hasSkinTone": false,
      "isZwjSequence": false,
      "keywords": [
        "flag"
      ]
    },
    {
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
A hundred of the 163 sequences Emoji 17.0 added
GET /api/emoji?version=17.0&skinTones=true&count=100
{
  "data": [
    {
      "emoji": "🤼🏾‍♂️",
      "name": "men wrestling: medium-dark skin tone",
      "slug": "men-wrestling-medium-dark-skin-tone",
      "codePoints": [
        "U+1F93C",
        "U+1F3FE",
        "U+200D",
        "U+2642",
        "U+FE0F"
      ],
      "group": "People & Body",
      "subgroup": "person-sport",
      "unicodeVersion": "17.0",
      "hasSkinTone": true,
      "isZwjSequence": true,
      "keywords": [
        "combat",
        "duel",
        "grapple",
        "medium-dark skin tone",
        "men",
        "ring",
        "tournament",
        "wrestle",
        "wrestling"
      ]
    },
    {
      "emoji": "🤼🏼‍♂️",
      "name": "men wrestling: medium-light skin tone",
      "slug": "men-wrestling-medium-light-skin-tone",
      "codePoints": [
        "U+1F93C",
        "U+1F3FC",
        "U+200D",
        "U+2642",
        "U+FE0F""generatedAt": "2026-09-15T19:47:18.000Z"
  }
}

GET /api/emoji/lookup

Live requestRuns against the public API
No key required
GET/api/emoji/lookup?emoji=%F0%9F%98%80

Request parameters

The emoji sequence itself. U+FE0F is ignored when matching, so an unqualified spelling still resolves.

The URL-safe name, e.g. woman-technologist.

1–16 hexadecimal code points separated by spaces, commas, plus signs or hyphens, with or without U+ prefixes.

Advanced response options4 options

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/emoji/lookup?emoji=%F0%9F%98%80"
const res = await fetch("https://randomapi.dev/api/emoji/lookup?emoji=%F0%9F%98%80");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/emoji/lookup?emoji=%F0%9F%98%80").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/emoji/lookup?emoji=%F0%9F%98%80"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 3
emoji string

The emoji sequence itself. U+FE0F is ignored when matching, so an unqualified spelling still resolves.

allowed: ≤ 64
example: emoji=👩‍💻
slug string

The URL-safe name, e.g. woman-technologist.

allowed: ≤ 80
example: slug=woman-technologist
codepoints string

1–16 hexadecimal code points separated by spaces, commas, plus signs or hyphens, with or without U+ prefixes.

allowed: ≤ 120
example: codepoints=1F469+200D+1F4BB
Universal parameters Shared response and formatting options 4
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=emoji,name
exclude list

Return all fields except these (comma-separated).

example: exclude=keywords
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 10
emoji string

The fully-qualified sequence itself, U+FE0F included where the sequence needs it.

example: 👩‍💻

name string

Unicode's name for the sequence, from emoji-test.txt.

example: woman technologist

slug string

URL-safe form of the name; unique across all sequences and accepted by /lookup.

example: woman-technologist

codePoints string[]

Every code point of the sequence in U+ notation, in order.

example: ["U+1F469","U+200D","U+1F4BB"]

group string

Unicode's top-level category, e.g. Smileys & Emotion.

example: People & Body

subgroup string

Unicode's subcategory, e.g. face-smiling.

example: person-role

unicodeVersion string

Emoji release that introduced the sequence — clients with older fonts will show tofu for newer releases.

example: 4.0

hasSkinTone boolean

True when the sequence carries a U+1F3FB–U+1F3FF skin-tone modifier.

example: false

isZwjSequence boolean

True when several emoji are joined with U+200D ZERO WIDTH JOINER.

example: true

keywords string[]

CLDR English search keywords, in CLDR's order — what /search matches on besides the name.

example: ["computer","developer","software","technologist","woman"]

Documented examples

Build-generated requests and complete responses
4
By the emoji itself
GET /api/emoji/lookup?emoji=%F0%9F%98%80
{
  "data": {
    "emoji": "😀",
    "name": "grinning face",
    "slug": "grinning-face",
    "codePoints": [
      "U+1F600"
    ],
    "group": "Smileys & Emotion",
    "subgroup": "face-smiling",
    "unicodeVersion": "1.0",
    "hasSkinTone": false,
    "isZwjSequence": false,
    "keywords": [
      "cheerful",
      "cheery",
      "face",
      "grin",
      "grinning",
      "happy",
      "laugh",
      "nice",
      "smile",
      "smiling",
      "teeth"
    ]
  },
  "meta": {
    "endpoint": "emoji",
    "route": "/lookup",
    "params": {
      "emoji": "😀"
    },
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
By slug
GET /api/emoji/lookup?slug=grinning-face
{
  "data": {
    "emoji": "😀",
    "name": "grinning face",
    "slug": "grinning-face",
    "codePoints": [
      "U+1F600"
    ],
    "group": "Smileys & Emotion",
    "subgroup": "face-smiling",
    "unicodeVersion": "1.0",
    "hasSkinTone": false,
    "isZwjSequence": false,
    "keywords": [
      "cheerful",
      "cheery",
      "face",
      "grin",
      "grinning",
      "happy",
      "laugh",
      "nice",
      "smile",
      "smiling",
      "teeth"
    ]
  },
  "meta": {
    "endpoint": "emoji",
    "route": "/lookup",
    "params": {
      "slug": "grinning-face"
    },
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
By code points (ZWJ sequence)
GET /api/emoji/lookup?codepoints=1F469%2B200D%2B1F4BB
{
  "data": {
    "emoji": "👩‍💻",
    "name": "woman technologist",
    "slug": "woman-technologist",
    "codePoints": [
      "U+1F469",
      "U+200D",
      "U+1F4BB"
    ],
    "group": "People & Body",
    "subgroup": "person-role",
    "unicodeVersion": "4.0",
    "hasSkinTone": false,
    "isZwjSequence": true,
    "keywords": [
      "coder",
      "computer",
      "developer",
      "inventor",
      "software",
      "technologist",
      "woman"
    ]
  },
  "meta": {
    "endpoint": "emoji",
    "route": "/lookup",
    "params": {
      "codepoints": "1F469+200D+1F4BB"
    },
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
Unqualified spelling resolves to the fully-qualified row
GET /api/emoji/lookup?codepoints=263A
{
  "data": {
    "emoji": "☺️",
    "name": "smiling face",
    "slug": "smiling-face",
    "codePoints": [
      "U+263A",
      "U+FE0F"
    ],
    "group": "Smileys & Emotion",
    "subgroup": "face-affection",
    "unicodeVersion": "0.6",
    "hasSkinTone": false,
    "isZwjSequence": false,
    "keywords": [
      "face",
      "happy",
      "outlined",
      "relaxed",
      "smile",
      "smiling"
    ]
  },
  "meta": {
    "endpoint": "emoji",
    "route": "/lookup",
    "params": {
      "codepoints": "263A"
    },
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}

GET /api/emoji/groups

Live requestRuns against the public API
No key required
GET/api/emoji/groups

Request parameters

Include the 2030 skin-tone variants. Off by default, which leaves the 1914 distinct emoji; on gives all 3944.

Advanced response options4 options

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/emoji/groups"
const res = await fetch("https://randomapi.dev/api/emoji/groups");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/emoji/groups").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/emoji/groups"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 1
skinTones boolean

Include the 2030 skin-tone variants. Off by default, which leaves the 1914 distinct emoji; on gives all 3944.

default: false
example: skinTones=true
Universal parameters Shared response and formatting options 4
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=emojiVersion,emojiCount
exclude list

Return all fields except these (comma-separated).

example: exclude=groups
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 5
emojiVersion string

The pinned Unicode Emoji release these counts describe.

example: 17.0

emojiCount integer

Total emoji counted under the current `skinTones` setting.

example: 1914

groupCount integer

Number of top-level groups.

example: 9

subgroupCount integer

Number of subgroups across all groups.

example: 98

groups object[]

Groups in Unicode's own order, each with its emoji count and its subgroups (name, count and one sample emoji).

example: [{"group":"Flags","slug":"flags","count":270,"subgroups":[{"subgroup":"flag","count":8,"sample":"🏁"}]}]

Documented examples

Build-generated requests and complete responses
2
The group tree (no skin-tone variants)
GET /api/emoji/groups
{
  "data": {
    "emojiVersion": "17.0",
    "emojiCount": 1914,
    "groupCount": 9,
    "subgroupCount": 98,
    "groups": [
      {
        "group": "Smileys & Emotion",
        "slug": "smileys-emotion",
        "count": 171,
        "subgroups": [
          {
            "subgroup": "face-smiling",
            "count": 14,
            "sample": "😀"
          },
          {
            "subgroup": "face-affection",
            "count": 9,
            "sample": "🥰"
          },
          {
            "subgroup": "face-tongue",
            "count": 6,
            "sample": "😋"
          },
          {
            "subgroup": "face-hand",
            "count": 7,
            "sample": "🤗"
          },
          {
            "subgroup": "face-neutral-skeptical",
            "count": 16,
            "sample": "🤐"
          },
          {
            "subgroup": "face-sleepy",
            "count": 6,
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
Counts including every skin-tone variant
GET /api/emoji/groups?skinTones=true
{
  "data": {
    "emojiVersion": "17.0",
    "emojiCount": 3944,
    "groupCount": 9,
    "subgroupCount": 98,
    "groups": [
      {
        "group": "Smileys & Emotion",
        "slug": "smileys-emotion",
        "count": 171,
        "subgroups": [
          {
            "subgroup": "face-smiling",
            "count": 14,
            "sample": "😀"
          },
          {
            "subgroup": "face-affection",
            "count": 9,
            "sample": "🥰"
          },
          {
            "subgroup": "face-tongue",
            "count": 6,
            "sample": "😋"
          },
          {
            "subgroup": "face-hand",
            "count": 7,
            "sample": "🤗"
          },
          {
            "subgroup": "face-neutral-skeptical",
            "count": 16,
            "sample": "🤐"
          },
          {
            "subgroup": "face-sleepy",
            "count": 6,
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}

GET /api/emoji/parse

Live requestRuns against the public API
No key required
GET/api/emoji/parse?text=%F0%9F%91%A8%E2%80%8D%F0%9F%91%A9%E2%80%8D%F0%9F%91%A7%E2%80%8D%F0%9F%91%A6+is+one

Request parameters

Text to scan, up to 1000 UTF-16 code units. Segmented with Intl.Segmenter, so one ZWJ family is one emoji.

Advanced response options4 options

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/emoji/parse?text=%F0%9F%91%A8%E2%80%8D%F0%9F%91%A9%E2%80%8D%F0%9F%91%A7%E2%80%8D%F0%9F%91%A6%20is%20one"
const res = await fetch("https://randomapi.dev/api/emoji/parse?text=%F0%9F%91%A8%E2%80%8D%F0%9F%91%A9%E2%80%8D%F0%9F%91%A7%E2%80%8D%F0%9F%91%A6%20is%20one");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/emoji/parse?text=%F0%9F%91%A8%E2%80%8D%F0%9F%91%A9%E2%80%8D%F0%9F%91%A7%E2%80%8D%F0%9F%91%A6%20is%20one").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/emoji/parse?text=%F0%9F%91%A8%E2%80%8D%F0%9F%91%A9%E2%80%8D%F0%9F%91%A7%E2%80%8D%F0%9F%91%A6%20is%20one"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 1
text string required

Text to scan, up to 1000 UTF-16 code units. Segmented with Intl.Segmenter, so one ZWJ family is one emoji.

allowed: 1 – 1000
example: text=Shipping it 🚀 with the family 👨‍👩‍👧‍👦
Universal parameters Shared response and formatting options 4
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=text,graphemeCount
exclude list

Return all fields except these (comma-separated).

example: exclude=emoji
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 6
text string

The input, echoed exactly as received.

example: hi 👋🏽 and 👨‍👩‍👧‍👦

graphemeCount integer

Total Unicode grapheme clusters in the input — what a user perceives as characters.

example: 10

emojiCount integer

Total emoji occurrences; a ZWJ family, a flag and a skin-tone sequence each count as one.

example: 2

distinctEmojiCount integer

Number of distinct emoji sequences found.

example: 2

textWithoutEmoji string

The input with every emoji grapheme removed and nothing else changed.

example: hi and

emoji object[]

Each distinct emoji in first-appearance order, with its occurrence count and — when the sequence is in the pinned snapshot — its name, slug, group and release. `recognized` is false when the grapheme is emoji-shaped but is not a fully-qualified sequence of this release: an invalid regional-indicator pair such as 🇦🇦, a bare hair or component modifier, or a code point Unicode has reserved for a future emoji. Those still count, with `name`, `slug`, `group` and `unicodeVersion` null.

example: [{"emoji":"👋🏽","count":1,"recognized":true,"name":"waving hand: medium skin tone","slug":"waving-hand-medium-skin-tone","codePoints":["U+1F44B","U+1F3FD"],"group":"People & Body","unicodeVersion":"1.0"}]

Documented examples

Build-generated requests and complete responses
3
A ZWJ family counts as one emoji
GET /api/emoji/parse?text=%F0%9F%91%A8%E2%80%8D%F0%9F%91%A9%E2%80%8D%F0%9F%91%A7%E2%80%8D%F0%9F%91%A6%20is%20one
{
  "data": {
    "text": "👨‍👩‍👧‍👦 is one",
    "graphemeCount": 8,
    "emojiCount": 1,
    "distinctEmojiCount": 1,
    "textWithoutEmoji": " is one",
    "emoji": [
      {
        "emoji": "👨‍👩‍👧‍👦",
        "count": 1,
        "recognized": true,
        "name": "family: man, woman, girl, boy",
        "slug": "family-man-woman-girl-boy",
        "codePoints": [
          "U+1F468",
          "U+200D",
          "U+1F469",
          "U+200D",
          "U+1F467",
          "U+200D",
          "U+1F466"
        ],
        "group": "People & Body",
        "unicodeVersion": "2.0"
      }
    ]
  },
  "meta": {
    "endpoint": "emoji",
    "route": "/parse",
    "params": {
      "text": "👨‍👩‍👧‍👦 is one"
    },
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
Mixed text with flags and skin tones
GET /api/emoji/parse?text=Hi%20%F0%9F%87%AC%F0%9F%87%A7%20%F0%9F%91%8B%F0%9F%8F%BD
{
  "data": {
    "text": "Hi 🇬🇧 👋🏽",
    "graphemeCount": 6,
    "emojiCount": 2,
    "distinctEmojiCount": 2,
    "textWithoutEmoji": "Hi  ",
    "emoji": [
      {
        "emoji": "🇬🇧",
        "count": 1,
        "recognized": true,
        "name": "flag: United Kingdom",
        "slug": "flag-united-kingdom",
        "codePoints": [
          "U+1F1EC",
          "U+1F1E7"
        ],
        "group": "Flags",
        "unicodeVersion": "0.6"
      },
      {
        "emoji": "👋🏽",
        "count": 1,
        "recognized": true,
        "name": "waving hand: medium skin tone",
        "slug": "waving-hand-medium-skin-tone",
        "codePoints": [
          "U+1F44B",
          "U+1F3FD"
        ],
        "group": "People & Body",
        "unicodeVersion": "1.0"
      }
    ]
  },
  "meta": {
    "endpoint": "emoji",
    "route": "/parse",
    "params": {
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
Strip emoji from user input
GET /api/emoji/parse?text=clean%20%F0%9F%A7%BC%20this%20%F0%9F%9A%80%20up
{
  "data": {
    "text": "clean 🧼 this 🚀 up",
    "graphemeCount": 17,
    "emojiCount": 2,
    "distinctEmojiCount": 2,
    "textWithoutEmoji": "clean  this  up",
    "emoji": [
      {
        "emoji": "🧼",
        "count": 1,
        "recognized": true,
        "name": "soap",
        "slug": "soap",
        "codePoints": [
          "U+1F9FC"
        ],
        "group": "Objects",
        "unicodeVersion": "11.0"
      },
      {
        "emoji": "🚀",
        "count": 1,
        "recognized": true,
        "name": "rocket",
        "slug": "rocket",
        "codePoints": [
          "U+1F680"
        ],
        "group": "Travel & Places",
        "unicodeVersion": "0.6"
      }
    ]
  },
  "meta": {
    "endpoint": "emoji",
    "route": "/parse",
    "params": {
      "text": "clean 🧼 this 🚀 up"
    },
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}

About this API

Coverage & behavior

Unicode's own emoji-test.txt for Emoji 17.0, pinned by SHA-256, joined to the CLDR English annotations (release-48-2) so every sequence carries real search keywords rather than a guess from its name.

The count nobody agrees on. There are 3944 fully-qualified emoji, but 2030 of those are skin-tone variants of an emoji already in the set. Exclude them and 1914 distinct emoji remain — which is why skinTones is an explicit switch that defaults to off, and why both numbers are printed here instead of one marketing figure.

/parse uses Intl.Segmenter grapheme segmentation, so 👨‍👩‍👧‍👦 counts as one emoji, not four. Regex-over-code-units emoji counters get this wrong on every ZWJ family, every flag and every skin-tone sequence.

/search matches the Unicode name and the CLDR keywords, so q=happy finds 😀 even though "happy" is not in its name. /groups returns Unicode's official 9-group, 98-subgroup tree with live counts, and /lookup resolves a sequence, a slug or a code-point list — an unqualified spelling such as 263A resolves to the fully-qualified ☺️ because lookups match on the U+FE0F-stripped key.

Rendering is your font's job, not the API's. unicodeVersion is the emoji release that introduced a sequence: anything from a recent release will render as tofu on a device whose emoji font predates it. Filter with maxVersion when you need a set that older clients can actually display.

Scope: only fully-qualified sequences are served. The minimally-qualified and unqualified rows upstream are alternative U+FE0F spellings of sequences already present, and the nine component rows (bare skin-tone and hair modifiers) are not standalone emoji.

Use it for

  • Build an emoji picker with Unicode's own groups, subgroups and keyword search
  • Count emoji in user-generated text correctly, including ZWJ families and flags
  • Ship an emoji set older devices can actually render by capping the release
  • Seeded emoji fixtures that stay identical across CI runs

Frequently asked questions

How many emoji are there?

Unicode Emoji 17.0 has 3944 fully-qualified sequences, but 2030 of them are skin-tone variants of another sequence. Excluding those leaves 1914 distinct emoji, which is what this API returns unless you pass skinTones=true.

How do I count emoji in a string correctly?

GET /api/emoji/parse?text=… segments with Intl.Segmenter, so a zero-width-joiner family such as 👨‍👩‍👧‍👦 counts as one emoji and a flag counts as one, not two. It also returns each distinct emoji with its name and occurrence count.

Can I search emoji by keyword instead of by name?

Yes — /api/emoji/search?q=happy matches the CLDR English annotation keywords as well as the Unicode name, ranking exact name matches first and keyword substring matches last.

Why do some emoji show as boxes on my device?

Because the device's emoji font predates that release. Every record carries unicodeVersion, the emoji release that introduced the sequence, and the list route's maxVersion filter returns only sequences at or below a release you choose.

Can I look up an emoji by its code points?

/api/emoji/lookup?codepoints=1F468+200D+1F4BB accepts space-, comma-, plus- or hyphen-separated hex, with or without the U+ prefix. U+FE0F is ignored when matching, so an unqualified spelling resolves to the fully-qualified sequence.

Standards & references