Skip to main content

Reply Keyboard: send, switch, one-time hide, and remove

Send ReplyKeyboardMarkup via reply_markup; plain buttons yield message.text; is_persistent vs one_time vs remove; selective, Privacy Mode, and private-only web_app.

In short

Reply Keyboard is the right-side custom keyboard under the input. Send it with sendMessage reply_markup = ReplyKeyboardMarkup. A normal button sends a user message whose text is the button label — not a callback_query. It is independent from the left Menu Button.


Overview

Use Reply Keyboard for persistent or one-shot shortcuts. For buttons that stay on a message bubble and call your backend with callback_data, use Inline Keyboard instead. Official reference: core.mp.net/bots.

Send via reply_markup

Pass a ReplyKeyboardMarkup object as reply_markup on sendMessage (also accepted on other message-sending methods that support the ReplyMarkup union). Discriminator fields must match exactly one markup type.

{
"chat_id": 12345,
"text": "Choose an action",
"reply_markup": {
"keyboard": [[{ "text": "Status" }, { "text": "Help" }]],
"resize_keyboard": true,
"is_persistent": true
}
}

Normal buttons → message.text (not callback_query)

  • When the user taps a plain text button, the client sends a normal message.

  • Your Update contains message.text equal to the button label.

  • Do not expect callback_query — that path is for Inline callback_data buttons only.

is_persistent / one_time_keyboard / remove

Field / markup

Behavior

is_persistent

Requests the keyboard stay available (client keeps offering the toggle).

one_time_keyboard

Collapses after one use, but the user can usually summon it again from the toggle.

ReplyKeyboardRemove (remove_keyboard)

Deletes the effective Reply Keyboard state for the chat (true remove).

Do not confuse with Menu Button

setChatMenuButton never creates, removes, or expands a Reply Keyboard. To hide the custom keyboard, send ReplyKeyboardRemove, not a menu API call.

selective in groups

In groups, set selective: true so the keyboard is shown only to users mentioned in the message / the sender of the replied-to message (Telegram-compatible selective semantics). Without it, the keyboard may apply more broadly in that chat.

Privacy Mode caveat

Privacy Mode

If the bot runs with Privacy Mode enabled in a group, it may only see commands, mentions, and replies to the bot. A Reply Keyboard press that sends plain text without being a command or a reply to the bot may not reach your backend. Prefer slash-command labels, require reply context, or disable Privacy Mode when the product needs every button tap.

web_app button: private chat only

A Reply Keyboard button with web_app is intended for private chats. Do not rely on it in groups. Ownership / URL rules for keyboard web_app follow the message button path on core.mp.net/bots (stricter than Menu Button web_app, which allows any HTTPS ≤2048).

Independence from Menu Button

  • Left Menu Button ↔ setChatMenuButton.

  • Right Reply Keyboard ↔ message reply_markup only.

  • Both can be present at once; neither API drives the other.

Related

Source of truth

Prefer core.mp.net/bots over PRD wording.

Did this answer your question?