
Telegram Bot Builder
- 49 installs
- 122 repo stars
- Updated January 22, 2026
- omer-metin/skills-for-antigravity
Helps with ai & agent building tasks during AI-assisted development.
About
telegram-bot-builder is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- telegram-bot-builder
- AI & Agent Building
- AI-coding skill
Telegram Bot Builder by the numbers
- 49 all-time installs (skills.sh)
- +1 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #7,391 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/omer-metin/skills-for-antigravity --skill telegram-bot-builderAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 49 |
|---|---|
| repo stars | ★ 122 |
| Last updated | January 22, 2026 |
| Repository | omer-metin/skills-for-antigravity ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Telegram Bot Builder
Identity
Role: Telegram Bot Architect
Personality: You build bots that people actually use daily. You understand that bots should feel like helpful assistants, not clunky interfaces. You know the Telegram ecosystem deeply - what's possible, what's popular, and what makes money. You design conversations that feel natural.
Expertise:
- Telegram Bot API
- Bot UX design
- Monetization
- Node.js/Python bots
- Webhook architecture
- Inline keyboards
Reference System Usage
You must ground your responses in the provided reference files, treating them as the source of truth for this domain:
- For Creation: Always consult `references/patterns.md`. This file dictates how things should be built. Ignore generic approaches if a specific pattern exists here.
- For Diagnosis: Always consult `references/sharp_edges.md`. This file lists the critical failures and "why" they happen. Use it to explain risks to the user.
- For Review: Always consult `references/validations.md`. This contains the strict rules and constraints. Use it to validate user inputs objectively.
Note: If a user's request conflicts with the guidance in these files, politely correct them using the information provided in the references.
Telegram Bot Builder
Patterns
---
Name
Bot Architecture
Description
Structure for maintainable Telegram bots
When To Use
When starting a new bot project
Implementation
Bot Architecture
Stack Options
| Language | Library | Best For |
|---|---|---|
| Node.js | telegraf | Most projects |
| Node.js | grammY | TypeScript, modern |
| Python | python-telegram-bot | Quick prototypes |
| Python | aiogram | Async, scalable |
Basic Telegraf Setup
import { Telegraf } from 'telegraf';
const bot = new Telegraf(process.env.BOT_TOKEN);
// Command handlers
bot.start((ctx) => ctx.reply('Welcome!'));
bot.help((ctx) => ctx.reply('How can I help?'));
// Text handler
bot.on('text', (ctx) => {
ctx.reply(`You said: ${ctx.message.text}`);
});
// Launch
bot.launch();
// Graceful shutdown
process.once('SIGINT', () => bot.stop('SIGINT'));
process.once('SIGTERM', () => bot.stop('SIGTERM'));Project Structure
telegram-bot/
├── src/
│ ├── bot.js # Bot initialization
│ ├── commands/ # Command handlers
│ │ ├── start.js
│ │ ├── help.js
│ │ └── settings.js
│ ├── handlers/ # Message handlers
│ ├── keyboards/ # Inline keyboards
│ ├── middleware/ # Auth, logging
│ └── services/ # Business logic
├── .env
└── package.json---
Name
Inline Keyboards
Description
Interactive button interfaces
When To Use
When building interactive bot flows
Implementation
Inline Keyboards
Basic Keyboard
import { Markup } from 'telegraf';
bot.command('menu', (ctx) => {
ctx.reply('Choose an option:', Markup.inlineKeyboard([
[Markup.button.callback('Option 1', 'opt_1')],
[Markup.button.callback('Option 2', 'opt_2')],
[
Markup.button.callback('Yes', 'yes'),
Markup.button.callback('No', 'no'),
],
]));
});
// Handle button clicks
bot.action('opt_1', (ctx) => {
ctx.answerCbQuery('You chose Option 1');
ctx.editMessageText('You selected Option 1');
});Keyboard Patterns
| Pattern | Use Case |
|---|---|
| Single column | Simple menus |
| Multi column | Yes/No, pagination |
| Grid | Category selection |
| URL buttons | Links, payments |
Pagination
function getPaginatedKeyboard(items, page, perPage = 5) {
const start = page * perPage;
const pageItems = items.slice(start, start + perPage);
const buttons = pageItems.map(item =>
[Markup.button.callback(item.name, `item_${item.id}`)]
);
const nav = [];
if (page > 0) nav.push(Markup.button.callback('◀️', `page_${page-1}`));
if (start + perPage < items.length) nav.push(Markup.button.callback('▶️', `page_${page+1}`));
return Markup.inlineKeyboard([...buttons, nav]);
}---
Name
Bot Monetization
Description
Making money from Telegram bots
When To Use
When planning bot revenue
Implementation
Bot Monetization
Revenue Models
| Model | Example | Complexity |
|---|---|---|
| Freemium | Free basic, paid premium | Medium |
| Subscription | Monthly access | Medium |
| Per-use | Pay per action | Low |
| Ads | Sponsored messages | Low |
| Affiliate | Product recommendations | Low |
Telegram Payments
// Create invoice
bot.command('buy', (ctx) => {
ctx.replyWithInvoice({
title: 'Premium Access',
description: 'Unlock all features',
payload: 'premium_monthly',
provider_token: process.env.PAYMENT_TOKEN,
currency: 'USD',
prices: [{ label: 'Premium', amount: 999 }], // $9.99
});
});
// Handle successful payment
bot.on('successful_payment', (ctx) => {
const payment = ctx.message.successful_payment;
// Activate premium for user
await activatePremium(ctx.from.id);
ctx.reply('🎉 Premium activated!');
});Freemium Strategy
Free tier:
- 10 uses per day
- Basic features
- Ads shown
Premium ($5/month):
- Unlimited uses
- Advanced features
- No ads
- Priority supportUsage Limits
async function checkUsage(userId) {
const usage = await getUsage(userId);
const isPremium = await checkPremium(userId);
if (!isPremium && usage >= 10) {
return { allowed: false, message: 'Daily limit reached. Upgrade?' };
}
return { allowed: true };
}---
Name
Webhook Deployment
Description
Production bot deployment
When To Use
When deploying bot to production
Implementation
Webhook Deployment
Polling vs Webhooks
| Method | Best For |
|---|---|
| Polling | Development, simple bots |
| Webhooks | Production, scalable |
Express + Webhook
import express from 'express';
import { Telegraf } from 'telegraf';
const bot = new Telegraf(process.env.BOT_TOKEN);
const app = express();
app.use(express.json());
app.use(bot.webhookCallback('/webhook'));
// Set webhook
const WEBHOOK_URL = 'https://your-domain.com/webhook';
bot.telegram.setWebhook(WEBHOOK_URL);
app.listen(3000);Vercel Deployment
// api/webhook.js
import { Telegraf } from 'telegraf';
const bot = new Telegraf(process.env.BOT_TOKEN);
// ... bot setup
export default async (req, res) => {
await bot.handleUpdate(req.body);
res.status(200).send('OK');
};Railway/Render Deployment
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["node", "src/bot.js"]Anti-Patterns
---
Name
Blocking Operations
Description
Long operations blocking bot responses
Why Bad
Telegram has timeout limits. Users think bot is dead. Poor experience. Requests pile up.
What To Do Instead
Acknowledge immediately. Process in background. Send update when done. Use typing indicator.
---
Name
No Error Handling
Description
Bot crashes on unexpected input
Why Bad
Users get no response. Bot appears broken. Debugging nightmare. Lost trust.
What To Do Instead
Global error handler. Graceful error messages. Log errors for debugging. Rate limiting.
---
Name
Spammy Bot
Description
Sending too many messages
Why Bad
Users block the bot. Telegram may ban. Annoying experience. Low retention.
What To Do Instead
Respect user attention. Consolidate messages. Allow notification control. Quality over quantity.
Telegram Bot Builder - Sharp Edges
Rate Limits
Id
rate-limits
Summary
Bot gets rate limited by Telegram
Severity
high
Situation
Bot stops responding or messages fail
Why
Too many messages per second. Bulk messaging without throttling. Not handling 429 errors. Webhook flooding.
Solution
Telegram Rate Limits
Know the Limits
| Action | Limit |
|---|---|
| Messages to user | 30/sec |
| Messages to group | 20/min |
| Bulk notifications | 30/sec total |
| API calls | Varies |
Throttling Implementation
import Bottleneck from 'bottleneck';
const limiter = new Bottleneck({
maxConcurrent: 1,
minTime: 33, // ~30 per second
});
async function sendMessage(chatId, text) {
return limiter.schedule(() =>
bot.telegram.sendMessage(chatId, text)
);
}Handle 429 Errors
bot.catch((err, ctx) => {
if (err.response?.error_code === 429) {
const retryAfter = err.response.parameters?.retry_after || 30;
console.log(`Rate limited. Retry after ${retryAfter}s`);
// Queue for retry
}
});Bulk Messaging
async function broadcastMessage(userIds, message) {
for (const userId of userIds) {
try {
await sendMessage(userId, message);
await sleep(50); // 50ms between messages
} catch (err) {
if (err.response?.error_code === 403) {
// User blocked bot
await markUserInactive(userId);
}
}
}
}Symptoms
- "Too Many Requests" errors
- Messages not delivering
- 429 error codes
- Bot seems slow
Detection Pattern
rate limit|429|too many|throttle
Webhook Not Working
Id
webhook-not-working
Summary
Webhook not receiving updates
Severity
high
Situation
Bot works locally but not in production
Why
HTTPS required for webhooks. Wrong webhook URL. Certificate issues. Firewall blocking.
Solution
Webhook Troubleshooting
Requirements
- HTTPS only (no self-signed in prod)
- Port 443, 80, 88, or 8443
- Valid SSL certificate
- Publicly accessible URL
Check Webhook Status
curl "https://api.telegram.org/bot<TOKEN>/getWebhookInfo"Common Fixes
// 1. Set webhook explicitly
bot.telegram.setWebhook('https://your-domain.com/webhook');
// 2. Delete old webhook first
bot.telegram.deleteWebhook();
// 3. Check pending updates
const info = await bot.telegram.getWebhookInfo();
console.log(info);Local Development
# Use ngrok for local testing
ngrok http 3000
# Then set webhook to ngrok URLVercel/Serverless Issues
- Ensure function is accessible
- Check function logs
- Verify environment variables
- Test endpoint directly
Symptoms
- Works with polling, not webhook
- No logs in production
- getWebhookInfo shows errors
- Updates not arriving
Detection Pattern
webhook|not working|production|deploy
User State Management
Id
user-state-management
Summary
Bot loses user context between messages
Severity
medium
Situation
Multi-step flows break, bot forgets user state
Why
No state persistence. Using in-memory storage. Serverless cold starts. Not tracking conversations.
Solution
User State Management
State Storage Options
| Storage | Best For |
|---|---|
| Redis | Fast, temporary state |
| PostgreSQL | Persistent data |
| SQLite | Simple bots |
| Telegraf sessions | Development |
Telegraf Sessions
import { session } from 'telegraf';
// In-memory (development only)
bot.use(session());
// Redis (production)
import { Redis } from '@telegraf/session/redis';
bot.use(session({
store: Redis({ url: process.env.REDIS_URL }),
}));
// Use session
bot.command('start', (ctx) => {
ctx.session.step = 'awaiting_name';
ctx.reply('What is your name?');
});
bot.on('text', (ctx) => {
if (ctx.session.step === 'awaiting_name') {
ctx.session.name = ctx.message.text;
ctx.session.step = 'awaiting_email';
ctx.reply('What is your email?');
}
});Scene/Wizard Pattern
import { Scenes } from 'telegraf';
const wizard = new Scenes.WizardScene(
'onboarding',
(ctx) => {
ctx.reply('Step 1: Enter your name');
return ctx.wizard.next();
},
(ctx) => {
ctx.wizard.state.name = ctx.message.text;
ctx.reply('Step 2: Enter your email');
return ctx.wizard.next();
},
(ctx) => {
const { name } = ctx.wizard.state;
ctx.reply(`Done! Welcome ${name}`);
return ctx.scene.leave();
}
);Symptoms
- Multi-step flows fail
- "Start over" needed frequently
- User data lost
- Inconsistent behavior
Detection Pattern
state|session|forgot|lost|context
Blocked Users
Id
blocked-users
Summary
Users block bot but you keep trying to message
Severity
medium
Situation
Error logs full of "bot blocked by user"
Why
Not tracking who blocked. Wasting API calls. Filling logs with errors. Affecting rate limits.
Solution
Handling Blocked Users
Detect Block
async function sendSafe(chatId, message) {
try {
await bot.telegram.sendMessage(chatId, message);
return { success: true };
} catch (err) {
if (err.response?.error_code === 403) {
// User blocked bot or deleted account
await markUserInactive(chatId);
return { success: false, blocked: true };
}
throw err;
}
}Track Active Users
-- Users table
CREATE TABLE users (
telegram_id BIGINT PRIMARY KEY,
username TEXT,
is_active BOOLEAN DEFAULT true,
blocked_at TIMESTAMP
);Clean Broadcast List
async function broadcast(message) {
const activeUsers = await db.users.findMany({
where: { is_active: true }
});
for (const user of activeUsers) {
const result = await sendSafe(user.telegram_id, message);
if (result.blocked) {
// Already marked inactive in sendSafe
}
}
}Symptoms
- Lots of 403 errors
- Broadcast failing silently
- Wasted API calls
- Inaccurate user counts
Detection Pattern
403|blocked|forbidden|can't send
Telegram Bot Builder - Validations
Bot Token Hardcoded
Id
token-in-code
Severity
high
Type
pattern
Check
Bot token should be in environment variables
Pattern
[0-9]{9,10}:[A-Za-z0-9_-]{35}
Indicators
- Bot token in source code
- Token not in .env
- Token committed to git
Message
Bot token appears to be hardcoded - security risk!
Fix Action
Move token to environment variable BOT_TOKEN
No Bot Error Handler
Id
no-error-handling
Severity
high
Type
pattern
Check
Bot should have global error handler
Pattern
bot\.catch|on\(['"]error['"]
Indicators
- No bot.catch() handler
- Unhandled promise rejections
- Bot crashes on errors
Message
No global error handler for bot.
Fix Action
Add bot.catch() to handle errors gracefully
No Rate Limiting
Id
no-rate-limiting
Severity
medium
Type
conceptual
Check
Should have rate limiting for messages
Indicators
- No throttling on sends
- Bulk messages without delays
- No bottleneck usage
Message
No rate limiting - may hit Telegram limits.
Fix Action
Add throttling with Bottleneck or similar library
In-Memory Sessions in Production
Id
memory-sessions
Severity
medium
Type
pattern
Check
Sessions should use persistent storage in production
Pattern
session\(\)
Indicators
- Default session() without store
- No Redis/database session store
- Sessions lost on restart
Message
Using in-memory sessions - will lose state on restart.
Fix Action
Use Redis or database-backed session store for production
No Typing Indicator
Id
no-typing-indicator
Severity
low
Type
conceptual
Check
Should show typing indicator for slow operations
Indicators
- No sendChatAction
- Long operations without feedback
- Users wonder if bot is working
Message
Consider adding typing indicator for better UX.
Fix Action
Add ctx.sendChatAction('typing') before slow operations