Skip to main content


The Telegram Bot Framework.
Very Popular
Go to Latest
class Bot
extends Composer<C>
import { Bot } from "";

This is the single most important class of grammY. It represents your bot.

First, you must create a bot by talking to @BotFather, check out Once it is ready, you obtain a secret token for your bot. grammY will use that token to identify as your bot when talking to the Telegram servers. Got the token? You are now ready to write some code and run your bot!

You should do three things to run your bot:

// 1. Create a bot instance
const bot = new Bot('<secret-token>')
// 2. Listen for updates
bot.on('message:text', ctx => ctx.reply('You wrote: ' + ctx.message.text))
// 3. Launch it!


Bot(token: string, config?: BotConfig<C>)

Creates a new Bot with the given token.

Remember that you can listen for messages by calling

bot.on('message', ctx => { ... })

or similar methods.

The simplest way to start your bot is via simple long polling:


Type Parameters

C extends Context = Context
A extends Api = Api


clientConfig: ApiClientOptions | undefined
ContextConstructor: new (...args: ConstructorParameters<Context>) => C
lastTriedUpdateId: number
me: UserFromGetMe | undefined
mePromise: Promise<UserFromGetMe> | undefined
observedUpdateTypes: Set<string>

Used to log a warning if some update types are not in allowed_updates

pollingAbortController: AbortController | undefined
pollingRunning: boolean
api: A

Gives you full access to the Telegram Bot API.

// This is how to call the Bot API methods:
bot.api.sendMessage(chat_id, 'Hello, grammY!')

Use this only outside of your middleware. If you have access to ctx, then using ctx.api instead of bot.api is preferred.

botInfo: UserFromGetMe

Information about the bot itself as retrieved from api.getMe(). Only available after the bot has been initialized via await bot.init(), or after the value has been set manually.

Starting the bot will always perform the initialization automatically, unless a manual value is already set.

Note that the recommended way to set a custom bot information object is to pass it to the configuration object of the new Bot() instantiation, rather than assigning this property.

errorHandler: ErrorHandler<C>

Holds the bot's error handler that is invoked whenever middleware throws (rejects). If you set your own error handler via bot.catch, all that happens is that this variable is assigned.


fetchUpdates(unnamed 0: PollingOptions)

Internal. Do not call. Reliably fetches an update batch via getUpdates. Handles all known errors. Returns undefined if the bot is stopped and the call gets cancelled.

handlePollingError(error: unknown)

Internal. Do not call. Handles an error that occurred during long polling.

handleUpdates(updates: Update[])

Internal. Do not call. Handles an update batch sequentially by supplying it one-by-one to the middleware. Handles middleware errors and stores the last update identifier that was being tried to handle.

loop(options?: PollingOptions)

Internal. Do not call. Enters a loop that will perform long polling until the bot is stopped.

catch(errorHandler: ErrorHandler<C>)

Sets the bots error handler that is used during long polling.

You should call this method to set an error handler if you are using long polling, no matter whether you use bot.start or the @grammyjs/runner package to run your bot.

Calling bot.catch when using other means of running your bot (or webhooks) has no effect.

handleUpdate(update: Update, webhookReplyEnvelope?: WebhookReplyEnvelope)

This is an internal method that you probably will not ever need to call. It is used whenever a new update arrives from the Telegram servers that your bot will handle.

If you're writing a library on top of grammY, check out the documentation of the runner plugin for an example that uses this method.

init(signal?: AbortSignal)

Initializes the bot, i.e. fetches information about the bot itself. This method is called automatically, you usually don't have to call it manually.

Checks if the bot has been initialized. A bot is initialized if the bot information is set. The bot information can either be set automatically by calling bot.init, or manually through the bot constructor. Note that usually, initialization is done automatically and you do not have to care about this method.

on<Q extends FilterQuery>(filter: Q | Q[], ...middleware: Array<Middleware<Filter<C, Q>>>): Composer<Filter<C, Q>>

Starts your bot using long polling.

This method returns a Promise that will never resolve except if your bot is stopped. You don't need to await the call to bot.start, but remember to catch potential errors by calling bot.catch. Otherwise your bot will crash (and stop) if something goes wrong in your code.

This method effectively enters a loop that will repeatedly call getUpdates and run your middleware for every received update, allowing your bot to respond to messages.

If your bot is already running, this method does nothing.

Note that this starts your bot using a very simple long polling implementation. bot.start should only be used for small bots. While the rest of grammY was built to perform well even under extreme loads, simple long polling is not capable of scaling up in a similar fashion. You should switch over to using @grammyjs/runner if you are running a bot with high load.

What exactly high load means differs from bot to bot, but as a rule of thumb, simple long polling should not be processing more than ~5K messages every hour. Also, if your bot has long-running operations such as large file transfers that block the middleware from completing, this will impact the responsiveness negatively, so it makes sense to use the @grammyjs/runner package even if you receive much fewer messages. If you worry about how much load your bot can handle, check out the grammY documentation about scaling up.

Stops the bot from long polling.

All middleware that is currently being executed may complete, but no further getUpdates calls will be performed. The current getUpdates request will be cancelled.

In addition, this method will confirm the last received update to the Telegram servers by calling getUpdates one last time with the latest offset value. If any updates are received in this call, they are discarded and will be fetched again when the bot starts up the next time. Confer the official documentation on confirming updates if you want to know more:

Note that this method will not wait for the middleware stack to finish. If you need to run code after all middleware is done, consider waiting for the promise returned by bot.start() to resolve.