Deploy your bot using webhooks for production environments
Webhooks are the preferred way to receive updates in production. Instead of polling Telegram’s servers, Telegram sends updates directly to your server via HTTP POST requests.
import { Bot, webhookCallback } from "grammy";import express from "express";const bot = new Bot("YOUR_BOT_TOKEN");bot.on("message:text", (ctx) => ctx.reply("Got your message!"));// Create Express appconst app = express();// Use the webhook callbackapp.use(express.json());app.use(`/webhook/${bot.token}`, webhookCallback(bot, "express"));// Set webhookawait bot.api.setWebhook(`https://your-domain.com/webhook/${bot.token}`);app.listen(3000);
Never expose your bot token in the URL! Use it as a secret path component to prevent unauthorized webhook calls.
import express from "express";import { webhookCallback } from "grammy";const app = express();app.use(express.json());app.use(webhookCallback(bot, "express"));await bot.api.setWebhook("https://example.com/webhook");app.listen(8080);
import fastify from "fastify";import { webhookCallback } from "grammy";const server = fastify();server.post("/webhook", webhookCallback(bot, "fastify"));await bot.api.setWebhook("https://example.com/webhook");await server.listen({ port: 8080 });
import Koa from "koa";import { koaBody } from "koa-body";import { webhookCallback } from "grammy";const app = new Koa();app.use(koaBody());app.use(webhookCallback(bot, "koa"));await bot.api.setWebhook("https://example.com/webhook");app.listen(8080);
await bot.api.setWebhook("https://example.com/webhook", { // Only receive specific update types allowed_updates: ["message", "callback_query"], // Drop pending updates from previous bot instance drop_pending_updates: true, // Secret token to verify requests secret_token: "your-secret-token", // Maximum allowed number of connections (1-100) max_connections: 40, // Use specific IP address ip_address: "1.2.3.4",});
# Install ngroknpm install -g ngrok# Start your botnode bot.js# In another terminal, create a tunnelngrok http 3000# Use the https URL provided by ngrok
// Get current webhook infoconst info = await bot.api.getWebhookInfo();console.log(info);// Delete webhook (switch back to long polling)await bot.api.deleteWebhook({ drop_pending_updates: true });// Check if webhook is setconst webhookInfo = await bot.api.getWebhookInfo();if (webhookInfo.url) { console.log("Webhook is set to:", webhookInfo.url);} else { console.log("No webhook set");}