Free tool
Telegram text formatting, with the escaping done for you
Your message has a price in it, a hyphen and a full stop, and the Bot API answers with "can't parse entities". MarkdownV2 reserves 18 characters, and a plain English sentence usually contains four or five of them. Write the message here, pick bold or a spoiler or a code block, and copy the output with every one of those characters already escaped.
Write your message
Select text and apply a style, or type the tags yourself. The box works in Telegram's HTML syntax, so what you edit is already valid for one of the two outputs. The preview is a picture of the message, not a send button: nothing here leaves your browser.
Characters 198 of 4096
Past 4096 characters. Telegram will reject this as a single message, so split it or move the long part into a file.
Telegram counts visible characters, so the markup itself is free. Entities and the formatting tags do not count against the limit.
Fixed: the CSV import dropped rows ending in a comma.
Reported by three of you on the same day.
Run
npm i -g entergram@2.4 to upgrade.The migration note is boring but mandatory.
MarkdownV2
*Release 2\.4 is out\.* Fixed: the CSV import dropped rows ending in a comma\. >Reported by three of you on the same day\. Run `npm i -g entergram@2.4` to upgrade\. The migration note is ||boring but mandatory||\.
Send with parse_mode=MarkdownV2. Every reserved character in ordinary text is escaped; inside a code span only the backslash and the backtick are.
HTML
<b>Release 2.4 is out.</b> Fixed: the CSV import dropped rows ending in a comma. <blockquote>Reported by three of you on the same day.</blockquote> Run <code>npm i -g entergram@2.4</code> to upgrade. The migration note is <tg-spoiler>boring but mandatory</tg-spoiler>.
Send with parse_mode=HTML. Fewer things to escape, which is why most libraries default to it.
The syntax, both parse modes
Telegram accepts three parse modes. Markdown is the legacy one and supports four styles; MarkdownV2 and HTML support all ten. This table is MarkdownV2 and HTML side by side.
| Style | MarkdownV2 | HTML |
|---|---|---|
| Bold | *bold* | <b>bold</b> |
| Italic | _italic_ | <i>italic</i> |
| Underline | __underline__ | <u>underline</u> |
| Strikethrough | ~strike~ | <s>strike</s> |
| Spoiler | ||hidden|| | <tg-spoiler>hidden</tg-spoiler> |
| Inline code | `code` | <code>code</code> |
| Code block | ```python code ``` | <pre><code class="language-python">code</code></pre> |
| Blockquote | >quoted line | <blockquote>quoted</blockquote> |
| Inline link | [text](https://example.com) | <a href="https://example.com">text</a> |
| Custom emoji |  | <tg-emoji emoji-id="5368324170671202286">👍</tg-emoji> |
Underline and italic cannot simply be nested in MarkdownV2, because __ and _ collide at the boundary. Use HTML when you need both on the same run of text.
Why MarkdownV2 keeps rejecting your message
MarkdownV2 reserves eighteen characters, and outside a code entity every single one of them must be preceded by a backslash, even where it could not possibly be read as markup. The list is _ * [ ] ( ) ~ ` > # + - = | { } . ! and, because it is the escape character itself, the backslash.
Two of those are the reason this trips almost everybody. The full stop ends most sentences. The hyphen appears in dates, ranges, flags and compound words. A release note that reads "Fixed: the 2.4-rc build" has three reserved characters in nine words, and the API rejects the whole message rather than passing the text through.
The rules change inside an entity, which is the second thing people get wrong. In a code span or a code block, only the backslash and the backtick are special, so escaping the rest there puts visible backslashes in your code. Inside the parentheses of a link or a custom emoji, only the closing parenthesis and the backslash are. The tool above applies the right rule per context, which is the part a search-and-replace cannot do.
If none of this appeals, use HTML. It escapes three characters, &, < and >, and it nests without the ambiguities. The one reason to prefer MarkdownV2 is that it is easier to read in source control.
The 4096-character limit counts text, not markup
A Telegram text message holds 4096 characters. Formatting is carried as entities alongside the text rather than inside it, so the tags, the asterisks and the backslashes you see in the output do not count. The counter above shows the visible length, which is the number Telegram checks.
Two limits sit near it and are worth knowing before you build a sender. A media caption holds 1024 characters, so a formatted message that fits fine on its own will be rejected once you attach an image. A message over the limit is not truncated; the API returns an error and sends nothing.
Questions
Does this work for channel posts and ordinary chats, or only bots?
The syntax table applies to anything that sends through the Bot API or a client library. If you are typing into Telegram yourself, the app has its own formatting menu and you never see MarkdownV2 at all. This tool is for the case where something else does the sending and needs the text pre-formatted.
Which parse mode should I use?
HTML, unless you have a reason. It escapes three characters instead of eighteen, it nests predictably, and the failure mode when you get it wrong is usually a visible tag rather than a rejected message. MarkdownV2 reads better in a source file, which is the honest argument for it.
Why did my message send but lose its formatting?
Almost always a missing parse_mode. Without it Telegram treats the text as literal, so the asterisks and the tags show up as characters. Set parse_mode to MarkdownV2 or HTML on the send call, matching whichever output you copied.
Can I nest bold inside a link, or italic inside bold?
Yes, in both parse modes, with one exception: underline and italic together in MarkdownV2 need a workaround because the delimiters collide. Code spans and code blocks cannot contain any other style at all, in either mode.
What is the custom emoji ID and where do I get one?
It is the numeric ID of a premium custom emoji, and you read it off a message that already contains the emoji rather than from a public catalogue. The sender needs Telegram Premium, or needs to be a bot that owns the sticker set. Everyone else sees the fallback character you wrapped.
Does anything I type here get uploaded?
No. The conversion runs in your browser and the page has no send step, no account and no storage. Close the tab and the message is gone.
Keep going
Also free: Telegram Group Finder , Telegram Lead Finder , Free QR Code Generator .
If the formatting is for a message you are about to send to 200 people
Pre-escaped text is the small half of a broadcast. The larger half is sending it from an account people will actually reply to, pacing it so Telegram stays happy, and catching the replies somewhere other than a phone. Entergram does that part: real personal Telegram accounts rather than a bot, each on its own proxy, with the replies landing in one interface against the contact record.
See how broadcasts work