answerWebAppQuery
Returns: SentWebAppMessageOfficial docs ↗
Use this method to set the result of an interaction with a Web App and send a corresponding message on behalf of the user to the chat from which the query originated. On success, a SentWebAppMessage object is returned.
Parameters
web_app_query_idStringRequiredUnique identifier for the query to be answered
A JSON-serialized object describing the message to be sent
Returns
On success, the SentWebAppMessage object is returned.
GramIO Usage
typescript
import { Bot } from "gramio";
const bot = new Bot(process.env.BOT_TOKEN as string);
// Basic usage — answer a Web App query with an article result
bot.on("message", async (ctx) => {
// web_app_query_id comes from the Web App via initData or postMessage
const queryId = ctx.message.web_app_data?.web_app_query_id;
if (!queryId) return;
const result = await bot.api.answerWebAppQuery({
web_app_query_id: queryId,
result: {
type: "article",
id: "result-1",
title: "Selected Item",
input_message_content: {
message_text: "You selected: Item #1",
},
},
});
// result.inline_message_id can be used to edit the sent message later
console.log("Sent message ID:", result.inline_message_id);
});
// Answering with a photo result
bot.on("message", async (ctx) => {
const queryId = ctx.message.web_app_data?.web_app_query_id;
if (!queryId) return;
await bot.api.answerWebAppQuery({
web_app_query_id: queryId,
result: {
type: "photo",
id: "photo-result-1",
photo_url: "https://example.com/photo.jpg",
thumbnail_url: "https://example.com/photo_thumb.jpg",
caption: "Photo from Web App",
},
});
});Errors
| Code | Error | Cause |
|---|---|---|
| 400 | Bad Request: QUERY_ID_INVALID | web_app_query_id has expired or was already answered — call this method once and promptly after the Web App sends the query |
| 400 | Bad Request: query is too old | The Web App query was not answered within its validity window — answer immediately upon receiving the query ID |
| 400 | Bad Request: result id is not unique | Two results share the same id — ensure every result in results has a unique ID |
| 403 | Forbidden: bot is not a member | The bot that owns the token does not match the bot that served the Web App — ensure the correct bot token is used |
| 429 | Too Many Requests: retry after N | Rate limit hit — inspect the retry_after field and use the auto-retry plugin |
Tips & Gotchas
- This method is for Web App (Mini App) interactions only. The
web_app_query_idis generated by Telegram when a user interacts with a Web App attached to an inline keyboard or menu button. It is delivered viaweb_app_dataon the server or viapostMessagein the Mini App frontend. - Can only be answered once. Attempting to call
answerWebAppQuerya second time with the sameweb_app_query_idreturnsQUERY_ID_INVALID. Cache your result if you need to reference it later. - The returned
inline_message_idallows later edits. Storeresult.inline_message_idif you plan to update the sent message later usingeditMessageText,editMessageMedia, etc. - Not the same as
answerInlineQuery.answerInlineQueryresponds to a user typing@botnamein any chat.answerWebAppQueryresponds to an interaction triggered from a Web App within a bot. - Result type must match the intended content. Use
"article"for text content,"photo"for images, etc. Invalid or mismatched result types cause a 400 error. - No
parse_modeneeded alongsideformat. When using GramIO'sformattagged template to buildmessage_textwith entities, do not also passparse_mode— the entities are already embedded.
See Also
SentWebAppMessage— Return type containinginline_message_idInlineQueryResult— Union type for all result kinds (article, photo, video, etc.)- Mini App (TMA) overview — How Web Apps integrate with Telegram bots
- Formatting guide — Build
message_textwith entities using GramIO helpers - Keyboards overview — Attach inline keyboards to Web App results via
reply_markup