Telegram Bot Commands: How to Set, Scope, and Fix Them

Telegram Bot Commands: How to Set, Scope, and Fix Them

Almost every problem people have with Telegram bot commands comes from one misunderstanding, and it is worth naming in the first paragraph. Registering a command and handling a command are two completely separate things. The list you publish is a menu. It is a hint to the interface about what to offer. It does not make anything happen, it does not reserve the word, and a bot that has never registered a single command will still receive every command anybody types at it.

Once that is clear, the rest of the topic stops being mysterious. A command that does not appear in the menu is a registration problem. A command that appears but does nothing is a handling problem. A command that works in private chats and dies in groups is almost always neither, and instead a privacy setting that is on by default and quietly filters what your bot is allowed to see.

This article covers the format rules, the three commands the platform expects every bot to support, the seven separate scopes a command list can be published to, the privacy rule that decides what reaches your bot inside a group, parameters and deep links, and the specific reasons a command fails in each of those layers.

What a Command Actually Is

Strip away the interface and a command is a very ordinary thing.

It is just a message

A command is a text message that begins with a forward slash. There is no special transport, no separate event type and no privileged channel. Your bot receives it exactly the way it receives somebody typing hello, and everything that happens next is code you wrote reacting to a string.

The interface decorates it

What makes commands feel special is client behaviour layered on top. The documentation describes it directly: when users begin a message with a slash, a list of commands supported by all the bots present in the current chat is shown. That autocomplete is a convenience offered by the application, not a contract enforced by the servers.

Why this framing saves hours

Because it tells you where to look when something breaks. If the word is not offered as you type, the problem lives in the published list. If the word is offered, sent, and nothing comes back, the published list is fine and your handler never ran or never matched. Those are different bugs in different files, and confusing them is the single biggest time sink in bot development.

The Three Commands Every Bot Is Expected to Support

This is not a style guide suggestion. The documentation states it as a requirement on developers.

Start, help and settings

Three commands are named. The first begins the interaction with the user, like sending an introductory message. The second returns a help message, a short text about what the bot can do. The third shows the bot's settings and options for editing them, where such things apply. Between them they cover the entire first minute of anybody's relationship with your bot.

Where users encounter them

The first of the three is not typed by most people. On first contact the interface shows a Start button, and pressing it sends that command on the user's behalf. The other two appear as links in the bot's profile, which means they are discoverable without the user knowing they exist. That is why writing a real help text matters more than it seems: it has a permanent, findable entry point.

Nothing enforces it at the protocol level, so a bot that ignores all three still runs. What you lose is the part of the experience the platform builds for you. A missing help command turns a profile link into a dead end, and a missing start handler means the very first message a user ever sends you produces silence.

The Rules a Command Has to Obey

The format constraints are short, published, and stricter than most people assume.

Length and characters

A command starts with a forward slash and runs to at most thirty-two characters, using Latin letters, numbers and underscores. That is the whole permitted set. No spaces, no dashes, no dots, no accented characters. Anything outside it is not a command that fails to match; it is a message that was never a command in the first place.

Case, and why lowercase is the safe choice

The guidance is to use simple lowercase text. Mixed case invites a class of bug that is painful to diagnose, because the value that reaches your code is whatever the user typed. If your matching is case-sensitive and your users are typing on phone keyboards that capitalise the first letter, you will get intermittent failures that reproduce on nobody's machine but theirs.

Every registered command carries a description, and that text is what appears next to it in the menu. It is the only documentation most users will ever read about your bot. Treating it as a placeholder is a wasted opportunity, since a menu of eight commands with clear one-line descriptions is a better help page than the help command usually is.

Registering Is Not Handling

This deserves its own section because it is the root of most of the confusion in this whole topic.

What registration buys you

Publishing a command list tells the interface what to suggest. That is the entire effect. It populates the autocomplete, it fills the menu, and it makes your bot look finished. It does not route anything, it does not validate anything, and it does not stop other text from arriving.

Unregistered commands still arrive

If somebody types a slash followed by a word you never published, your bot receives that message in full. Plenty of bots run undocumented commands deliberately this way, for administrative functions that are not meant to be advertised. That is a legitimate pattern, and it is also why an unpublished command is not a private one: anybody who guesses it can send it.

The reverse is equally true and much more common. A published command with no matching handler produces a menu entry that sends a message into silence. Users read that as a broken bot, which it functionally is. Publishing a list you have not implemented is worse than publishing nothing, because it converts an absence into a visible failure.

The Menu Button and What It Shows

The button beside the message field is the main way most users meet your commands.

Its default behaviour

The menu button appears in every chat with a bot, and by default it shows a menu holding some or all of the bot's commands with their descriptions, so a user can pick one instead of typing it. For a bot with a small, well-described set, that button is the interface.

It is not the only surface

The same list drives the autocomplete that appears when a user types a slash, and that list combines every bot in the chat rather than showing yours alone. In a busy group your commands are competing for attention in a shared list, which is a good reason to prefix them with something recognisable rather than claiming generic words.

Command lists are cached on the client side, so a list you just published may not appear on a device that already has an older copy. If you have changed a list and cannot see the change, the honest first step is to check on a different account or a freshly opened chat before assuming the update failed. Our walkthrough on how to create a Telegram bot covers the registration path itself.

Seven Scopes, and What Each One Covers

A command list is not global. It is published against a scope, and there are seven of them with exact meanings.

The broad three

The default scope makes commands valid in all dialogs, which is the one most bots use and often the only one they need. A second scope narrows to all private chats with users. A third narrows to all groups and supergroups. Those three cover almost every design, and the distinction between the second and third is the one that matters most, because a command that makes sense one-to-one often makes no sense shouted into a group of four hundred people.

The administrator scopes

One scope makes commands valid only for chat administrators across all groups and supergroups. Another does the same for the administrators of one specific group. This is how a bot shows moderation commands to the people who can use them and hides them from everybody else, which is both cleaner and safer than publishing them to all and rejecting the calls afterwards.

Beyond that, commands can be scoped to a specific dialog, or to a specific user inside a specific group. That last one is unusual enough to be worth stating plainly: two members of the same group can see two different command menus for the same bot. It is the mechanism behind bots that reveal extra commands to a subscriber or a verified member.

Choosing a Scope Without Making a Mess

Seven options is enough to build something nobody can maintain, so a couple of rules help.

Start with one list

Publish everything to the default scope until you have a concrete reason not to. A single list is easy to reason about, easy to test, and produces identical behaviour everywhere. Most bots that end up with scope problems added scopes before they had a problem that scopes solve.

Split when the audiences genuinely differ

The honest test is whether a command would confuse or mislead the people who can see it but cannot use it. Moderation commands in a group qualify. A private-chat command that has no meaning in a group qualifies. A command that simply happens to be used more often by one group does not, and splitting for that reason gives you two lists to keep in step for no benefit.

A scope decides what is displayed. It does not decide what is accepted. Somebody who is not an administrator can still type an administrator command, and if your handler does not check permissions it will run. Scoping is presentation; the permission check in your code is the security, and our article on Telegram admin rights covers what those permissions actually are.

It is also worth knowing what the scope system does not give you. There is no inheritance between scopes, so a narrow list does not extend a broad one; whichever list applies replaces the others entirely rather than adding to them. A bot that publishes ten commands by default and one command to administrators has just given administrators a menu of exactly one command, which is almost never what the author intended. If a narrow audience needs an extra command, the narrow list has to carry the whole set.

Groups, and the Privacy Rule That Breaks Most Bots

If your commands work in a private chat and fail in a group, this section is almost certainly the answer.

Privacy mode is on by default

Every bot has privacy mode enabled by default, with one exception: bots that hold administrator rights in the group. That default is a deliberate protection for group members, and it means the normal state of your bot in a group is partially blind.

Exactly what a bot receives

The documentation lists it precisely. With privacy mode on, a bot receives commands explicitly addressed to it, general commands if the bot sent the last message in the chat, messages sent through the bot inline, replies to the bot's own messages, and all service messages. Everything else in the group is invisible to it. Ordinary conversation simply never arrives.

A bot that needs to read every message, for moderation or logging or keyword triggers, cannot do that with privacy mode on. The documented route is administrator rights, which turn the filter off. That is a real trade: you are asking a group owner for elevated permissions in exchange for functionality, and the honest way to ask is to say which of the five categories above is not enough for what you are building.

When several bots share a group

Command collisions in groups are common and the platform has a documented answer.

A command can be written with the bot's username attached, in the form of the command followed by an at sign and the bot name. That targets one bot explicitly and prevents every other bot in the room from reacting. In a group with three bots that all implement a stats command, this is the only thing that makes the room usable.

Why your bot should handle both forms

Users will type the bare form, and the interface will often insert the addressed form for them. Your matching has to accept both, or you will have a command that works when picked from the menu and fails when typed by hand. That single omission is behind a large share of reports that a command works sometimes.

Generic words are the problem. Anything that a moderation bot, a statistics bot and a welcome bot would all plausibly claim will end up claimed by all three. Names tied to what your bot actually does age better and read better in a shared autocomplete list, which is where a user first sees you next to everybody else. Our guides to Rose bot and Combot show how two widely used bots handle their own naming.

There is a second reason the addressed form matters, and it only shows up once a bot is popular. Groups copy each other: somebody sees a bot working in one room, adds it to theirs, and the command set arrives alongside whatever was already there. A bot whose commands are named after its own function survives that; one that claimed a generic word starts fighting with a bot that was there first, and the group owner resolves the fight by removing whichever one they added last. Our guide on how to automate a Telegram channel covers the same collision problem from the channel side, where the stakes are higher because there is no conversation to absorb the confusion.

Commands That Carry a Value

Most useful commands need an argument, and the platform's position on this is simple to the point of being blunt.

There is no parameter system

A command with parameters is a message with a space in it. The platform does not parse arguments, does not validate types, and does not tell you what the user meant. You receive the whole line and split it yourself. Every library that offers typed command arguments built that on top; nothing underneath enforces it.

What that means for your handlers

It means the failure modes are yours to design. A missing argument, three arguments where you expected one, quoted text, an emoji where a number should be, a user who typed the command and then thought better of it: all of these arrive as ordinary strings. The bots that feel solid are the ones that answer a malformed command with a sentence explaining the correct form, rather than silence or a stack trace.

Commands with several arguments are hard to type on a phone and impossible to remember. A short command that asks a question, then reads the answer as a normal message, is usually a better interface than one long line, and it also sidesteps the parsing problem entirely. That conversational shape is the same one behind our auto reply bot guide.

Deep Links, or Commands That Arrive From Outside

There is one command that can carry data from outside Telegram, and it is the most useful mechanism in this entire article.

How the link works

A link to your bot can carry a start parameter, in the form of the bot address followed by a query that sets a value. When somebody opens that link, the start command fires with your value attached. The user sees a normal Start button; your bot receives a message it can trace back to exactly where that link was placed.

The published limits

The parameter permits upper and lower case letters, digits, underscores and hyphens, and is limited to sixty-four characters. That is small on purpose. It is a reference, not a payload: you put a short code in the link and look up the rest on your side. Anybody trying to pack a customer record into it is fighting the design.

What people actually use it for

Attribution, mostly. A different code per channel, per advertisement or per partner turns your bot into something you can measure, because the very first message a user sends already carries its source. There is a matching parameter for adding a bot to a group rather than opening a private chat, which is the variant to use when the destination is a group. The same idea underpins our piece on Telegram invite links, where the link itself is the measurement.

The same is true of a bot that broadcasts rather than answers. A command is a pull, and a broadcast is a push, and the two have different failure modes, different limits and different consequences when they go wrong. Our piece on the Telegram broadcast bot covers the push direction, including why a bot cannot start a conversation with somebody who has never opened one with it.

Why a Command Does Not Appear

Take the failures in order, because each layer has its own symptom.

It was never published

The most common cause is the simplest: the list was never set, or was set once during development and never updated after the command was renamed. A bot with no published list shows no menu at all, which reads to users as a bot that does not have commands rather than one that never announced them.

It was published to a scope you are not in

If a list went to the administrator scope and you are testing as a member, you will not see it, and nothing is broken. This is the failure that wastes the most time because everything looks correct from the code's point of view. Checking which scope you published to, and which one you are standing in, resolves it in seconds.

Menus are cached. A change can be live on the servers and absent on your screen. Test on a second account or a chat you have not opened before, rather than assuming the write failed and publishing it three more times.

Why a Command Appears but Nothing Happens

The second family of failures, and a completely different set of causes.

Privacy mode swallowed it in a group

In a group, if the command was not addressed to your bot and your bot did not send the last message, your bot never received it. Nothing in your logs will show a missed message, because there was no message to miss. Testing the same command in a private chat separates this from every other cause in one step.

Your matcher is stricter than reality

The three near-misses are the addressed form with the bot name attached, capitalisation from a phone keyboard, and trailing arguments on a command you expected bare. All three arrive as valid commands and all three fail a naive equality check. This is the most common bug in first bots and it has the most boring fix, which is to normalise before matching.

The bot is not receiving anything at all

Worth ruling out early rather than late. If nothing arrives from any chat, the problem is not commands but delivery, which usually means the credential or the receiving endpoint. Our article on the Telegram bot token covers the credential side, including what to do when one has been replaced.

Command Lists in More Than One Language

Command lists can be published per language, which is more useful than it first appears.

How it works

A list is published against a language code as well as a scope, and users see the list matching their own interface language. The commands themselves generally stay the same; what changes is the description beside each one. That is the right split, because a translated command word is a different command, while a translated description is the same command explained.

Where it goes wrong

An invalid language code is rejected with its own documented error, so a typo in the code fails loudly rather than silently falling back. The subtler problem is drift: adding a command to one language list and forgetting the others leaves some users with a shorter menu than everybody else, and nothing warns you.

Unless you already know your audience is split across languages, publish one list and spend the effort on clearer descriptions instead. Localisation multiplies the number of lists you must keep in step, and lists that drift are worse than lists that are merely in the wrong language.

Designing a Set People Can Actually Use

The technical rules leave a lot of room, and most of the difference between a pleasant bot and an irritating one lives here.

Fewer commands, better named

A menu is read, not searched. Past roughly a dozen entries people stop reading and start guessing, and guessing means typing something that does not exist. If a set has grown past that, the answer is usually that several commands should be one command that asks a question.

Write descriptions for a stranger

The description is read by somebody who has never used your bot and does not know your vocabulary. Internal words fail this test every time. A description that says what the command does in plain language beats a clever one, and it is the cheapest improvement available in this whole topic.

Command names end up in other people's documentation, in pinned messages, in support replies and in deep links. Renaming one breaks all of that with no redirect and no warning. If a rename is unavoidable, keep the old name working silently for a while, since the cost is a few lines and the alternative is a stream of users typing something that no longer exists.

One more habit worth building early. Keep the published list and the implemented list in the same place in your code, close enough that changing one without the other looks wrong on the screen. Almost every menu entry that sends a message into silence started as a rename in one file that never reached the other, and no amount of testing catches it reliably because the command still exists and still appears. Proximity in the source is a better defence than discipline.

There is a quieter cost to a long menu that only appears at scale. Every entry you publish is a promise you have to keep working, in every scope you published it to, in every language, forever. Commands are the most public part of a bot and the hardest part to retire, because unlike a button you can remove from a keyboard, a command that somebody has learned stays in their fingers. Teams that treat the list as a product surface rather than a configuration file end up with shorter lists and fewer support messages, and the two are the same fact seen from opposite ends.

When You Run More Than One Bot

Everything above is manageable for one bot and becomes an operations problem at three.

Consistency stops being automatic

A set of bots that share a house style needs its command sets kept in step deliberately, because nothing does it for you. Users who meet two of your bots will expect the same word to mean the same thing in both, and the moment it does not, both bots feel unreliable. Keeping that consistent is what our Bot Manager product exists to handle.

Each bot carries its own credential and its own list

There is no shared command list and no inheritance between bots. Every one is registered separately, scoped separately and published separately. That is fine at two and tedious at ten, which is the point at which people start writing scripts and the point at which a missing command in one bot goes unnoticed for weeks.

Commands are one automation surface among several

A command is a user pulling something from you. Most business automation is the other direction, where you reach the user first, and that runs on entirely different mechanisms. If that is the side you need, our Mass DMs tooling handles outbound at volume, Account Manager covers running the accounts behind it, and our guide to Telegram DM automation sets out where the line between the two sits.

Worth separating two things that get conflated here. A command list is per bot, and a bot is one identity with one credential. If you are running a set of accounts rather than a set of bots, none of this applies to them at all, because ordinary accounts do not have command lists and cannot publish one. That distinction catches people who assume the two are variations of the same thing, and it is the reason automation built on accounts and automation built on bots almost never share code. Our Member Adder and Channel Clone products sit on the account side of that line, which is why they behave nothing like a bot even when the task looks similar.

What All of This Adds Up To

A command is a message beginning with a slash. Everything that feels like machinery around it is either interface polish or code you wrote. Publishing a list changes what the application offers; it never changes what your bot receives, and it never makes anything happen.

The constraints are small enough to remember. Up to thirty-two characters, Latin letters, numbers and underscores, lowercase by convention and by good sense. Three commands the documentation expects every bot to support. Seven scopes ranging from every dialog down to one user in one group. A start parameter capped at sixty-four characters that turns any link into a measurable entry point.

When something breaks, the layer tells you the cause. Missing from the menu means the list, the scope, or a cached client. Present but silent means privacy mode in a group, or a matcher that rejected the addressed form, the capitalisation or the trailing argument. Silent everywhere means the credential or the endpoint, not commands at all. Working through those in order is faster than any amount of rereading your handler.

Frequently Asked Questions

What are the rules for a Telegram bot command?

A command begins with a forward slash and can be up to thirty-two characters long, using Latin letters, numbers and underscores only. The guidance is to keep to simple lowercase text. Anything containing a space, a dash, a dot or an accented character is not a valid command and will be treated as ordinary text.

Which commands does every Telegram bot need?

The documentation names three. One begins the interaction, like an introductory message. One returns a short help text explaining what the bot can do. One shows the bot's settings and how to change them, where that applies. The first is sent automatically when a user presses Start, and the other two appear as links in the bot's profile.

Why are my bot commands not showing in the menu?

Three causes cover nearly all cases. The list was never published, or was published before the command was renamed. The list was published to a scope you are not currently in, such as an administrator scope while you are testing as an ordinary member. Or your client is displaying a cached copy, which you can rule out by checking from a different account.

Why does my bot ignore commands in a group?

Because privacy mode is enabled by default. With it on, a bot receives only commands addressed to it directly, general commands when it sent the last message, messages sent through it inline, replies to its own messages, and service messages. Ordinary group chatter never reaches it. Granting the bot administrator rights turns that filter off.

How do I send a command to one specific bot in a group?

Write the command with the bot's username attached, using an at sign between them. That addresses one bot explicitly and stops every other bot in the group from responding. Your own bot should accept both this form and the bare form, since users type one and the interface often inserts the other.

Can Telegram bot commands take parameters?

Yes, but only in the sense that a message can contain a space. There is no parameter system, no type checking and no validation. You receive the entire line and split it yourself, which also means every malformed input is yours to handle. For anything with more than one value, asking a follow-up question is usually easier for users than a long line.

What is the start parameter and how long can it be?

It is a value carried in a link to your bot, which arrives attached to the start command when somebody opens that link. It permits upper and lower case letters, digits, underscores and hyphens, and is limited to sixty-four characters. It is designed as a short reference code that you look up on your side, not as a place to store data.

How many different command lists can a bot have?

Lists are published per scope and per language, and there are seven scopes: all dialogs, all private chats, all groups and supergroups, administrators across all groups, one specific dialog, the administrators of one specific group, and a single specific user inside a group. Multiply that by the languages you support and the number of lists you maintain grows quickly.

Do hidden commands still work if they are not published?

Yes. Publishing a list only affects what the interface suggests; it has no effect on what your bot receives. A command you never registered still arrives in full when somebody types it, which is how undocumented administrative commands work. It also means an unpublished command is not a secret one, since anybody who guesses the word can send it.

Why does my command appear in the menu but do nothing?

Because registering and handling are separate. A published command with no matching handler produces a menu entry that sends a message into silence. The other common cause is a matcher that is too strict, rejecting the form with the bot name attached, an unexpected capital letter, or trailing text after the command word.

A Command Is a Pull, Not a Push

Commands wait for someone to type them. Reaching people first is a different mechanism entirely, and it is the one our tooling is built on. Open a demo and see it.

Try Free Demo