Telegram Mini App notifications: how to send push messages through the bot
A Mini App has no push of its own: notifications arrive as bot messages, and you can write to a user only after they start the bot or grant access with requestWriteAccess. To open the right screen use a web_app button or a direct link with the startapp parameter. Mark users who blocked the bot and stop messaging them.
A Mini App opens inside Telegram, but it has no push notifications of its own. Everything a user receives “outside the app” is a message from the bot. Here is how it works and which mistakes get in the way most often.
How notifications work
A Mini App is always tied to a bot. When you need to notify a user (a new item appeared, a price dropped, an order is ready), your server calls the sendMessage Bot API method as the bot. The message arrives in the private chat with the bot and Telegram shows an ordinary notification.
For the bot to write to a user one of these must be true:
- the user started the bot (pressed “Start”);
- the Mini App requested permission to message the user and they agreed.
How to get permission from a Mini App
If a user opened the app through a direct link and never started the bot, you may not be allowed to write to them. The user data in initData has an allows_write_to_pm flag. If it is not set, ask for permission:
const tg = window.Telegram.WebApp;
if (!tg.initDataUnsafe.user?.allows_write_to_pm) {
tg.requestWriteAccess((granted) => {
// granted === true: you can send messages
});
}
The requestWriteAccess method is available in Bot API 6.9 and newer. Check support in your users' clients and keep a fallback: an “Enable notifications” button that opens the bot chat.
Do not ask for permission on first launch. The best moment is when it makes sense: after the user presses “Subscribe to new listings” or “Tell me about the price”.
Sending a notification
The ID of the private chat with a user equals their user_id. The server calls:
import requests
def notify(token: str, user_id: int, text: str, app_url: str) -> bool:
r = requests.post(
f"https://api.telegram.org/bot{token}/sendMessage",
json={
"chat_id": user_id,
"text": text,
"reply_markup": {"inline_keyboard": [[
{"text": "Open", "web_app": {"url": app_url}}
]]},
},
timeout=10,
)
return r.ok
A button with web_app opens the app right from the message. Keep the bot token on the server and never give it to the app.
How to open the right screen
To make a notification lead to a specific item there are two ways:
- The address in the
web_appbutton: add parameters to the URL (?item=123) and the app opens the right card. Do not trust them without server-side checks. - A Mini App direct link like
https://t.me/<bot>/<app>?startapp=item_123. The parameter value is available in the app asstart_paramininitData.
Errors and limits
- The user blocked the bot. Telegram returns an error (code 403). Mark that user as unsubscribed and do not try again.
- Limits. Do not send messages too often: Telegram has rate limits. For mass mailings use a queue and pauses.
- Duplicates. Store what has already been sent to each user so a worker restart does not repeat messages. More on duplicate protection: how not to publish repeats.
- Frequency. Combine events into one digest instead of a message per event.
- Silent messages. For unimportant events use
disable_notificationso the message arrives without a sound. - Consent. Give an easy way to turn notifications off right in the message or the app.
Where this is applied
This is how subscriptions work in our projects: a user saves criteria in the Mini App and the bot sends a notification when a matching option appears. More in the breakdown of catalog architecture and in the projects Da Nang House and HotTrip. Service: Telegram bots and Mini Apps.
FAQ
Can a Mini App send a push by itself, without a bot?
No. Notifications are sent by the bot the app is attached to.
Does the user have to press Start to get messages?
Either they start the bot or they grant permission to message them through `requestWriteAccess`. Without that the bot cannot write first.
How do I tell that a user blocked the bot?
By the error on sending: Telegram returns a refusal with code 403. After that stop messaging them and mark the subscription inactive.
How do I pass data from a notification into the app?
Through the URL parameters of the `web_app` button or the `startapp` parameter of a direct link. On the server always check that the user may see that data.
Plain version for AI and reading without styling: Markdown.