Broadcasts
The Broadcasts section sends one message to a chosen audience of your bot's users. The audience is built with the same filters as your reports, so "message everyone who pressed the button but never paid" is not a CSV export and a third-party service — it is a few clicks in the same place you read your analytics.
A broadcast moves through states: draft → prepare → start. The split is deliberate: between "I have finished writing" and "the message has reached people" there is a step that freezes the text and shows the exact recipient count before anything goes out.
Who can do what
| Action | Minimum role |
|---|---|
| View broadcasts, recipients and progress | Reader |
| Create, edit, delete a draft | Writer |
| Send a test | Writer |
| Prepare, and move back to draft | Writer |
| Start and recall | Admin |
Starting and recalling require an administrator for a real reason: a message sent to a million people cannot be "changed back", unlike a widget on a dashboard.
Broadcast states
| State | What it means | What can still be undone |
|---|---|---|
| Draft | Text and audience are editable. Nothing has been sent | Everything. A draft can be deleted outright |
| Preparing | The recipient list is being built. Minutes, for a large audience | Wait for it to finish |
| Ready to send | The recipient list is fixed and the message is frozen | "Back to draft" — the list is discarded and the text is editable again |
| Sending | Messages are going out | Only "Recall": sending stops and delivered messages are deleted |
| Completed | Every recipient has been processed | Only "Recall" — and only while the deletion window is still open |
| Recalling | Sending has stopped; delivered messages are being deleted | Wait for it to finish |
| Recalled | The recall has finished | Nothing. This is a record of what happened |
A broadcast that has been sent cannot be deleted: it is the record that real people received a real message. Only a draft is deletable.
After preparing, the text, buttons and attachment cannot be changed — an edit is refused. That is deliberate: a broadcast whose first half received one text and second half another can neither be explained to recipients nor recalled correctly. To fix the text, press "Back to draft".
Audience
The audience is defined by exactly one of four forms — it is a choice, not a set of independent fields.
| Form | Who receives it |
|---|---|
| All time | Everyone the bot can message, however long ago they were active |
| Last N days | Everyone active in the last N days. Counted back from the moment you prepare, not from when you opened the draft |
| Exact dates | Everyone active between two dates. The bounds do not move, whenever the broadcast goes out |
| A list | Only the people you name |
The first three can be narrowed with a filter — the same builder as
analytics filters: by event, by property, by a $tg.* value. "All time
plus a condition" is how you reach everyone who ever did a particular thing.
The relative window is the normal choice, and that is exactly why it is resolved at prepare time: "active in the last 30 days" has to mean the 30 days before the send, not the 30 days before the draft was created.
Who is in the audience, and who is not
The audience is built from events, not from the user list. The reason is simple: a user record does not prove the bot has anywhere to write, whereas an event in a private chat does.
So the audience excludes:
- people who only ever talked to the bot in a group — Telegram forbids a bot from writing first, and such a send is guaranteed to fail;
- people who never opened a private chat with the bot.
If the estimate says nobody matches while the bot clearly has users, this is almost always why.
The audience is a snapshot taken at prepare time. It proves a private chat existed inside the chosen window; it does not prove the person has not blocked the bot since. Those recipients are filtered out at send time and show up in the breakdown as "The user blocked the bot".
The recipient estimate
A live estimate — "N people will receive this" — sits under the filter. It is counted up to your plan's limit rather than exactly: an exact count across a project's whole history is the most expensive query in the product, and the editor only ever asks two questions — "roughly how many" and "is this over the limit". Above the limit you see "more than N people match".
A hand-written list
In A list mode recipients are typed one per line: a numeric Telegram ID or a @username.
- Up to 10,000 entries — IDs and handles together. Your plan's recipient limit applies on top.
- An ID must be positive: a negative one is a group or a channel, and a broadcast only reaches private chats.
- A
@usernamecan only be resolved among people the bot has already seen: Telegram gives a bot no way to look up an ID by name. Handles that resolve to nobody are listed in the editor — before the send, while you can still do something about it. @durov,t.me/durovandDurovare all accepted and normalised.- Filters do not apply in this mode: narrowing a hand-written list with a condition would silently drop people you named on purpose.
The message
Text and formatting
| What | Limit |
|---|---|
| Message text | 4096 characters |
| Caption, when a file is attached | 1024 characters |
Both are Telegram's limits, not ours. The gap between them is the trap: attaching a file to already-written text cuts the limit fourfold, and Telegram then refuses the whole send rather than truncating. The editor warns about this immediately.
The formatting toolbar gives bold, italic, underline, strikethrough, spoiler, monospace, blockquote and links. The markup is stored separately from the text, so you neither need nor should write HTML or Markdown by hand.
Two switches sit beside the text:
- No link preview — a link will not expand into a card with an image and description.
- Silent — the notification arrives without a sound. For a large broadcast this is noticeably more polite.
Buttons
An inline keyboard can be built under the message.
| What | Limit |
|---|---|
| Rows | 12 |
| Buttons per row | 8 |
| Button label | 64 characters |
callback_data | 64 bytes |
A button carries either a URL or callback_data — exactly one of the two. The URL must be
absolute, scheme included: https://example.com, not example.com; http, https and tg are
accepted.
callback_data is counted in bytes, not charactersCyrillic costs two bytes per character, emoji cost more. Russian text runs out at roughly 32 characters. The editor shows the counter in bytes.
callback_data has a picker listing the values your bot has actually received. If what you type
is not in that list, the editor flags it: the button will most likely do nothing when pressed — unless
you have just taught the bot that value.
Attachment
One file can be attached to the message.
| Kind | Size limit |
|---|---|
| Photo | 10 MB |
| Video, GIF/animation, audio, voice, document | 50 MB |
These are Bot API ceilings. The widely quoted 2 GB is a consumer-app number that does not apply to bots.
You choose the kind, and it matters: a GIF sent as a "document" will not play, and a voice message is only accepted as OGG — an MP3 arrives as an ordinary file. Metriox inspects the file's contents and will not let you send, say, an image labelled as a video.
The file library
Uploaded files stay in the project's library and are reused: the same image never has to be uploaded twice. The library shows how much space is used, which files broadcasts reference, and lets you delete what you no longer need.
- Deleting a file un-sends nothing. Copies already delivered stay in recipients' chats.
- A file held by an unfinished broadcast cannot be deleted: until that broadcast sends its first message, those bytes are the only copy.
- Files no broadcast references are removed automatically after the period set by your plan (180 days by default). A file attached to a draft is left alone however old it is.
The file is uploaded to Telegram once, on the broadcast's first send, and reused after that. A test send does it in advance.
Test send
"Send a test" delivers the message to a single chat — usually your own — down the exact same path a real broadcast takes: the same queue, the same sender, the same error handling. A test that took a different path would prove nothing about the path that actually runs.
How a test differs from the real thing:
| Test | Broadcast | |
|---|---|---|
| Who receives it | The one chat you name | The whole prepared audience |
| Allowed from | Draft included | Ready to send only |
| Which text | The current draft, if not yet prepared | The one frozen at prepare |
| Broadcast status | Unchanged | Changes |
| Broadcast counters | Not counted | Counted |
| Recalling the broadcast | The test is not deleted | Delivered messages are deleted |
Use a chat you control. The most common first failure is "Never started the bot":
Telegram does not let a bot write first. Open the chat, press /start, and try again.
If a test was sent from a draft and the text changed afterwards, the real broadcast will go out different. The editor warns about this.
Prepare, start and cancel
Prepare
"Prepare for sending" does two things: it freezes the message and builds the recipient list. Nothing is sent.
- For a large audience this takes minutes. Pressing it again is safe: preparation resumes where it stopped rather than starting over.
- A broadcast with zero recipients is refused. Otherwise it would complete instantly and look, in the progress panel, exactly like one delivered perfectly.
- An audience above your plan's limit is refused too — before a single row is written.
A prepared broadcast occupies one of your plan's concurrent-broadcast slots. If it is not started within 7 days it returns to drafts and frees the slot; the same happens to a preparation stuck for more than an hour.
"Back to draft" is the inverse: the recipient list is discarded and the text becomes editable again. It moves a broadcast further from going out — the safe direction — which is why it needs no administrator. Preparing again rebuilds the audience: anyone who joined since is included, anyone who blocked the bot is not.
Start
"Send now" is available only from Ready to send, and only to an administrator. The confirmation dialog shows:
- how many people will receive the message;
- roughly how many events this will draw from your quota;
- the approximate duration — messages go out at about 25 per second per bot (below Telegram's own ceiling, because the bot's own replies share it);
- a reminder about the recall window.
If the broadcast changed while the confirmation dialog was open, the start is refused: the figures you agreed to are the entire basis of that agreement.
There is no "cancel the start". The only recourse is to recall the broadcast — and only for the messages that still fall inside Telegram's deletion window.
Cancel
"Recall" does two things at once:
- It stops sending. Anyone whose turn had not come is marked "Cancelled before sending" — rather than left queued forever.
- It starts deleting messages already delivered. That is the next section.
Recalling a delivered broadcast
Metriox can delete already-delivered messages from recipients' chats. This is not cancelling a send — by the time you recall, the messages exist in people's conversations; Metriox walks the recipient list and removes them.
The deletion window
Telegram allows a bot to delete its own message only within 48 hours. That is Telegram's own limit and cannot be worked around. Metriox stops trying at the 47th hour — an hour early, on purpose: the send time is recorded when the sender reports the outcome, slightly after the real send, and the margin covers that difference along with the recall's own queue time.
This matters more than it looks. Sending runs at about 25 messages per second, so a large broadcast is spread over hours: the first recipient's window closes before the last one's. A recall two days later may delete the tail of a broadcast and fail to delete its beginning.
In practice: recall as soon as you realise the wrong broadcast went out. Assume you have less than two days, not exactly 48 hours.
What actually happens
- Only delivered messages whose Telegram identifier was recorded are deleted.
- Messages older than the window are marked "Could not delete" without contacting Telegram. That is why recalling a week-old million-recipient broadcast is instant: there is nothing to ask.
- If a message is already gone — deleted by the recipient, say — that counts as success. The goal is that the message does not exist, and it does not.
- Deletion only. Metriox does not replace an old message with different text: a broadcast older than the deletion window cannot be taken back at all, and the product says so plainly instead of staging the appearance of a recall.
- Test sends are left alone by a recall.
What you see
The progress panel gains a "Recall progress" block with "Deletion attempts" and "Deleted" counters, and each recipient shows its own state: "Still in the chat", "Deleted" or "Could not delete".
Recall works on a completed broadcast as well as a running one — provided the messages still fall inside the window.
What it costs
Every broadcast message sent is one event against your analytics quota. A broadcast to 100,000 people spends 100,000 events of the project's monthly allowance — the same allowance whose exhaustion stops event ingestion and breaks your own analytics. Better to learn that here than from an invoice.
Delivered messages appear in your analytics as message.outbound events, so a broadcast is visible in
reports alongside the rest of the bot's traffic.
A broadcast is bounded by two ceilings, and the smaller one binds:
| Ceiling | What it is |
|---|---|
| Monthly event quota | The project's overall quota. Starting reserves as many events as there are messages to send. Not enough room, and the start is refused, stating what is needed and what is left |
| Monthly broadcast message limit | A separate limit on broadcasts specifically. Attributed to the period the broadcast was started in |
The check runs once, at start. After that the broadcast runs to completion: a started broadcast cannot stop halfway because someone else's traffic used up the quota. A half-sent announcement is worse than an overage.
The editor's recipient estimate is also the cost estimate: one recipient, one message, one event.
Limits
Telegram's limits, the same for everyone:
| What | Value |
|---|---|
| Message text | 4096 characters |
| Caption with an attachment | 1024 characters |
| Button label | 64 characters |
callback_data | 64 bytes |
| Keyboard | 12 rows of 8 buttons |
| Attachments per message | 1 |
| Photo size | 10 MB |
| Other file sizes | 50 MB |
| Message deletion window | 48 hours (Metriox stops trying at the 47th hour) |
Plan limits — these are the defaults; your plan may be more generous:
| What | Free | Paid plans |
|---|---|---|
| Recipients in one broadcast | 100,000 | 1,000,000 |
| Concurrent broadcasts | 5 | 50 |
| Broadcast messages per month | 25,000 | 5,000,000 |
| File storage | 1 GB | 20 GB |
| Automatic removal of unused files | after 180 days | after 180 days |
| Recipient list retention | 365 days | 365 days |
Separately: up to 10,000 entries in a hand-written list, and an audience window reaching back at most 730 days.
Once retention expires the per-row list is deleted and only the totals remain. After that you can no longer see what happened to one particular person, or whether they received the message at all. It does not affect recall: the 48-hour deletion window closes long before any retention period does.
Recipient statuses
| Status | What happened |
|---|---|
| Queued | Not attempted yet |
| Sending | The message is in flight |
| Delivered | Telegram accepted the message |
| Partially delivered | Some messages arrived and some did not |
| Cancelled before sending | The broadcast was recalled before their turn came |
| The user blocked the bot | Ordinary in any broadcast |
| Never started the bot | There is no private chat, and Telegram does not allow writing first |
| Account deleted | The user no longer exists |
| Unreachable | Telegram found no such chat |
| Unconfirmed | The message was sent, but no confirmation came back |
The message most likely arrived. Telegram offers no way to check after the fact, so Metriox does not resend: rare uncertainty beats a person receiving the same announcement twice.
What broadcasts do not do
- Scheduled sending. A broadcast goes out when you start it.
- Albums, or several files in one message. One attachment per message.
- Editing a delivered message. A recall is a deletion, and only inside the window.
- Resending to recipients whose status is "Unconfirmed".
What's next?
- Filters — how to target an audience more precisely
- Users — what a user record is made of
- Events — what consumes quota and how it is counted
- MCP: tools — the same broadcasts, driven by an AI agent