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 |
| Cancel a schedule | Writer |
| Start, schedule 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 |
| Scheduled | Sends itself at the set time. The audience has not been built yet | "Cancel schedule" — a draft again |
| 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 |
| Not sent | A send of a repeating broadcast that did not happen. Nobody was messaged | Nothing. The reason is on its page |
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.
A segment instead of a filter
To avoid building the conditions again, press "Insert a segment": the conditions of a saved segment are copied into the draft. It really is a copy: if you later change or delete the segment, the broadcast does not change. The editor shows which segment the conditions came from and whether they still match it. You can also start a broadcast from the Segments section: a segment's "New broadcast" button opens a draft with a copy of its conditions.
A segment on the Users page can hold more people than the broadcast has recipients: the message only reaches people who opened a private chat with the bot (see below).
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.
Skip people the bot messaged recently
The "Skip people this bot messaged recently" switch sets a frequency cap: a recipient is skipped if the same bot already messaged them in another broadcast within the last N days (1 to 90). It works with every audience form, a hand-written list included.
What counts as "messaged":
| What happened to the person in another broadcast from this bot | Counts |
|---|---|
| Delivered, partially delivered | yes |
| Unconfirmed | yes: the message may have arrived |
| Being sent right now | yes |
| Queued, cancelled before sending, blocked the bot, never started the bot, account deleted, unreachable | no: nothing arrived |
| A test send | no |
Another bot is another chat, so messages from the project's other bots do not count. A recalled message does count: the person already got the notification.
The decision is made when the recipient's turn comes. One bot's broadcasts go out one after another, so two broadcasts prepared at the same time and started back to back will not send a person two messages: the second sees that the first already delivered.
The other side of that: the recipient count in the editor and in the start dialog still includes the people the cap will skip, which is why the start dialog says "at most N people". How many were skipped shows while the broadcast sends, with the status "Skipped: messaged recently".
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, or "at most N" and over how many days when a frequency cap is on;
- how many messages this draws from your monthly broadcast allowance;
- 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.
Scheduled and repeating sends
A broadcast does not have to go out straight away. "Schedule" on a draft opens a dialog with two options:
| Option | What happens |
|---|---|
| Once | The broadcast sends itself at the date and time you choose |
| Repeat | Every day, on chosen weekdays, or monthly, at a set time. You can set a date after which it stops |
The dialog shows the next sends straight away. The server works them out — the same code that will later send the broadcast. A repeating broadcast can use a time zone you choose (yours by default) and does not drift when the clocks change. A one-off is set in your own time zone.
Only an Admin can schedule, just as only an Admin can start: a scheduled broadcast goes out with nobody watching. A Writer can cancel a schedule, because that only moves a send further away.
What is checked when it sends, not when you schedule it
- The audience is rebuilt. The recipient count in the dialog is today's estimate. "Everyone active in the last 7 days" means the 7 days before the send, not before the day you scheduled it.
- Your plan's limits are checked then too: concurrent broadcasts, event quota, monthly message allowance. If one is short, the broadcast does not go out and the reason appears on its page.
- Permissions are checked again. If whoever scheduled it no longer has admin rights on the project, it does not go out, and a repeating broadcast stops altogether.
While a broadcast is scheduled its message and audience are locked. To change something, press "Cancel schedule" — it becomes a draft again — and schedule it anew.
Repeating broadcasts
Every send of a repeating broadcast is a broadcast of its own, with its own progress, recipients and recall. They are not in the main broadcast list, so daily sends do not bury your drafts: they are collected under "Send history" on the repeating broadcast's own page, each with its scheduled time and result. When the repeats end, the page says "Repeats finished".
If the previous send has not finished when the next one is due, the next one is skipped — otherwise the same people would get the same message twice in a row.
A repeating broadcast with a broad filter will message the same people on every repeat. "Skip people the bot messaged recently" carries into every send and prevents that.
Why a scheduled send might not have happened
A one-off returns to being a draft; a send of a repeating broadcast gets the status "Not sent". The reason is shown on the broadcast's page:
| Reason | What it means |
|---|---|
| Could not start in time | It was more than an hour late. A morning message arriving in the evening is worse than none |
| The filter matched nobody | Normal for a repeating broadcast such as "new users yesterday" |
| The previous send was still going | See above |
| A limit was short | Concurrent-broadcast slots, event quota or monthly message allowance |
| No admin rights | Whoever scheduled it no longer has them |
| Preparation was interrupted | Schedule it again |
No e-mail is sent when a scheduled send does not happen — the reason is shown only on the broadcast's page.
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.
Broadcast results
Every sent broadcast has a Results block under its progress: what people did after they received the message.
Each recipient is measured over their own window - from the moment it reached them, for the number of days you choose. A broadcast to a million people takes hours, and one shared window would give the first recipients hours and the last ones minutes.
| Figure | What it means |
|---|---|
| Reached | How many people the broadcast actually got to. Every percentage is out of this. |
| Replied | Wrote to the bot, pressed a button or otherwise acted inside their window. Being blocked is not a reply, and neither is a message in a group: a broadcast goes to a private chat. |
| Did the goal | How many people did the thing the broadcast was for. Shown only when a goal is set. |
| Blocked the bot | How many blocked the bot inside their window. |
| Button presses | Per button: how many people pressed it and how many presses in total. |
Below them: how many the frequency cap skipped, and how many could not be reached.
The goal
The goal is set in the composer, before sending, and saved with the broadcast. That way the report shows the same number to everyone who opens it, and the goal is chosen before the result is known rather than picked afterwards to fit a comfortable figure.
A goal is an ordinary event filter, built with the same editor as the audience. The window is chosen there too: 1 to 30 days, 3 by default.
Without a goal the report answers everything else and shows no conversion. For a broadcast already sent, the window can be switched in the results block itself.
When to trust the numbers
- "Still counting" - some recipients' windows are still open, so the figures can rise.
- "Not tracked" instead of a block count - the bot does not record membership events, so nobody knows how many people blocked it. That is missing data, not a zero: turn on membership capture in the bot's settings.
- Presses say they cannot be counted - the message carried only link buttons, and Telegram reports nothing at all when one is tapped.
- Analytics history does not reach back to the broadcast - some activity may have been removed by retention.
- The recipient list has been deleted by retention - the results cannot be rebuilt, and the block says so rather than showing zeros.
Presses count only on the messages this broadcast sent: a press on a button under another message of the bot's does not reach the report.
What it costs
Broadcast messages draw from your plan's monthly broadcast message allowance. A broadcast to 100,000 people is 100,000 messages of that allowance.
The messages themselves are not written to your analytics and spend no events from your quota, so a broadcast does not show up in event reports.
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 checks that it has room for as many events as there are messages to send, counting the project's other running broadcasts. Not enough room, and the start is refused, stating what is needed and what is left. The messages themselves spend none of it |
| 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.
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, an audience window reaching back at most 730 days, and a frequency cap of 1 to 90 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 |
| Skipped: messaged recently | The frequency cap applied: this bot had already messaged the person in another broadcast within the chosen number of days |
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
- 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