Ephemeral Messages

Bot API 10.2 — July 2026

An ephemeral message is sent into a group but shown to one person. Nobody else in the chat sees it, and it is not part of the chat’s history — there is no message id to fetch later, no forwarding, no search.

It is what a bot should use for anything addressed to one member: an error, a private prompt, a result nobody else asked for. Before this existed the choices were spamming the group or starting a private chat the user may not have opened.

Ephemeral messages are sent by bots.


Sending one

from pyrogram import Client, filters

app = Client("my_bot")


@app.on_message(filters.command("balance"))
async def balance(client, message):
    await client.send_ephemeral_message(
        chat_id=message.chat.id,
        receiver_id=message.from_user.id,
        text=f"Your balance is {get_balance(message.from_user.id)} Stars.",
    )


app.run()

chat_id is the group it appears in; receiver_id is the only person who will see it. Both are required — an ephemeral message with no receiver has nowhere to go.

Keyboards, replies and rich text

The message is otherwise a normal one. It takes a reply_markup, so a private prompt can carry buttons; reply_parameters, so it can quote the message that triggered it; and rich_text with rich_text_media for a full rich message:

from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton

await app.send_ephemeral_message(
    chat_id=group_id,
    receiver_id=user_id,
    text="Only you can see this. Continue?",
    reply_markup=InlineKeyboardMarkup([[
        InlineKeyboardButton("Yes", callback_data="go"),
        InlineKeyboardButton("No", callback_data="stop"),
    ]]),
)

query_id answers a guest bot query with an ephemeral message — see Guest Mode and Managed Bots.

Deleting one

await app.delete_ephemeral_message(
    chat_id=group_id,
    receiver_id=user_id,
    message_id=sent.id,
)

The receiver has to be named again, because the message only ever existed for them.

Gotchas

  • disable_web_page_preview is accepted and ignored. The RPC behind ephemeral messages has no link preview field; the parameter is kept so existing call sites do not break.

  • These messages are not in the chat history. Do not expect get_messages() to find one, and do not build a flow that needs to read it back — hold what you need in your own state.

  • Everything about them is per-receiver. To tell three people something privately, send three messages.