Comprehensive Telegram Bot Builder
Boost productivity using this skill, should, used, user. Includes structured workflows, validation checks, and reusable patterns for development.
Comprehensive Telegram Bot Builder
A complete skill for building Telegram bots using the Bot API. Covers bot setup, command handling, inline keyboards, webhook configuration, conversation flows, and production deployment patterns for both Node.js and Python ecosystems.
When to Use This Skill
Choose this skill when:
- Creating a new Telegram bot from scratch with BotFather setup
- Implementing command handlers, inline keyboards, and callback queries
- Building conversational flows with state management
- Setting up webhooks for production deployment
- Integrating external APIs and databases with bot responses
Consider alternatives when:
- Building a Discord bot → use a Discord bot skill
- Working on a Slack integration → use a Slack API skill
- Need a general chat interface → use a chat UI skill
- Building a WhatsApp bot → use a WhatsApp API skill
Quick Start
# Node.js setup npm install telegraf dotenv # Python setup pip install python-telegram-bot python-dotenv
// Node.js Telegram bot with Telegraf import { Telegraf, Markup } from 'telegraf'; const bot = new Telegraf(process.env.BOT_TOKEN!); // Command handlers bot.command('start', (ctx) => { ctx.reply( `Welcome, ${ctx.from.first_name}! Choose an option:`, Markup.inlineKeyboard([ [Markup.button.callback('📊 Status', 'status')], [Markup.button.callback('⚙️ Settings', 'settings')], [Markup.button.callback('❓ Help', 'help')], ]) ); }); bot.action('status', async (ctx) => { await ctx.answerCbQuery(); await ctx.editMessageText('System is running smoothly! ✅'); }); bot.command('echo', (ctx) => { const text = ctx.message.text.replace('/echo ', ''); ctx.reply(text || 'Please provide text after /echo'); }); // Error handling bot.catch((err, ctx) => { console.error(`Error for ${ctx.updateType}:`, err); ctx.reply('An error occurred. Please try again.'); }); // Start bot bot.launch(); process.once('SIGINT', () => bot.stop('SIGINT')); process.once('SIGTERM', () => bot.stop('SIGTERM'));
Core Concepts
Bot API Capabilities
| Feature | Method | Use Case |
|---|---|---|
| Text messages | sendMessage | Responses, notifications |
| Inline keyboards | InlineKeyboardMarkup | Buttons within messages |
| Reply keyboards | ReplyKeyboardMarkup | Persistent button menu |
| Photos/documents | sendPhoto, sendDocument | Media responses |
| Callback queries | answerCallbackQuery | Handle button clicks |
| Webhook | setWebhook | Production event delivery |
| Inline mode | answerInlineQuery | Cross-chat bot mentions |
Conversation Flow with State Machine
import { Scenes, session } from 'telegraf'; // Define a wizard scene for multi-step conversation const orderWizard = new Scenes.WizardScene( 'order-wizard', // Step 1: Ask for product async (ctx) => { await ctx.reply('What product would you like to order?'); return ctx.wizard.next(); }, // Step 2: Ask for quantity async (ctx) => { if (!ctx.message || !('text' in ctx.message)) return; ctx.wizard.state.product = ctx.message.text; await ctx.reply('How many would you like?'); return ctx.wizard.next(); }, // Step 3: Confirm async (ctx) => { if (!ctx.message || !('text' in ctx.message)) return; const quantity = parseInt(ctx.message.text); if (isNaN(quantity) || quantity < 1) { await ctx.reply('Please enter a valid number.'); return; // stay on same step } ctx.wizard.state.quantity = quantity; await ctx.reply( `Order: ${ctx.wizard.state.quantity}x ${ctx.wizard.state.product}\nConfirm?`, Markup.inlineKeyboard([ Markup.button.callback('✅ Confirm', 'confirm_order'), Markup.button.callback('❌ Cancel', 'cancel_order'), ]) ); return ctx.wizard.next(); }, // Step 4: Process order async (ctx) => { if (ctx.callbackQuery && 'data' in ctx.callbackQuery) { if (ctx.callbackQuery.data === 'confirm_order') { await ctx.answerCbQuery('Order placed!'); await ctx.editMessageText('Order confirmed! 🎉'); } else { await ctx.answerCbQuery('Cancelled'); await ctx.editMessageText('Order cancelled.'); } } return ctx.scene.leave(); } ); const stage = new Scenes.Stage([orderWizard]); bot.use(session()); bot.use(stage.middleware()); bot.command('order', (ctx) => ctx.scene.enter('order-wizard'));
Webhook Setup for Production
// Production webhook configuration import express from 'express'; const app = express(); // Set webhook URL (run once during deployment) await bot.telegram.setWebhook(`${process.env.WEBHOOK_URL}/bot${process.env.BOT_TOKEN}`); // Express webhook handler app.use(bot.webhookCallback(`/bot${process.env.BOT_TOKEN}`)); app.listen(process.env.PORT || 3000, () => { console.log('Bot webhook server running'); });
Configuration
| Parameter | Type | Default | Description |
|---|---|---|---|
updateMode | string | 'polling' | Mode: polling (dev) or webhook (prod) |
framework | string | 'telegraf' | Framework: telegraf (Node.js) or python-telegram-bot |
sessionStorage | string | 'memory' | Session: memory, redis, or database |
rateLimitPerSecond | number | 30 | Telegram API rate limit per second |
webhookPath | string | '/bot{token}' | Webhook endpoint path |
parseMode | string | 'HTML' | Message parse mode: HTML or MarkdownV2 |
Best Practices
-
Use webhooks in production, polling in development — Polling is simpler for development but wastes resources in production. Webhooks deliver updates instantly and scale better. Use HTTPS with a valid certificate for webhook endpoints.
-
Implement rate limiting and error handling — Telegram limits bots to 30 messages per second. Queue outgoing messages and handle
429 Too Many Requestserrors with exponential backoff. Never let unhandled errors crash the bot process. -
Store conversation state externally for multi-instance deployment — In-memory sessions are lost on restart and don't work across multiple bot instances. Use Redis or a database for session storage in production.
-
Always answer callback queries — When a user taps an inline keyboard button, call
answerCbQuery()even if you don't need to show a notification. Without it, the button shows a loading spinner indefinitely. -
Validate and sanitize all user input — Bot messages can contain any text, including HTML injection attempts and extremely long strings. Validate input lengths, sanitize HTML, and never use user input directly in database queries or API calls.
Common Issues
Bot stops receiving updates after setting webhook — Setting a webhook disables polling. If you switch back to polling, delete the webhook first with deleteWebhook(). Having both active causes the bot to miss updates.
Inline keyboard buttons stop working — Callback data has a 64-byte limit. Long callback data strings are silently truncated, causing mismatches. Use short identifiers in callback data and store full context in session state.
Bot responds to old messages on restart — When polling restarts, the bot processes queued updates that arrived while it was offline. Set an offset to skip old updates, or check message timestamps and ignore messages older than a threshold.
Reviews
No reviews yet. Be the first to review this template!
Similar Templates
Full-Stack Code Reviewer
Comprehensive code review skill that checks for security vulnerabilities, performance issues, accessibility, and best practices across frontend and backend code.
Test Suite Generator
Generates comprehensive test suites with unit tests, integration tests, and edge cases. Supports Jest, Vitest, Pytest, and Go testing.
Pro Architecture Workspace
Battle-tested skill for architectural, decision, making, framework. Includes structured workflows, validation checks, and reusable patterns for development.