Skip to content

Instantly share code, notes, and snippets.

@scragly
Last active September 3, 2023 10:07
Show Gist options
  • Star 60 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save scragly/b8d20aece2d058c8c601b44a689a47a0 to your computer and use it in GitHub Desktop.
Save scragly/b8d20aece2d058c8c601b44a689a47a0 to your computer and use it in GitHub Desktop.
Emoji for Discord Bots

Discord Emoji

Note: This is written for those using Python 3 and discord.py, so if you're using something else please reference the relevant documentation for your language or library if you choose to use this as a general reference.

On Discord, there are two different emoji types:

Each needs to be handled differently, as while unicode emoji are just simple unicode characters, Discord custom emoji are special objects available only in Discord, belonging to a specific Discord guild and having their own snowflake ID.

The nature of the two can be easily compared by seeing their representations in Discord message contents:

  • Unicode emoji look like the actual emoji character, just the same as any other letter or number: 🙂
  • Custom emoji are a special tag representation using the custom emoji's name and snowflake ID: <:blobsad:396521773144866826>

Unicode Emoji

Unicode emoji are normal characters and should be treated as standard strings. You send the character as-is, and receive them as-is, are universally available, and work even outside of Discord. This makes them super easy to work with.

An example of a unicode emoji is the commonly used :slight_smile: (🙂).

Discord uses specifically Twemoji assets for all their unicode emojis.

How do they work?

As these emoji are normal unicode characters, they can be used anywhere unicode is supported, including here in this Github gist.

Each unicode character is referenced by an "address" of the full character set. These addresses are called their "code point" and are typically represented as a hexidecimal (aka hex) value. In our examples, we'll be using 32 bit hex values, also known as UTF-32.

The capital A character has a code point of 0x00000041, while the 🙂 emoji character has the code point of 0x0001F642.

Some emoji are combinations of characters to either modify a base emoji appearance, create a combined emoji, or were mapped with multiple due to not having a single code points available when they were added.

Some examples of this are:

  • 👨‍👧‍👦 / :family_man_girl_boy: / 0x0001f468, 0x0000200d, 0x0001f467, 0x0000200d, 0x0001f466
    • Combination emoji built from 👨 (man), 👧 (girl), 👦 (boy), joined with the special joiner character \u200d.
  • 🇦🇺 / :flag_au: / \U0001f1e6, \U0001f1fa
    • Regional flag emoji built from the Regional Indicator symbols representing the Australian country code AU (🇦,🇺).
  • 1️⃣ / :one: / \U00000031, \U0000fe0f, \U000020e3
    • Keycap emoji built from the literal number 1 character, special unicode character \U0000fe0f that indicates the 1 is part of an emoji, and the key cap modifier \U000020e3.
  • 👍🏾 / :thumbsup::skin-tone-4: / \U0001f44d, \U0001f3fe
    • Modified thumbs up emoji using the normal thumbs up character (👍) and the skin tone modifier character \U0001f3fe.

You can figure out a character's codepoint in code by retrieving it's ordinal and converting it to a hexidecimal representation:

>>> ordinal = ord("🙂")
>>> ordinal
128578
>>> f"{ordinal:x}"  # to hex
'1f642'

Due to combination emojis as outlined above, it's best to iterate through all characters, even if you think you're working with a single emoji.

>>> keycap_one = "1️⃣"
>>> [f"0x{ord(c):08x}" for c in keycap_one]
['0x00000031', '0x0000fe0f', '0x000020e3']

You can also reference the Unicode emoji list or Emojipedia.

How are they received?

As message content

As unicode emoji are standard text characters, you'll receive them as normal text characters, just the same as any letter or number.

>>> message.content
'🙂 is a smiley face.'

As a reaction emoji

Typically, the reaction object will return the string with the emoji character(s) directly when trying to reference it:

>>> reaction.emoji
'🙂'

But if you have a Discord emoji object from an event (perhaps a PartialEmoji), and that object is missing an ID value, the real string of the emoji will be in the name attribute instead. This is because emoji objects representing Unicode emoji are not true Discord objects, and as such do not have any id.

>>> emoji.id
None
>>> emoji.name
'🙂'

How are they sent?

As message content

In your code, there are four ways to define a unicode character:

  • Raw character: "🙂"
  • Code point: "\U0001F642"
  • Unicode name: "\N{SLIGHTLY SMILING FACE}"
  • Discord-specific emoji names: ":slight_smile:"
Raw character
await ctx.send("Hi 🙂")

Due to unicode sometimes causing issues when trying to be rendered on some consoles, loggers and editors, causing output errors or readability issues, it's not recommended to use raw emoji characters directly in code.

Code point
await ctx.send("Hi \U0001f642")

As this isn't the most readable code, it's recommended to add a comment describing the emoji, or storing the emoji string in it's own named variable instead.

slight_smile = "\U0001f642"
await ctx.send(f"Hi {slight_smile}")
Unicode name
await ctx.send("Hi \N{SLIGHTLY SMILING FACE}")

More readable by default, but takes a lot of horizontal room as the unicode names are often longer than necessary.

Discord emoji name
await ctx.send("Hi :slight_smile:")

Discouraged due to non-standard Discord emoji names being subject to change without any notice.

Custom Emoji

Custom emoji aren't characters, but Discord-specific image objects. They belong to a specific Guild and an account can only use a guild's custom emoji if it is a member of that Guild. This applies to both users and bots.

All bot accounts are capable of using emojis external to the guild they originate. Users, however, are limited to custom emojis in the current guild they're chatting in unless they subscribe to Discord Nitro.

How do they work

Discord emoji objects are basically special images that are bound to a specific guild, have their own Discord ID, and can be referenced by a specific name.

It's possible to view the image of the emoji directly by right-clicking a custom emoji, clicking 'Copy Link', and pasting that copied a URL into a browser. The URL you get looks like https://cdn.discordapp.com/emojis/396521773144866826.png.

The numbers in the URL is the custom emoji ID, so you can use this to reference it's ID, or, if you already have the ID, you can build the URL manually with f"https://cdn.discordapp.com/emojis/{}.{ext}", replacing ext with any of the static filetypes such as png if it's a standard emoji, or gif if it's an animated emoji.

How are they received?

As message content

Custom emojis in standard content is represented as specially formatted tags:

  • Standard: <:name:id>, e.g. <:blobsad:396521773144866826>
  • Animated: <a:name:id>, e.g. <a:ablobpanic:506956736113147909>

You can force these formatted tags to be shown raw in the normal client by escaping a custom emoji you send (by prefixing it with \).

You can retreive a custom emoji's URL in the standard client, which will be of the following format: https://cdn.discordapp.com/emojis/{emoji_id}.{ext}

The ext to use depends on the emoji types:

  • Standard (Static Types): png, jpg, webp
  • Animated: gif

As reaction emoji

A Reaction object will return an emoji object representing custom emojis. These are proper Discord objects, with each having their own id.

>>> reaction.emoji
<PartialEmoji animated=False name='blobsad' id=396521773144866826>
>>> reaction.emoji.id
396521773144866826
>>> reaction.emoji.name
'blobsad'
>>> str(reaction.emoji)
'<:blobsad:396521773144866826>'

How are they sent?

In your code, there's 2 ways to define a custom emoji:

  • Emoji object by ID
  • Emoji object by name
  • Using a formatted string

Emoji object by ID

If you store the emoji ID, you can fetch an Emoji instance that's cached in the bot's client. Discord IDs are guaranteed to be unique even across different guilds, so there's no chance of conflict:

>>> ctx.bot.get_emoji(396521773144866826)
<Emoji animated=False name='blobsad' id=396521773144866826>

You can also fetch an emoji directly from a specific guild, however keep in mind that this calls the API:

>>> await ctx.guild.fetch_emoji(396521773144866826)
<Emoji animated=False name='blobsad' id=396521773144866826>

You can then use the emoji in a message by casting it to a string, either explicitly or implicitly:

emoji = await ctx.guild.fetch_emoji(396521773144866826)
await ctx.send(f"Sorry! {emoji}")

Or pass it directly when using it for reactions:

emoji = await ctx.guild.fetch_emoji(396521773144866826)
await ctx.message.add_reaction(emoji)

Emoji object by name

If you want to use emoji's local to the guild in context, you may end up using emoji names to fetch emojis:

for emoji in ctx.guild.emojis:
    if emoji.name == "checkmark":
        return emoji

There's also a utility function available in the discord.py library for generic O(n) attribute-based lookups like the above:

checkmark = discord.utils.get(message.guild.emojis, name='checkmark')

Keep in mind, each guild your bot is in will need to have an emoji present with the correct name or you should have a fallback in place in case they don't. You also won't be able to fetch the emoji in the context of DMs, as they aren't in a guild.

Using a formatted string

As mentioned before, a custom emoji can be represented as a special formatted string tag: <:blobsad:396521773144866826>

You can store this string and use it as-is for sending in message contents as well as for reactions:

sad_emoji = "<:blobsad:396521773144866826>"
msg = await ctx.send(f"Sorry! {sad_emoji}")
await msg.add_reaction(sad_emoji)

For reactions, you can also drop the angle brackets (<>) and it will still work, however it's not recommended to do this as it's inconsistent with using it in message content.

While the tag format requires both the emoji name and emoji ID, the name doesn't actually have to match the proper name of the emoji. Because of this, the below will also work:

sad_emoji = "<:placeholdername:396521773144866826>"
msg = await ctx.send(f"Sorry! {sad_emoji}")
await msg.add_reaction(sad_emoji)

And thanks to this working, you could just opt to save emoji ID only, allowing you to keep track of the least amount of information necessary, allowing you to both easily fetch Emoji objects while also being capable of building formatted string tags manually.

@sayantan300
Copy link

Thanks

@AirOne01
Copy link

Well wrote and useful, thx! 👍

@Dislaik
Copy link

Dislaik commented Jun 14, 2020

Thx!

@aggiczy
Copy link

aggiczy commented Aug 13, 2020

Hi! How can I get an Animated Emoji's ID without nitro?

@nspeedzy
Copy link

nspeedzy commented Sep 3, 2020

Well explained!

@VirUs-23
Copy link

VirUs-23 commented Sep 7, 2020

Thanks!

@LouissXI
Copy link

LouissXI commented Oct 2, 2020

Well explained ! Thanks for the help !

@TomThe-Dev
Copy link

Thanks this was very helpful! Tbh kinda baffled that there isn't a way to get a emoji id with just the emoji name

@netotz
Copy link

netotz commented Oct 24, 2020

For Discord default emojis like :smile: 😄, I prefer to use the emoji package (pip install emoji). I don't like its default emojize() function so I do it like this:

# just import the emojis dictionary which aliases are the same as in discord
from emoji import EMOJI_ALIAS_UNICODE as EMOJIS

# get an emoji as string by using the discord alias
smilemoji = EMOJIS[':smile:']

For me it's easier and more understandable to do get an emoji with the Discord alias. @TaccaT17 this may help you as well

@AirOne01
Copy link

AirOne01 commented Dec 6, 2020

@Rayorrr

je n'arrive pas pour l'émojis basique

Lequel? Tu peut simplement utiliser :emoji: pour les emojis basiques. Par exemple tu peux utiliser la fonction Message#react() (ou discord.Message.add_reaction avec discord.py) avec "😀" ou ": smile :" (sans les espaces), ce qui donnera le même résultat.

Documentations:

Au fait, bienvenue sur Github!

@undefynedd
Copy link

Thanks!

@Pusywetass
Copy link

Well explained ! Thanks for the he?????????????

@dDryyy
Copy link

dDryyy commented Jan 7, 2021

Thanks!

@CyberFowl
Copy link

I got an unknown emoji error
image

@EacyCoding
Copy link

Thank you very much, this helps a lot <3

@KierenPH
Copy link

I got an unknown emoji error
image

Make sure the bot you are using is in a server with that emoji in it.

@CRYSTAL-HQ
Copy link

THANKS

@Redous-UK
Copy link

Anyone know why you cant use the :regional_indicator_a: ?

@scragly
Copy link
Author

scragly commented Jul 16, 2021

@Redous-UK You can, absolutely. Here's a screenshot of it working just the same as how we would typing it in the client:
image

Doing it this way is discouraged though, as emoji names in Discord are non-standard, set by them and are subject to change any time without notice. Relying on the Unicode standardised names and code-points is just far more dependable.

@scragly
Copy link
Author

scragly commented Jul 16, 2021

For the first time since 2018, I've updated this gist with current info, and fleshed out explanations a bit. Feel free to provide any feedback.

Copy link

ghost commented Jul 20, 2021

Hi! How can I get an Animated Emoji's ID without nitro?

Yes you can

@8dcc
Copy link

8dcc commented Apr 3, 2022

For Discord default emojis like :smile: 😄, I prefer to use the emoji package (pip install emoji). I don't like its default emojize() function so I do it like this:

# just import the emojis dictionary which aliases are the same as in discord
from emoji import EMOJI_ALIAS_UNICODE as EMOJIS

# get an emoji as string by using the discord alias
smilemoji = EMOJIS[':smile:']

Thank you so much.

@waqasali58
Copy link

Each needs to be handled differently, as while unicode emoji are just simple unicode characters, Discord custom emoji are special objects available only in Discord, I have built a website using using JSON API emoji copy and paste .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment