guide

Telegram post formatting: bold, spoilers, links, and what breaks

Every text style Telegram renders, how the 4096-character limit is actually counted, and the five formatting mistakes that turn a post into visible punctuation.

Published 29 August 2026

TL;DR

Telegram renders nine text styles and nothing else — there are no headings and no tables. Most broken posts come from one of two things: markdown written for a renderer Telegram does not have, or a message cut to length after it was converted, which splits a tag in half.

Key takeaways

  • No headings, no tables, no nested lists. A markdown heading renders as a literal hash character.
  • The 4096 limit is counted in UTF-16 code units, not characters. An emoji outside the basic plane costs two.
  • Media captions are capped far lower than messages — around 1024 — so a post that fits as text may not fit under a photo.
  • Formatting survives copy-and-paste inside Telegram, because it travels as entity ranges rather than as markup.
  • Cut before you convert, never after. Truncating finished markup is what produces a half-open tag and a rejected message.

What Telegram actually renders

StyleRendersNotes
BoldYesThe one style worth using in almost every post.
ItalicYesTitles, quoted phrases.
UnderlineYesRare in practice; reads as a link that isn't one.
StrikethroughYesCorrections and before/after.
SpoilerYesHidden until tapped.
Inline codeYesSuppresses all formatting inside it.
Code blockYesMulti-line, optional language label.
BlockquoteYesLine-level, and can be made expandable.
LinksYesInline text links, not just bare URLs.
HeadingsNoA leading hash renders literally.
TablesNoBecomes a wall of pipe characters.
Nested listsNoIndentation is not interpreted.
Images inside textNoMedia is attached to a message, not embedded in it.

The absence of headings is the one that catches people out most, because almost every drafting tool produces them. If your draft needs headings to be navigable, it is structured like an article and needs rewriting as a post.

The two ways to send formatting

A post can carry its formatting in one of two forms, and it is worth knowing which one you are using.

As markup, where the text contains markers a parser interprets. Telegram accepts an HTML subset and a markdown dialect called MarkdownV2. The HTML subset is the more forgiving of the two — it uses ordinary tags, and a stray angle bracket in prose is far rarer than a stray asterisk or full stop.

As entities, where the text is plain and the formatting travels beside it as a list of ranges: bold from offset 12, length 6. This is what Telegram itself uses internally, and it is why formatting survives when you copy a post inside the app — you are copying the ranges, not markup that needs re-parsing.

MarkdownV2's escaping requirement is the usual source of trouble. These characters must each be preceded by a backslash anywhere they appear literally:

_ * [ ] ( ) ~ ` > # + - = | { } . !

That includes the full stop, which appears in essentially every sentence. Sending unescaped prose as MarkdownV2 is the single most common way a post fails to send at all.

How the 4096 limit is really counted

The limit on a text message is 4096, and on a media caption it is far lower — around 1024. But the unit is not what most people assume.

Telegram counts UTF-16 code units. For ordinary Latin text that is the same as counting characters. For anything outside the basic multilingual plane — most emoji, and every skin-tone or flag sequence — one visible glyph costs two units, and a composed emoji can cost considerably more.

The practical consequences:

  • An emoji-heavy post is closer to the ceiling than its character count suggests.
  • A length check written with a naive character count will disagree with Telegram's, and will disagree only on the posts that were already near the limit.
  • Escaping and conversion both expand text. A quote-heavy post grows substantially once converted to the HTML subset, because each quote mark becomes a multi-character entity. Text that fitted as source may not fit as markup.

Five things that break a post

1. Cutting after converting. If you truncate a message that already contains markup, the cut can land inside a tag — and a half-open tag is a rejected message, not a slightly odd-looking one. Cut the source text first, then convert. Done in that order an unclosed marker simply renders as a literal character, which is untidy but harmless.

2. Assuming headings exist. A line beginning with a hash renders as a hash. So does the second one, and by the fourth your post has visible punctuation where its structure should be. Use bold on its own line instead.

3. Pasting a table. Tables do not render, and a table pasted as pipes is unreadable in a phone-width column. Rewrite the rows as short lines, or cut the comparison down to the two rows that mattered.

4. Unescaped punctuation in MarkdownV2. See the character list above. A single unescaped full stop is enough for the message to be rejected.

5. Formatting inside code spans. Inline code and code blocks suppress everything within them — bold inside a code span stays literally as asterisks. That is correct behaviour, and surprising the first time you meet it.

Test before you publish

Send the post to yourself, or to a private channel with one member, and read it on a phone. That catches, in about ten seconds, all of the things a desktop editor hides: where the "read more" fold lands, whether the preview card swamps the opening, whether a line break you intended survived, and whether the emoji you used renders at all on your platform.

If you publish weekly, this is the step to make automatic rather than the one to skip.

How Ingy handles this

Ingy writes posts in a markdown subset chosen to match what Telegram actually renders, then converts to the HTML form at send time — so the draft you read in the bot is the post your channel gets. Length is measured in Telegram's own units, and any truncation happens to the source before conversion, never to finished markup. You copy one message into your channel with its formatting intact.

The editorial half of the job — deciding what the post is about — is covered in how to turn an article into a Telegram post.

Frequently asked questions

Does Telegram support markdown headings?

No. A line beginning with a hash character renders as a literal hash. Telegram has no heading style at all — use bold on its own line where you would otherwise use a heading.

What is Telegram's character limit for a post?

4096 for a text message and roughly 1024 for a caption attached to media. Both are counted in UTF-16 code units rather than characters, so emoji outside the basic multilingual plane count as two or more each.

Why does my formatted message fail to send?

Almost always an unescaped character in MarkdownV2 or a tag that was split by truncation. MarkdownV2 requires a backslash before each of a long list of characters including the full stop, and cutting a message to length after converting it can leave a tag half-open.

Can I use tables in a Telegram post?

No. Pipe-delimited tables render as literal pipes and are unreadable on a phone. Rewrite the two rows that carry the point as short lines of prose.

Does formatting survive copy and paste?

Inside Telegram, yes — formatting travels as entity ranges attached to the text rather than as markup, so a copied post keeps its bold and links. Pasting into an external editor generally loses it.

Can I hide part of a post behind a spoiler?

Yes. Telegram has a spoiler style that stays hidden until the reader taps it, available in both the HTML subset and MarkdownV2.

Send Ingy the last link you read.

Open Ingy in Telegram
3 posts free · no card