Rich Text Formatting¶
Rich Text is Telegram’s structured formatting engine used for Instant View articles, page blocks, web app responses, and modern Rich Messages (introduced in Bot API 10.1 and MTProto Layer 228+).
Unlike ordinary message text formatting (which attaches a flat list of MessageEntity
offsets on top of a string), Rich Text is a tree-based hierarchical document structure. It supports
advanced styling that ordinary messages cannot express, such as mathematical formulas (LaTeX), subscript,
superscript, highlighted text, named anchors, collapsible sections, and inline images.
Ordinary Formatting vs Rich Text¶
Feature |
Ordinary Message Formatting |
Rich Text ( |
|---|---|---|
Wire Protocol |
|
|
Methods |
|
|
Subscript & Superscript |
❌ Not supported |
✅ |
Highlighted / Marked Text |
❌ Not supported |
✅ |
Math Expressions (LaTeX) |
❌ Not supported |
✅ |
Inline Anchors & Links |
❌ Text links only |
✅ |
Collapsible Details & Blocks |
❌ Blockquotes only |
✅ Full collapsible sections & tables |
Writing and Sending Rich Text¶
Bots can send rich messages using send_rich_message() and construct the content
using InputRichMessage.
There are three ways to compose rich content:
1. Using HTML (Recommended)¶
You can write standard HTML tags including rich tags like <mark>, <sub>, <sup>, and <tg-emoji>:
from pyrogram import Client
from pyrogram.types import InputRichMessage
app = Client("my_bot")
async with app:
await app.send_rich_message(
chat_id="me",
rich_text=InputRichMessage(
html=(
"<h2>Scientific Note</h2>"
"<p>Water molecule: H<sub>2</sub>O</p>"
"<p>Einstein's equation: E = mc<sup>2</sup></p>"
"<p>Important note: <mark>Exam starts at 9:00 AM</mark></p>"
"<p>Emoji: <tg-emoji emoji-id=5469770542288478598>👍</tg-emoji></p>"
)
),
)
2. Using Markdown¶
Markdown mode supports standard styling along with blockquotes and code blocks:
from pyrogram.types import InputRichMessage
await app.send_rich_message(
chat_id="me",
rich_text=InputRichMessage(
markdown=(
"## Project Update\n\n"
"> Deployment to production is completed.\n\n"
"**Status**: All checks passed.\n"
)
),
)
3. Using Structured Blocks¶
For full control over articles, headings, tables, checkboxes, and collages, use InputRichBlock classes:
from pyrogram.types import (
InputRichMessage,
InputRichBlockSectionHeading,
InputRichBlockParagraph,
InputRichBlockList,
InputRichBlockListItem,
InputRichBlockPreformatted,
InputRichBlockDivider,
)
await app.send_rich_message(
chat_id="me",
rich_text=InputRichMessage(
blocks=[
InputRichBlockSectionHeading(text="Release v3.2", size=2),
InputRichBlockParagraph(text="Tobigram now features enhanced rich media text formatting."),
InputRichBlockDivider(),
InputRichBlockList(
items=[
InputRichBlockListItem(text="Instant View acceleration", has_checkbox=True, is_checked=True),
InputRichBlockListItem(text="LaTeX math rendering", has_checkbox=True, is_checked=True),
InputRichBlockListItem(text="Interactive checklists", has_checkbox=True, is_checked=False),
],
ordered=False,
),
InputRichBlockPreformatted(text="pip install -U tobigram", language="bash"),
]
),
)
Supported RichText Elements¶
When receiving messages or reading Instant View pages, Telegram represents formatted nodes with
the following RichText types:
Class |
Description |
|---|---|
|
Plain text without styling. |
Bold styled text. |
|
Italic styled text. |
|
Underlined text. |
|
Strikethrough text. |
|
Hidden spoiler text. |
|
Inline fixed-width code. |
|
Subscript text (e.g. chemical formulas). |
|
Superscript text (e.g. mathematical powers). |
|
Highlighted or marked text background. |
|
Animated or static custom emoji from sticker pack. |
|
Reader-localized date and time. |
|
LaTeX mathematical formula. |
|
Clickable web link URL. |
|
Clickable email address. |
|
Clickable phone number. |
|
Formatted bank card number. |
|
Named anchor target inside the article. |
|
Link jumping to a named anchor in the same document. |
|
Inline picture embedded directly into text flow. |
Rich Message Drafts & AI Composition¶
Bots can send rich message drafts to display typing states, live generated progress, or “Thinking…” placeholders:
from pyrogram.types import (
InputRichMessage,
InputRichBlockParagraph,
InputRichBlockThinking,
)
# Send a draft while computing the final response
await app.send_rich_message_draft(
chat_id="me",
rich_text=InputRichMessage(
blocks=[
InputRichBlockParagraph(text="Generating response..."),
InputRichBlockThinking(),
]
),
)
# Send the final rich message once computation completes
await app.send_rich_message(
chat_id="me",
rich_text=InputRichMessage(
html="<p><b>Done!</b> Here is your complete report.</p>"
),
)