mrkeyoor.com_
Sat 08 Aug 21:01 UTC
PyPIUtilsupdated 08 Aug 2026

emoji

emoji is a data-backed Unicode emoji utility for Python. It converts official or alias shortcodes to emoji, converts emoji back to localized names, scans text without relying on one giant regular expression, reports Python string positions and Emoji version metadata, and replaces or filters sequences. Version 2.15.0 includes Unicode 17.0 data, typed APIs, English plus 14 translated name sets, and special handling for variation selectors, skin tones, and zero-width-joiner sequences.

Verdict

This is the sensible Python default for shortcode conversion and Unicode-aware emoji scanning. Do not confuse its data and tokenizer with a renderer, grapheme library, sentiment model, or permanent multilingual naming scheme.

API stability4/5The 2.x surface has settled around emojize, demojize, analyze, replace_emoji, list and count helpers, validation, version lookup, and EMOJI_DATA. Releases mainly track Unicode and translation data. The deduction comes from the major 2.0 cleanup, which removed the public regex and legacy dictionaries and changed non-English names, plus module-wide configuration and external CLDR data that can alter text output between versions.
Docs5/5The live Sphinx site documents every public function, module data, supported languages, aliases, variations, extraction positions, counts, replacement callbacks, version filtering, ZWJ families, non-RGI behavior, and the 2.0 migration. Examples explicitly show that an emoji may span several indexes and that is_emoji differs from purely_emoji. The README is shorter, but it points to both the API docs and a generated list for the exact supported release.
Maintenance4/5Version 2.15.0 and the last repository push both date to 2025-09-21, when the data was updated to Unicode 17.0. GitHub reports 27 open issues and pull requests, and workflows cover Python tests, PyPI publishing, builds, and documentation updates. The project is maintained on the cadence of Unicode and CLDR data rather than constant feature work; by 2026 the release is not brand new, but it is still the current Unicode generation.
Ecosystem5/5The package records 5,452,303 weekly downloads, has 2,034 GitHub stars, supports CPython and PyPy from Python 3.8 through 3.14, includes a py.typed marker, and covers English plus 14 translated languages. Its data follows the Unicode Consortium and CLDR rather than a private vocabulary. The main ecosystem limit is outside Python: actual glyph appearance still depends on client fonts and operating-system emoji support.

Use it if

  • You need reliable shortcode conversion and emoji extraction that understands multi-codepoint and zero-width-joiner sequences
  • Your application needs localized emoji names in one of the 14 supported non-English languages
  • You must filter emoji by Emoji version for clients with older platform support
  • You want packaged Unicode 17.0 emoji metadata with no required runtime dependencies
Skip it if

Setup reality

python -m pip install emoji installs a pure Python, typed package on Python 3.8 or newer with no required runtime dependencies. The practical setup is choosing a storage and display contract. Official English names are enabled by default; informal aliases such as :thumbsup: require language='alias'. Localized emojize and demojize calls use CLDR-derived names, and direct access to a non-English key in EMOJI_DATA requires emoji.config.load_language(code) first. Those language files are loaded into module-global data on demand, which saves initial import work but changes the shared EMOJI_DATA object for the process. Shortcodes are useful interchange text, not immutable IDs: names can change with CLDR releases, aliases are not the official set, and 2.0 already broke old localized names. Unicode strings also need grapheme-aware treatment. emoji_list reports Python string offsets where a family or skin-tone sequence can span several indexes; do not slice or count visible symbols one code point at a time. is_emoji asks whether the entire input is one RGI entry, while purely_emoji allows strings made only of emoji tokens and their variation selectors. Non-RGI ZWJ handling is controlled by the module-wide config.demojize_keep_zwj setting, so changing it in one library affects other callers. Emoji version gating removes unsupported entries by default unless handle_version supplies replacement text. Finally, this library cannot make an operating system render Unicode 17 glyphs; fonts and platform releases decide whether users see the intended symbol, tofu, or separated component glyphs.

Patterns

Convert official shortcodes to Unicode emojiconvert-shortcodes

import emoji

message = emoji.emojize('Deploy complete :check_mark_button:')
print(message)

The default language is English and uses official names. Unknown shortcodes remain unchanged.

Accept common alias namesenable-shortcode-aliases

import emoji

message = emoji.emojize(
    'Nice work :thumbsup: :+1:',
    language='alias',
)

Alias mode includes the official English list plus informal aliases. Do not assume aliases are stable, unique product identifiers.

Convert emoji back to portable namesconvert-to-shortcodes

import emoji

stored = emoji.demojize('Ship it 👍')
# 'Ship it :thumbs_up:'

Shortcodes are readable storage text, but names can change with Unicode or CLDR data updates. Pin the package if serialized output is a protocol.

Avoid collisions with colon syntaxuse-custom-delimiters

import emoji

rendered = emoji.emojize(
    'Status {green_circle}',
    delimiters=('{', '}'),
)

Use the same delimiter pair when demojizing if round trips must preserve your chosen shortcode syntax.

Convert Spanish emoji namesuse-localized-names

import emoji

rendered = emoji.emojize(
    'Todo bien :pulgar_hacia_arriba:',
    language='es',
)
shortcodes = emoji.demojize(rendered, language='es')

Not every emoji has a name in every language, and localized CLDR names changed during the 2.0 migration.

Find emoji and Python string offsetsfind-emoji-positions

import emoji

for match in emoji.emoji_list('A 👩‍🚀 aboard a 🚀'):
    print(match['emoji'], match['match_start'], match['match_end'])

Offsets are Python string indexes, not visible-character counts or UTF-8 byte offsets. The astronaut sequence spans multiple code points.

Inspect matches and Unicode metadataanalyze-emoji-metadata

import emoji

for token in emoji.analyze('Launch 🚀'):
    match = token.value
    print(token.chars, match.start, match.end)
    if match.data is not None:
        print(match.data['en'], match.data['E'])

analyze returns a generator. A joined non-RGI ZWJ sequence can have data=None even though its individual components have metadata.

Count total and unique emojicount-emoji

import emoji

text = '🌍 😂 😃 😂 🌍 🌦️'
total = emoji.emoji_count(text)
unique = emoji.emoji_count(text, unique=True)
unique_values = sorted(emoji.distinct_emoji_list(text))

distinct_emoji_list builds from a set, so sort it when deterministic output order matters.

Remove all recognized emojiremove-emoji

import emoji

plain = emoji.replace_emoji('Alert 🚨 resolved ✅', replace='')

This removes recognized emoji tokens, not all symbols, pictographs, variation selectors, or arbitrary Unicode grapheme clusters.

Replace emoji with searchable namesreplace-with-names

import emoji

def english_name(chars, data):
    return f' {data["en"]} '

searchable = emoji.replace_emoji(
    'Weather 🌧️ improving ☀️',
    replace=english_name,
)

The callback receives each matched Unicode sequence and a copy of its data dict. Normalize whitespace afterward if this feeds search indexing.

Replace emoji newer than a client supportslimit-emoji-version

import emoji

safe = emoji.emojize(
    'A :T-Rex: eats a :croissant:',
    version=3.0,
    handle_version='[unsupported emoji]',
)

The number is the Emoji version stored in EMOJI_DATA, not a Python, package, or operating-system version. Without handle_version, newer emoji are removed.

Distinguish one emoji from emoji-only textvalidate-emoji-input

import emoji

assert emoji.is_emoji('👍')
assert not emoji.is_emoji('👍👍')
assert emoji.purely_emoji('👍👍')
assert emoji.purely_emoji('😀️')

is_emoji requires the whole string to match one RGI entry. purely_emoji tokenizes the full string and handles variation selectors more naturally.

Alternatives

PackageRegistryPick it when
demojiPyPIUse it for a narrower find, describe, replace, or remove workflow when shortcode localization is unnecessary
emotPyPIUse it when social-text extraction must recognize classic emoticons as well as Unicode emoji
pilmojiPyPIUse it when the task is rendering emoji into Pillow images rather than analyzing Unicode strings