name: tg-alerts description: Use when adding Telegram error notifications to any project. Guides through bot creation with @BotFather, chat/channel/forum-topic ID discovery, alert service implementation with deduplication and graceful failure, and framework-specific integration for Python (async/sync) and Node.js.
Telegram Error Alerts
Adds operational error alerts to any project via a dedicated Telegram bot. Alerts go to a private channel, group, or forum topic — not to end users. Battle-tested pattern with deduplication, HTML formatting, and crash-proof error handling.
When to Use
- User asks to add error notifications, Telegram alerts, or operational monitoring
- Setting up a new deployment and want to know when things break
- NOT for: user-facing bot messages or interactive Telegram features
Setup Flow
This skill is interactive. Each phase involves asking the user questions or guiding them through Telegram actions.
digraph flow {
rankdir=LR;
"Assess\nProject" -> "Create\nBot" -> "Get\nChat ID" -> "Generate\nCode" -> "Integrate" -> "Test";
}
Phase 1: Assess Project
Detect from codebase or ASK:
- Language — Python / Node.js / TypeScript / other
- Framework — FastAPI, Django, Flask, Express, NestJS, Hono, etc.
- Async or sync — determines implementation variant
- Already has a Telegram bot? — alert bot MUST be separate from any main bot
Phase 2: Create Alert Bot
Guide the user through these Telegram steps:
- Open Telegram, find @BotFather
- Send
/newbot- Name: something like "MyApp Alerts"
- Username: something like
myapp_alerts_bot- BotFather replies with a token — copy it
- Save as
ALERT_BOT_TOKENin.env
ASK the user to confirm they have the token before proceeding.
Phase 3: Get Chat ID
ASK: "Where should alerts go?"
| Target | Best for | Complexity |
|---|---|---|
| Private chat | Solo dev | Easiest |
| Group | Small team | Easy |
| Channel | Read-only broadcast | Medium |
| Forum topic | Organized by category | Medium |
Guide based on their choice:
Option A: Private Chat
- Open Telegram, find your new alert bot
- Send it any message (e.g., "hello")
- Run in terminal:
curl -s "https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates" | python3 -m json.tool
- Find
"chat": {"id": 123456789}— that positive number is yourALERT_CHAT_ID
Option B: Group
- Create a Telegram group (or use existing)
- Add the alert bot to the group
- Send any message in the group
- Run the
getUpdatescurl above- Find
chat.id— negative number like-1001234567890
Option C: Channel
- Create a channel (or use existing)
- Add the alert bot as administrator (needs "Post Messages" permission)
- Post any message in the channel
- Run
getUpdates- Find
"channel_post"->"chat"->"id"— negative, starts with-100
Option D: Forum Topic
- Create a group -> Settings -> enable Topics
- Add the bot to the group
- Create a topic (e.g., "Errors")
- Send a message inside that topic
- Run
getUpdates- Find TWO values:
chat.id->ALERT_CHAT_IDmessage_thread_id->ALERT_THREAD_ID
Verify IDs
Always test before writing code:
curl -s -X POST "https://api.telegram.org/bot<TOKEN>/sendMessage" \
-d chat_id=<CHAT_ID> -d "text=Test alert" -d parse_mode=HTML
For forum topics, add -d message_thread_id=<THREAD_ID>.
If the message appears in Telegram, proceed to Phase 4.
Troubleshooting empty getUpdates:
- Send another message, then run curl immediately (updates expire)
- For channels: bot must be admin, not just member
- For groups: send
/setprivacyto @BotFather -> set to Disabled
Phase 4: Generate Alert Service
Use the appropriate reference implementation from this skill's directory:
| Stack | Reference File |
|---|---|
| Python async (FastAPI, aiohttp) | references/alert_service_async.py |
| Python sync (Django, Flask) | references/alert_service_sync.py |
| Node.js / TypeScript | references/alert_service_node.ts |
Read the reference file and adapt to the project:
- Match code style, naming conventions, import patterns
- Use the project's existing HTTP client if available
- Place where services/utils live in the project structure
- Add env vars to the project's config system
Phase 5: Framework Integration
Wire alert service into the project's error handling. The pattern:
- Initialize on startup (only if env vars present)
- Attach logging handler to root logger (captures all
logger.error()/console.error()) - Add unhandled exception handler specific to the framework
- Send lifecycle alert on startup and shutdown
| Framework | Unhandled Exception Hook | Startup Hook |
|---|---|---|
| FastAPI | @app.exception_handler(Exception) |
lifespan context manager |
| Django | Custom middleware + 500 handler | AppConfig.ready() |
| Flask | @app.errorhandler(Exception) |
App factory / before_first_request |
| Express | app.use((err, req, res, next) => ...) |
After app.listen() |
| NestJS | @Catch() exception filter |
onModuleInit() |
Phase 6: Environment Variables
Add to .env and .env.example:
# Telegram operational alerts (optional)
# ALERT_BOT_TOKEN=123456:ABC-DEF...
# ALERT_CHAT_ID=-1001234567890
# ALERT_THREAD_ID=42
Ensure the config treats these as optional — alerting gracefully disables when not configured:
alerting_enabled = bool(ALERT_BOT_TOKEN and ALERT_CHAT_ID)
Phase 7: Test
- Start the app with alert env vars set
- Check for startup lifecycle alert in Telegram
- Trigger an intentional error (e.g., hit a broken endpoint)
- Verify error alert appears with traceback
- Trigger same error again — verify dedup blocks the duplicate
- Stop the app — verify shutdown alert
Alert Message Format
Consistent across all stacks — use Telegram HTML parse mode:
🔴 <b>Error</b>
<pre>Env: production
Error: ValueError
Context: [module.name] error message
Traceback (most recent call last):
...</pre>
🟡 <b>Warning</b>
<pre>Env: production
Some warning message</pre>
🟢
<pre>Application started
Env: production</pre>
Critical Design Rules
Non-negotiable for every implementation:
- Alert failures NEVER crash the app — wrap all sending in try/except or try/catch
- Log alert failures at DEBUG — ERROR would trigger the handler again -> infinite loop
- Deduplicate by exception location — key:
{ExcType}:{lineno}@{filename}. One alert per crash site - Truncate to 3500 chars — Telegram limit is 4096; stay well under
- HTML-escape all dynamic content — tracebacks contain
<>&breaking Telegram HTML - Separate bot — never reuse the main app bot for alerts
- Include environment — every alert shows dev/staging/prod
- Make alerting optional — app runs normally without alert env vars
- Fire-and-forget — async:
create_task(), sync: daemon thread. Never block requests - Cap dedup set at ~10k — clear when full to prevent unbounded memory growth
Common Mistakes
| Mistake | Consequence | Fix |
|---|---|---|
| Same bot for app + alerts | Alerts fail when app bot is down | Separate bot token |
| No dedup | Hundreds of identical alerts | Dedup by exc type + location |
await send_alert() in request path |
Slow requests if Telegram lags | Fire-and-forget |
| Log send failure at ERROR | Infinite alert loop | Log at DEBUG |
| No truncation | Telegram silently drops message | Truncate to 3500 chars |
| Raw HTML in traceback | Broken formatting | html.escape() all content |
| Alert required for startup | App won't start without Telegram | Optional via alerting_enabled |
getUpdates returns empty |
Can't find chat ID | Send message first, curl immediately |