Telegram Bot Commands Not Showing? How setMyCommands Scopes Decide the Menu (2026)

By · Published 2026-11-01 · Last verified 2026-11-01

Why aren't my Telegram bot commands showing in the menu?

Most of the time the commands were never registered for the place you're looking, or a more specific list is hiding them. Telegram doesn't read your code to find commands. It shows the list you set with the Bot API method setMyCommands (or through BotFather), and each list belongs to a scope and, optionally, a language. When a user opens the menu, Telegram picks the most specific list that matches that chat, that user and that language, and shows only that one. So a list set for one group, or for a single language, can quietly replace the default everywhere it applies. This guide shows how the scopes work, the order Telegram checks them in, and a short routine to find which list is winning. It's the same check we run on the Auto X bot, which schedules X posts from Telegram, whenever its menu looks wrong.

How Telegram decides which command list to show

The Bot API documents seven scope types for setMyCommands. If you don't pass a scope, the list goes to BotCommandScopeDefault. If you don't pass a language_code, the list applies to every user in that scope who doesn't have a list for their own language. Language codes are two-letter ISO 639-1 codes, such as en or it.

Grid of setMyCommands scopes: Default, AllPrivateChats, AllGroupChats, AllChatAdministrators, Chat and ChatAdministrators for one chat, and ChatMember for one user in one group
The command scopes.

For a private chat, Telegram returns the first list it finds in this order: Chat with the user's language, Chat, AllPrivateChats with the language, AllPrivateChats, Default with the language, then Default. In groups the chain is longer. It starts with ChatMember, then ChatAdministrators (for admins), then Chat, then AllChatAdministrators (for admins), then AllGroupChats, and finally Default, each one checked with the user's language first and then without it.

Lookup order in a private chat: Chat, then AllPrivateChats, then Default, each checked with the user's language first, and only one list shown
First match wins.

The rule to remember: the first match wins, and lists don't merge. If you set three commands for AllGroupChats and ten for Default, people in groups see three, not thirteen.

Six reasons commands don't show, and the fix for each

  1. Nothing was registered. getMyCommands returns an empty list when no commands are set for that scope and language. Handling /start in code doesn't put it in the menu; you have to call setMyCommands or set the list in BotFather.
  2. A narrower list is hiding the default. An old Chat or AllGroupChats list from a test still wins in that place. Remove it with deleteMyCommands using the same scope and language; Telegram says that after deletion, higher-level commands are shown to affected users.
  3. A language list is winning. If you once set a list with language_code="en", English-language users get that list, even if you later updated the list with no language. Update or delete the language-specific one too.
  4. The command name is invalid. The API accepts 1 to 32 characters, using only lowercase English letters, digits and underscores. /Post, /post-now and a 33-character name are all rejected. Check the API response rather than assuming the call worked.
  5. The menu button was changed. By default the menu button opens the command list. If the bot set a Web App button with setChatMenuButton, that button replaces it. Set MenuButtonCommands again for that chat, or for the default.
  6. The client is showing an older list. After a change, close and reopen the chat before deciding the call failed. Compare with getMyCommands, which tells you what the server holds.
Grid of six reasons commands don't show: never set, a narrower list, a language list, an invalid name, a changed menu button and an old client view
Why commands don't show.

Commands that don't show are one symptom; a bot that doesn't react at all is another. If the bot ignores commands in a group, read why a Telegram bot doesn't receive group messages (privacy mode) first. If it ignores everything, check delivery with getWebhookInfo and the common webhook errors.

A five-minute check to find the winning list

Call getMyCommands for each scope and language you might have used, and write down what comes back. It takes the same scope and language_code parameters as setMyCommands, so you can walk the chain in the same order Telegram does:

  1. Default with no language, then Default with each language your users have.
  2. AllPrivateChats and AllGroupChats, with and without language.
  3. AllChatAdministrators if admins see a different menu.
  4. Chat, ChatAdministrators and ChatMember for any group where the menu looks wrong.

The first non-empty list in the order above, for that chat and user, is what they see. If it's an old test list, delete it. If it's the right list with the wrong commands, update it. Then keep one source of truth: a small script or config file that sets every list on deploy, so a manual BotFather edit doesn't drift from the code.

A simple layout most bots can use

Telegram's features page suggests a few global commands every bot should support, such as /start, /help and /settings. Beyond those, most small bots need only two or three lists:

Two columns: a simple layout of Default, AllPrivateChats and AllChatAdministrators lists, and reminders that lists don't merge and scopes don't protect commands
A layout most bots can use.

Add language-specific lists only if you really translate the descriptions, and keep each set complete, because a language list replaces the general one rather than adding to it. Descriptions can be 1 to 256 characters; a short verb phrase reads best in the menu.

Scopes hide commands, they don't protect them

A command scope controls what appears in the menu, not what a user can type. Telegram's documentation points out that updates don't tell your bot which scope a command came from, so the backend has to check permissions itself. If /broadcast is meant for admins, verify that the sender is an admin when the command arrives, even though only admins see it in the menu. For a scheduler like Auto X, that matters for anything that publishes or deletes posts: see our notes on approval gates and API token hygiene for Telegram-to-X bots. If you're setting commands for many groups in a loop, space the calls out; Telegram's 429 limits and retry_after apply to these methods too.

Vertical Pinterest graphic with five points on Telegram bot commands not showing
Pinterest pin: Telegram bot commands not showing.

FAQ

Why do my bot's commands show in private chat but not in groups?

Usually because a list set for AllGroupChats, one group or a group's admins is winning there, or because the only list you set was for AllPrivateChats. Call getMyCommands with the group scopes to see which list Telegram returns, then update or delete it.

How many commands can a Telegram bot have in its menu?

setMyCommands accepts up to 100 commands per list. Each command name is 1 to 32 characters of lowercase English letters, digits and underscores, and each description is 1 to 256 characters.

Do I need BotFather to set commands?

No. BotFather's /setcommands and the setMyCommands API method both work. Using the API from your deploy script keeps the menu in sync with your code and lets you use scopes and languages.

Can I hide admin commands from regular members?

Yes, by setting them only for the AllChatAdministrators or ChatAdministrators scope. That only hides them from the menu; your bot still has to check that the sender is an admin when the command arrives.

Why didn't my command list change after I updated it?

Check for a language-specific list that still holds the old commands, and reopen the chat. getMyCommands with the same scope and language shows what Telegram has stored.

Sources