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.
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.
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
- You need to display missing glyphs or render emoji into images: this package manipulates Unicode strings and data, but it ships no font, platform renderer, or image assets
- You want sentiment, intent, or natural-language meaning from emoji: metadata contains names, status, aliases, and version, not contextual classification
- Your code depends on a public emoji regular expression: get_emoji_regexp was removed in 2.0 because regex matching was slow and incorrect for some long sequences
- You plan to persist translated shortcodes as permanent identifiers: the 2.0 migration guide says CLDR updates changed non-English names, and not every emoji has a name in every language
- You assume one emoji equals one Python character or stable display width: variation selectors, skin tones, flags, and ZWJ families span multiple code points, and is_emoji can be false for a variant sequence that purely_emoji correctly accepts
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
| Package | Registry | Pick it when |
|---|---|---|
| demoji | PyPI | Use it for a narrower find, describe, replace, or remove workflow when shortcode localization is unnecessary |
| emot | PyPI | Use it when social-text extraction must recognize classic emoticons as well as Unicode emoji |
| pilmoji | PyPI | Use it when the task is rendering emoji into Pillow images rather than analyzing Unicode strings |