Converting Telegram Messages to X Posts: Weighted Character Counts, Entities, and URLs in 2026

By AutoX Editorial (gspteck) · Published 2026-10-06 · Last verified 2026-10-06

Operators of Telegram→X schedulers often run into the same failure. A draft looks short in Telegram, gets approved, and then X rejects it at publish time, or it goes out with a dead link because the clickable text in Telegram had no visible URL. The cause is almost always text conversion. Telegram and X count characters differently, carry links differently, and support different formatting. This guide explains how to turn a Telegram message, meaning its text plus its entities, into valid X Post text, and how to show the operator an accurate count before approval. It builds on our posts about approval gates and duplicate-content fingerprints, and it is engineering guidance, not a reach or growth promise.

Two platforms, two ways of counting

Start with what each side documents. Re-check these pages before you ship, because both APIs change:

So a Telegram length check tells you almost nothing about whether X will accept the Post. You have to compute X’s count yourself, on the converted text.

Four-step pipeline: receive Telegram text and entities, map entities, normalize to NFC and compute weighted count, preview and approve
Convert first, count second, approve last. The count the operator approves must be the count of the exact text the worker will send to X.

What the v3 weight table actually means

The v3 config sets maxWeightedTweetLength to 280, scale to 100, defaultWeight to 200, and transformedURLLength to 23. Only four code-point ranges get weight 100, which means 1 visible character:

Everything else weighs 2. That has consequences an operator won’t see in Telegram. The arrow → (U+2192) and the ellipsis … (U+2026) each count as 2. Hangul and CJK count as 2. The “𝐛𝐨𝐥𝐝” letters some tools generate to fake formatting come from the Mathematical Alphanumeric Symbols block, so they count as 2 each, and screen readers often read them poorly. A caption full of arrows and styled letters can be noticeably “longer” on X than it looks in Telegram.

Comparison of characters weighted 1 (Latin, Cyrillic, Arabic, dashes and curly quotes) versus weighted 2 (emoji, CJK and Hangul, arrows, ellipsis, math-styled letters)
Under twitter-text v3, only a few ranges weigh 1. Arrows, the ellipsis character, CJK, Hangul, emoji, and styled “bold” letters all weigh 2.

Slice Telegram entities in UTF-16, not code points

The most common conversion bug is slicing entities with the wrong unit. JavaScript strings are UTF-16, so text.slice(offset, offset + length) lines up with Telegram’s offsets. Python strings index by code point, so any emoji outside the Basic Multilingual Plane, which is two UTF-16 units, shifts every later entity by one. The result is a link wrapped around the wrong word, or a mention that loses its last letter. In Python, slice on the UTF-16 encoding:

def tg_slice(text: str, offset: int, length: int) -> str:
    b = text.encode("utf-16-le")
    return b[offset * 2:(offset + length) * 2].decode("utf-16-le")

Process entities from the end of the string toward the start when you rewrite text, so earlier offsets stay valid. Apply NFC only after you have finished applying entities, because normalization can change UTF-16 lengths.

Map each entity type deliberately

X Post text is plain text, so every Telegram entity needs an explicit rule. Here is a mapping we consider sensible for operator-run schedulers:

Six Telegram entity mappings: url kept at 23, text_link appended or flagged, mention mapped or stripped, styles stripped, spoiler blocks approval, bot_command removed
Give every entity type an explicit rule. The dangerous ones are text_link (lost URLs), mention (wrong X account), and spoiler (exposed text).

Count before approval, and again before publish

Put the conversion and the count in front of the human gate, not behind it:

  1. Convert on receipt. When a draft arrives, build the X text with the mapping above, normalize it to NFC, and run twitter-text’s parser on the result. Store the converted text and its weightedLength with the draft.
  2. Show the operator the result, not the input. Reply in Telegram with the converted text, the count (for example, “271/280”), and any warnings: an appended link, a stripped mention, a blocked spoiler. Approval then covers what will actually be published.
  3. Reject over-length drafts early. If valid is false, say by how much it is over and don’t offer the approve button. Do not auto-truncate. A Post cut mid-sentence or mid-URL is worse than a delayed one.
  4. Re-validate in the worker. Just before calling Create Post, recompute the count on the exact payload. If an edit or a config change slipped in after approval, the job should fail closed into your dead-letter queue (see failed-publish retries and dead letters) rather than burn a request on a guaranteed rejection.
  5. Hash the converted text. Compute duplicate fingerprints and idempotency keys on the normalized X text, not the raw Telegram text. Otherwise two drafts that differ only in bold formatting count as “different.” See client-request-id idempotency.

Attached media counts as 0 characters, according to X’s page, so moving an image link into a real upload saves 23 characters. Our media upload pipeline post covers that path. Some account tiers allow longer Posts. Treat that as a per-account setting you look up, not a constant you hard-code.

Approval flow: draft up to 4096 characters in Telegram, bot computes weighted length, over 280 returns overflow, valid drafts reach the approve gate
Telegram accepts up to 4096 characters, X accepts 280 weighted. The bot has to bridge that gap before the approve button appears.

Test cases worth keeping in CI

Pin your twitter-text version and record it with each published job. That way, if counting rules change later, you can explain why an older Post was accepted.

Practical checklist

Key takeaways

Character weights, limits, and entity definitions summarized here come from X’s and Telegram’s public developer documentation and the twitter-text v3 configuration as of 2026-10-06. They can change, so confirm them on docs.x.com and core.telegram.org before relying on them. No affiliate links. Last verified 2026-10-06.