· 7 min read
Telegram Automation with Message Entities: The Overlooked Feature That Makes Bots Smarter
Most Telegram automation tutorials focus on commands, keyboards, and raw text. A more powerful and often overlooked capability is message entities: the structured metadata Telegram attaches to text, links, mentions, code, and formatting. Used well, entities let bots and automation pipelines preserve meaning, parse intent reliably, and avoid brittle text processing.
When people build Telegram automation, they usually start with commands, callbacks, and scheduled messages. That gets you far, but it also pushes many developers into a fragile pattern: treating Telegram messages as plain text.
That approach works until it doesn’t.
A message like:
Deploy @alice to https://example.com at 15:30
is not just a string. In Telegram, it can contain structured metadata describing the mention, the link, formatting, hashtags, and more. That metadata is exposed through message entities, and it is one of the most underused features in Telegram automation.
If you build bots, log pipelines, moderation tools, content relays, or message transformers, entities can save you from a long list of parsing bugs.
What message entities are
Telegram message entities are positional annotations attached to message text. They describe spans of text that have semantic meaning, such as:
mentionhashtagcashtagbot_commandurlemailphone_numberbolditaliccodepretext_linktext_mentionspoilercustom_emoji
Instead of inferring meaning by regex, you can read the entities Telegram already detected or that you explicitly set when sending a message.
That matters because Telegram’s own parsing rules are more reliable than ad hoc string matching, and entity offsets preserve exact spans even when text includes Unicode, emojis, or formatting.
Why developers overlook entities
Most tutorials mention formatting modes like Markdown or HTML, then stop there. Developers learn to send parse_mode, or they call .text on incoming messages and move on.
Entities are overlooked for a few reasons:
- They feel low-level. Offsets and lengths look more tedious than simple regex.
- They are hidden by wrappers. Some libraries make them available, but not prominently.
- They are more useful in advanced pipelines. If you only need
/start, you won’t notice them. - They solve problems that only appear at scale. Relays, moderation, indexing, and message transformation all benefit more than simple bots.
If your bot ever needs to preserve formatting, extract structured references, or rewrite user messages safely, entities are the right tool.
The practical advantage: don’t parse text, inspect structure
Suppose your bot watches a support group and extracts ticket references.
A naive approach might search for patterns like:
#\d+
But what if a user writes the ticket number inside code? What if someone includes the same pattern in a quoted block? What if the message contains a hashtag and not a ticket?
Entities help you separate intent from incidental text.
For example:
- A real Telegram hashtag is entity type
hashtag. - A Markdown code block is entity type
pre. - A mention is entity type
mentionortext_mention. - A link created by formatting is
text_link.
That means your automation can decide what to process and what to ignore.
Reading entities from incoming messages
In the Bot API, incoming messages often include:
message.textmessage.entitiesmessage.captionmessage.caption_entities
The important thing is to treat the text and entities as a pair.
Each entity typically includes:
typeoffsetlength- sometimes
url - sometimes
user - sometimes
language - sometimes
custom_emoji_id
Offsets are usually measured in UTF-16 code units in Telegram’s API model, which is a detail that matters when you map entities back into your own string handling. If your library abstracts this for you, great. If not, be careful with multilingual text and emoji.
Example: extracting only real mentions
Imagine a bot that adds users to a CRM when they are mentioned in a message.
You do not want to grab every @name-looking substring. You want actual Telegram mentions.
A safe strategy is:
- Read the message text.
- Inspect its entities.
- Select only entities of type
mentionortext_mention. - Extract the exact substring or user object.
Pseudo-code:
for entity in message.entities:
if entity.type in ("mention", "text_mention"):
segment = message.text[entity.offset:entity.offset + entity.length]
process(segment)
In real Telegram libraries, you should use the library’s entity helper if it compensates for UTF-16 offsets. But the design principle is the same: trust the entity metadata, not pattern matching.
Example: preserving formatting in a message relay
A common automation task is relaying posts from one channel to another, possibly after adding a prefix or footer.
If you use plain text, you often destroy formatting:
- bold text becomes plain text
- links lose their target URLs
- code blocks become unreadable
- inline mentions lose the user reference
Entities let you reconstruct the message faithfully.
Bad relay pattern
await bot.send_message(chat_id=target, text="[Forwarded] " + message.text)
This may drop rich formatting or break links.
Better relay pattern
- Read original text and entities.
- Rebuild the message with new text.
- Recalculate or regenerate entities for the rewritten content.
If you only prepend a short prefix, you need to shift entity offsets accordingly. That is tedious, but it is also deterministic and safe.
This is especially useful for:
- cross-posting announcements
- moderation logs
- audit trails
- language translation bots that preserve emphasis and links
Example: filtering commands without false positives
Bot commands are another place where entities matter.
A user may write:
/startrun /start in production- ```
/start
If you only search the text for `/start`, you may trigger on any occurrence.
If you inspect entities, you can target only the real command entity at the start of the message.
That lets you avoid accidental triggers and better support messages that contain slash-prefixed paths or code samples.
## Entity-aware moderation
Entities can also improve moderation logic.
Examples:
- Detect when users are mass-mentioning others using actual mention entities.
- Ignore code blocks when looking for banned terms, depending on policy.
- Flag messages that include hidden links via `text_link`.
- Spot phishing attempts by comparing visible text and actual link target.
That last point is important.
A message may display harmless text while the actual hyperlink points somewhere else. If your moderation or review workflow only reads visible text, you miss the real destination. Entities expose the target URL directly for `text_link` entities.
## Sending messages with entities instead of parse mode
Entities are not only for reading. They are also useful when you send messages.
You can either:
- set a `parse_mode` such as Markdown or HTML, or
- provide explicit entities
For automation, explicit entities are often safer.
Why?
Because parse modes require escaping rules that vary by format, and they can break when your generated content contains user input.
With explicit entities, you build the message text first, then attach formatting spans intentionally.
This is ideal when your bot generates:
- status summaries
- changelogs
- schedule notices
- alert digests
- templated messages with dynamic values
## A good pattern for dynamic content
Suppose you want to send:
> Build `api-service` succeeded at 14:12
Instead of composing Markdown and escaping backticks, you can create plain text and mark only the service name as code.
Conceptually:
text = "Build api-service succeeded at 14:12" entities = [ {"type": "code", "offset": 6, "length": 10} ] await bot.send_message(chat_id, text=text, entities=entities)
The exact offsets depend on your string handling, but the benefit is clear: no parsing ambiguity, no accidental formatting injection.
## When entities beat Markdown
Use explicit entities when:
- text includes user input
- you need exact formatting control
- you relay or transform messages
- you handle multilingual text
- you want to avoid escaping issues
- you care about preserving links and mentions precisely
Use Markdown or HTML when:
- the message is short and static
- formatting is simple
- the text is controlled by you
- developer convenience matters more than precision
For automation systems, explicit entities often scale better.
## Common implementation pitfalls
### 1. Ignoring caption entities
Photos, videos, documents, and other media can have captions with their own entities. If your automation only checks `message.text`, you will miss formatted captions entirely.
### 2. Rewriting text without updating offsets
If you add, remove, or replace text, every entity after the change may need a new offset. Do not assume you can reuse old entity positions.
### 3. Handling Unicode incorrectly
Telegram entity offsets do not always align with naive character indexing in every language runtime. Test with emojis, combined characters, and non-Latin scripts.
### 4. Trusting visible text over actual links
For `text_link`, the visible span and destination URL are different things. Check both.
### 5. Losing entities during forwarding pipelines
If you ingest a message, store only raw text, and discard entities, you lose important meaning. Persist both when the structure matters.
## A developer-friendly storage model
If your automation archive stores messages, keep at least:
- raw text
- entity list
- message ID
- chat ID
- sender ID, if relevant
- timestamp
For searchable systems, also store derived fields such as:
- list of mentions
- list of URLs
- list of commands
- formatting spans
That gives you both exact replay and efficient querying.
## Designing entity-first workflows
An entity-first pipeline usually looks like this:
1. Receive the message.
2. Extract text and entities.
3. Classify the message based on entities.
4. Transform or enrich the content.
5. Send, store, or act on the structured result.
This is better than the old text-first pattern because it preserves semantics from the moment the message arrives.
## Where this feature pays off most
Entities are especially valuable in bots that do any of the following:
- relay content between chats
- moderate community posts
- extract mentions or links
- generate formatted alerts
- build audit logs
- translate or rewrite user messages
- mirror channels or groups
- index posts for search
If your bot only responds to `/help`, entities are nice to know. If your bot is part of a production automation system, they are essential.
## Final takeaway
Telegram automation gets much more reliable when you stop treating messages as raw strings and start treating them as structured documents.
Message entities are the overlooked feature that make this possible. They let you preserve formatting, extract intent accurately, and build bots that behave correctly across links, mentions, code, Unicode, and user-generated content.
If you are already comfortable with Telegram’s basics, this is one of the highest-leverage upgrades you can make to your bot architecture.
The next time you write a parser, ask a better question than “what text is here?” Ask: “what entities does Telegram already know about this message?”