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 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.
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
.
- Combination emoji built from π¨ (man), π§ (girl), π¦ (boy), joined with the special joiner character
- π¦πΊ /
: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 the1
is part of an emoji, and the key cap modifier\U000020e3
.
- Keycap emoji built from the literal number
- ππΎ /
:thumbsup::skin-tone-4:
/\U0001f44d, \U0001f3fe
- Modified thumbs up emoji using the normal thumbs up character (π) and the skin tone modifier character
\U0001f3fe
.
- Modified thumbs up emoji using the normal thumbs up character (π) and the skin tone modifier character
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.
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.'
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
'π'
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:"
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.
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}")
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.
await ctx.send("Hi :slight_smile:")
Discouraged due to non-standard Discord emoji names being subject to change without any notice.
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.
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.
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
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>'
In your code, there's 2 ways to define a custom emoji:
- Emoji object by ID
- Emoji object by name
- Using a formatted string
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)
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.
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.
Guys, if using a custom emoji for a reaction does this emoji necessarily needs to be in the server the bot is in? I tried using some random emojis I use from different servers, but getting the "Unknown Emoji" error all the time.
Bot has access for using external emojis tho.
With standard emojis everything works as expected. Ty!