Skip to main content

Overview

Message entities allow you to apply rich formatting to portions of message text. Each entity specifies a range of text (by start index and length) and a formatting style or semantic meaning.

Proto Definition

message MessageEntity {
  uint32 start_index = 1;
  uint32 length = 2;

  message CustomEmojiEntity {
    fixed64 emoji_id = 1;  // @snowflake<Emoji>
  }

  message TextUrlEntity { 
    string url = 1; 
  }
  
  message PreEntity { 
    optional string language = 1; 
  }
  
  message SpoilerEntity {}
  message UserMentionEntity {}

  oneof entity {
    bool bold = 3;
    bool italic = 4;
    bool underline = 5;
    bool strikethrough = 6;
    bool code = 7;
    bool url = 8;                           // implicit url (when the msg content is the url)
    SpoilerEntity spoiler = 9;
    PreEntity pre = 10;                     // code block
    TextUrlEntity textUrl = 11;             // masked url
    CustomEmojiEntity custom_emoji = 12;
    UserMentionEntity user_mention = 13;    // @ mention of user by id
    bool username = 14;                     // @ mention of user by name
  }
}

Common Fields

All entity types share these base fields:
start_index
uint32
required
The 0-based index of the first character in the entity range. Measured in Unicode code points, not bytes.Example: For “Hello world”, the word “world” starts at index 6.
length
uint32
required
The number of characters (Unicode code points) covered by this entity.Example: For “Hello world”, the word “world” has length 5.

Entity Types

Text Formatting

Bold

bold
bool
Renders the text in bold/strong formatting.
Example:
{
  "start_index": 0,
  "length": 9,
  "bold": true
}
For message “Important message”, makes “Important” bold.

Italic

italic
bool
Renders the text in italic/emphasized formatting.
Example:
{
  "start_index": 6,
  "length": 4,
  "italic": true
}
For message “Hello from the server”, makes “from” italic.

Underline

underline
bool
Renders the text with underline formatting.
Example:
{
  "start_index": 0,
  "length": 5,
  "underline": true
}

Strikethrough

strikethrough
bool
Renders the text with strikethrough formatting (crossed out).
Example:
{
  "start_index": 10,
  "length": 8,
  "strikethrough": true
}
For message “This is outdated information”, strikes through “outdated”.

Code Formatting

Inline Code

code
bool
Renders the text as inline code with monospace font and background highlighting.
Example:
{
  "start_index": 4,
  "length": 14,
  "code": true
}
For message “Use console.log() for debugging”, formats “console.log()” as inline code.

Code Block (Pre)

pre
PreEntity
Renders the text as a code block with optional syntax highlighting.Fields:
  • language (optional string) - Programming language for syntax highlighting (e.g., “javascript”, “python”, “rust”)
Example:
{
  "start_index": 0,
  "length": 45,
  "pre": {
    "language": "javascript"
  }
}
For a message containing JavaScript code, applies syntax highlighting.

Implicit URL

url
bool
Marks a portion of text as a clickable URL where the displayed text is the URL itself.Used when the message content itself is the URL (e.g., “https://example.com”).
Example:
{
  "start_index": 10,
  "length": 19,
  "url": true
}
For message “Check out https://example.com for details”, makes the URL clickable.
textUrl
TextUrlEntity
Creates a hyperlink where the displayed text differs from the actual URL.Fields:
  • url (string, required) - The actual URL to link to
Example:
{
  "start_index": 6,
  "length": 4,
  "textUrl": {
    "url": "https://example.com"
  }
}
For message “Click here for more info”, makes “here” link to “https://example.com”.

Mentions

User Mention (By ID)

user_mention
UserMentionEntity
Mentions a user by their ID. The text should be in the format “@username” or similar.The user ID is determined from context (typically the text content or the message’s author).
Example:
{
  "start_index": 0,
  "length": 9,
  "user_mention": {}
}
For message “@johndoe can you review this?”, creates a mention that notifies the user.

Username Mention (By Name)

username
bool
Mentions a user by their username. Similar to user_mention but references the user by name instead of ID.
Example:
{
  "start_index": 0,
  "length": 9,
  "username": true
}

Special Entities

Spoiler

spoiler
SpoilerEntity
Hides the text behind a spoiler warning. Users must click/tap to reveal the content.
Example:
{
  "start_index": 20,
  "length": 15,
  "spoiler": {}
}
For message “The movie ending is ||spoiler text||”, hides “spoiler text” until revealed.

Custom Emoji

custom_emoji
CustomEmojiEntity
Replaces text with a custom emoji image.Fields:
  • emoji_id (fixed64, required) - Snowflake ID of the custom emoji
Example:
{
  "start_index": 6,
  "length": 2,
  "custom_emoji": {
    "emoji_id": "123456789012345678"
  }
}
For message “Hello :smile: friend”, replaces “:smile:” with the custom emoji.

Multiple Entities

Multiple entities can be applied to the same message, including overlapping ranges: Example: Bold and Italic
{
  "message": "This is important text",
  "entities": [
    {
      "start_index": 8,
      "length": 9,
      "bold": true
    },
    {
      "start_index": 8,
      "length": 9,
      "italic": true
    }
  ]
}
Makes “important” both bold and italic. Example: Link with Bold
{
  "message": "Click here for details",
  "entities": [
    {
      "start_index": 6,
      "length": 4,
      "textUrl": {
        "url": "https://example.com"
      }
    },
    {
      "start_index": 6,
      "length": 4,
      "bold": true
    }
  ]
}
Makes “here” a bold link.

Complex Example

{
  "message": "Hey @alice, check out this code: `console.log('Hello')` and visit https://docs.example.com",
  "entities": [
    {
      "start_index": 4,
      "length": 6,
      "user_mention": {}
    },
    {
      "start_index": 32,
      "length": 24,
      "code": true
    },
    {
      "start_index": 67,
      "length": 25,
      "url": true
    }
  ]
}
This message includes:
  1. A user mention (“@alice”)
  2. Inline code (“console.log(‘Hello’)”)
  3. A clickable URL (“https://docs.example.com”)

Important Notes

Index Calculation

  • Start indices are 0-based: The first character is at index 0
  • Indices count Unicode code points, not bytes or UTF-16 code units
  • Emoji count as one code point (in most cases)
  • Combining characters may affect index calculations

Entity Ordering

  • Entities can be specified in any order
  • Multiple entities can overlap or nest within each other
  • The rendering order is determined by the client implementation

Entity Validation

  • Ensure start_index + length does not exceed the message length
  • Invalid indices may cause the entity to be ignored or the message to be rejected
  • Empty entities (length = 0) are typically ignored

Supported Combinations

Most formatting entities can be combined:
  • ✅ Bold + Italic
  • ✅ Bold + Underline
  • ✅ Link + Bold/Italic
  • ✅ Code + Spoiler (code block hidden by spoiler)
  • ❌ Code block (pre) typically doesn’t combine with inline formatting

Use in Edits

When editing a message:
  • Providing new entities replaces all existing entities
  • Omitting entities when changing text clears all entities
  • To preserve entities, include them in the edit request

Build docs developers (and LLMs) love