Telegram Studio

Visual Telegram MarkdownV2 & HTML markup editor, message bubble simulator, TMA InitData decoder, 64-byte callback checker, bot command & deep-link builder, and multi-language payload generator. All processing runs 100% locally in your browser.

Parse Mode:
Allowed tags: b/strong, i/em, u, s/strike/del, code, pre, a[href], span[class=tg-spoiler]. Anything else is stripped in preview and by Telegram.

Unescaped Character Diagnostics ({{ escapeDiagnostics.length }} flagged)

Highlighted characters are MarkdownV2 reserved characters not preceded by \. Some may be intentional formatting (e.g. * around bold text) — this is a raw diagnostic, not an entity-aware parser. Use Auto-Escape Text to escape everything literally.

Paste Telegram Mini App initData string

This inspector decodes the launch parameters so you can read what Telegram sent. It deliberately does not check the signature — verifying initData needs your bot token, and keeping one verified implementation instead of two means there is only one place for the algorithm to be wrong. For HMAC-SHA256 verification, signing, and the step-by-step algorithm trace, use Telegram Webhook Tester.

Inline Keyboard Builder (64 UTF-8 Byte Checker)

Row #{{ rIdx + 1 }}
Button #{{ bIdx + 1 }}
UTF-8 Bytes: {{ getByteLength(btn.value) }} / 64
⚠ callback_data is empty — Telegram rejects empty callback_data.
⚠ Exceeds Telegram's 64-byte callback_data limit.
⚠ Button text is empty.

Bot Commands

Preset:
Scope:
chat_id:
user_id:
language_code: Telegram falls back to the empty-language list when a user's language has none.
{{ issue }}

Order is preserved exactly as sent — Telegram shows the menu in this order, not alphabetically.

Deep Links

Bot username:
Link type:
Mini App short_name:
Payload as: Encoding:
{{ payloadBytesLabel }}
{{ issue.text }}

Decode a link

Paste any of the four shapes above — the components and the decoded payload appear on the right.

Method & Format

Method:
chat_id:
message_id:
callback_query_id:
Answer text:
{{ apiMethod==='sendPhoto' ? 'Photo URL:' : 'Document URL:' }}
Caption:
Format:
Escaped Output (Safe for {{parseMode}})
{{ escapedOutput }}
Telegram Chat Live Bubble Preview
AlexRel Bot
{{ currentTime }}
{{ btn.text || 'Button' }}
Parsed Key-Value Claims
KeyParsed Value
{{ item.key }}
{{ item.value }}
{{ item.value }}
No valid initData parsed yet. Enter a query string on the left.
Live reply_markup JSON
{{ JSON.stringify(buildReplyMarkupJson(), null, 2) || '(no buttons yet)' }}
Warnings
  • {{ issue }}
How to apply this command list {{ botFatherPossible ? 'BotFather or API' : 'API only' }}
{{ botFatherSteps }}
Command list
{{ commandExport || '(add commands on the left)' }}
Deep links
{{ deepLinksText }}
{{ primaryLink }}

{{ qrError }}

Decoded link

Paste a deep link on the left to take it apart.

{{ decodedLink.error }}

{{ row.key }}{{ row.value }}
Payload Exporter
{{ generatedCodeSnippet }}
About Telegram Studio

Telegram Studio covers the outbound half of Telegram development — everything you compose and send. Escape MarkdownV2 & HTML special characters with an XSS-safe allowlist-sanitized preview, decode TMA initData fields, inspect 64-byte callback limits, build BotFather command lists and start/startapp deep links, and generate production-ready, method-aware code snippets.

Command scopes. A bot does not have one command list, it has one list per (scope, language_code) pair, and Telegram resolves the most specific scope that matches before falling back to the empty-language list. The catch nobody documents in the same place: BotFather's /setcommands prompt cannot set either of them. It always writes the default, all-languages list. Anything narrower — a groups-only list, an admins-only list, a Russian list — has to go through the setMyCommands API, which is why this tab tells you which of the two routes your current settings actually allow.

Deep links. ?start= opens the bot chat with a payload, ?startapp= launches the Mini App, https://t.me/<bot>/<app>?startapp= launches a specific named Mini App, and ?startattach= opens the attachment menu. All of them share one hard rule: the payload may be at most 64 characters from A–Z a–z 0–9 _ - only. That character set is exactly base64url, and exactly not standard base64 — which emits +, / and = and produces a link Telegram silently refuses to carry. Encoding is base64url here by default for that reason, and the builder shows the encoded length because base64 inflates a payload by roughly a third, so 64 characters of link is closer to 47 bytes of data.

Companion tools: for the inbound half — decoding webhook Update payloads, replaying them to your endpoint, and cryptographically verifying initData or Login Widget callbacks — use Telegram Webhook Tester. To charge for any of it, build the createInvoiceLink payload with Telegram Stars Invoice.

Privacy: 100% Client-side. All processing happens in your browser. Bot tokens, keys, and message contents are never transmitted to external servers.
{{ toast.msg }}