Visor provides Telegram bot integration via long polling, enabling interactive workflows, AI-powered chat assistants, and automated responses directly in Telegram DMs, groups, supergroups (including forum topics), and channels.
- Overview
- Prerequisites
- Configuration
- Chat Types
- Features
- Example Workflows
- Telegram Side Settings
- Troubleshooting
- Related Documentation
The Telegram integration enables:
- DM Conversations: Respond to direct messages without any mention requirements
- Group Chat Support: Respond in groups and supergroups when @mentioned or replied to
- Forum Topic Support: Thread-aware sessions in supergroup forum topics
- Channel Processing: Process channel posts (bot must be admin)
- Reaction Management: Visual acknowledgement (👀) and completion (👍) emoji reactions
- HTML Formatting: Markdown AI output automatically converted to Telegram HTML
- Message Chunking: Long responses auto-split at 4096-character Telegram limit
- Hot Reload: Configuration changes picked up without restarting the bot
The integration uses grammY with @grammyjs/runner for concurrent update processing with automatic backoff and stall detection.
-
Open Telegram and start a chat with @BotFather
-
Create a new bot:
- Send
/newbot - Follow the prompts to choose a name and username
- Save the bot token (format:
123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11)
- Send
-
Configure privacy mode (for group usage):
- Send
/setprivacyto @BotFather - Select your bot
- Choose Disable to let the bot see all group messages
- Alternatively, make the bot a group admin (admins always see all messages)
- Send
# Required
export TELEGRAM_BOT_TOKEN="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"Enable Telegram long-polling runner with the --telegram flag:
visor --config workflow.yaml --telegram| Variable | Description | Required |
|---|---|---|
TELEGRAM_BOT_TOKEN |
Bot token from @BotFather | Yes |
Add Telegram-specific configuration in your workflow YAML:
version: "1"
# Telegram runtime configuration
telegram:
require_mention: true # Require @mention in groups (default: true)
chat_allowlist: # Optional: limit to specific chat IDs
- -1001234567890
- 98765432
# Frontend configuration for posting to Telegram
frontends:
- name: telegram
checks:
# Your workflow checks...| Option | Type | Default | Description |
|---|---|---|---|
bot_token |
string | $TELEGRAM_BOT_TOKEN |
Bot token (config overrides env) |
require_mention |
boolean | true |
Require @mention or reply-to-bot in groups/supergroups |
chat_allowlist |
(string|number)[] | [] |
Limit to specific chat IDs (empty = all chats) |
polling_timeout |
number | 30 |
Long polling timeout in seconds |
workflow |
string | — | Optional workflow name to dispatch |
Visor's Telegram integration handles all four Telegram chat types:
- Always accepted — no mention required regardless of
require_mentionsetting - Ideal for personal assistant workflows
- Each DM conversation gets its own workspace
- With
require_mention: true(default): Bot only responds when:- The message contains
@bot_username, or - The message is a reply to one of the bot's messages
- The message contains
- With
require_mention: false: Bot responds to all messages - Supergroups with forum topics use thread-aware sessions (
chat_id:topic_id)
- Each topic gets an isolated workspace (keyed by
chat_id:message_thread_id) - Replies include
message_thread_idto stay within the correct topic - Mention and reply-to-bot gating applies per-topic
- Always accepted — channels don't have mention semantics
- Bot must be added as a channel admin to receive and post in channels
- Channel posts arrive as
channel_postupdates (notmessage)
The Telegram frontend automatically posts AI responses to the originating chat:
- AI check outputs with
textfields are posted as replies - Messages are formatted using Telegram HTML (
<b>,<i>,<code>,<pre>, etc.) - Replies include
reply_to_message_idto thread in groups - Forum topic replies include
message_thread_idto stay in the correct topic
checks:
reply:
type: ai
schema: text
on:
- telegram_message
- manual
prompt: |
You are a helpful assistant.
Respond concisely to the user's message.
User message: {{ webhook.event.text }}The frontend manages emoji reactions for visual feedback:
- Acknowledgement (👀): Added when a check is scheduled
- Completion (👍): Replaces acknowledgement when workflow completes
Note: Emoji reactions require the bot to be an admin in groups. Reaction failures are non-fatal and silently ignored.
AI output in Markdown is automatically converted to Telegram HTML:
| Markdown | Telegram HTML |
|---|---|
# Header |
<b>Header</b> |
**bold** |
<b>bold</b> |
*italic* |
<i>italic</i> |
`code` |
<code>code</code> |
```block``` |
<pre>block</pre> |
[label](url) |
<a href="url">label</a> |
~~strike~~ |
<s>strike</s> |
> quote |
<blockquote>quote</blockquote> |
- item |
• item |
Code blocks with language hints are rendered with <pre><code class="language-X">.
If Telegram rejects the HTML (malformed tags), the message is automatically retried as plain text.
Telegram limits messages to 4096 characters. Long AI responses are automatically split into multiple messages at newline boundaries, preserving code block integrity where possible.
When a Telegram message triggers a workflow, the full event context is available in templates:
checks:
reply:
type: ai
prompt: |
Chat type: {{ webhook.event.chat.type }}
User: {{ webhook.event.from.first_name }}
Message: {{ webhook.event.text }}Available webhook fields:
| Field | Description |
|---|---|
webhook.event.type |
message or channel_post |
webhook.event.chat_id |
Numeric chat ID |
webhook.event.message_id |
Message ID |
webhook.event.text |
Message text content |
webhook.event.from |
Sender info (id, first_name, username) |
webhook.event.chat |
Chat info (id, type, title, username) |
webhook.event.reply_to_message |
Replied-to message (if any) |
webhook.event.message_thread_id |
Forum topic ID (if applicable) |
webhook.telegram_conversation |
Normalized conversation context |
version: "1"
telegram:
require_mention: false
checks:
respond:
type: ai
schema: text
on:
- telegram_message
- manual
prompt: |
You are a helpful assistant running inside Visor.
Respond concisely to the user's message.
User message: {{ webhook.event.text }}version: "1"
telegram:
require_mention: true
chat_allowlist:
- -1001234567890
frontends:
- name: telegram
checks:
reply:
type: ai
schema: text
on:
- telegram_message
prompt: |
You are a team assistant in a Telegram group.
Answer the question briefly.
Question: {{ webhook.event.text }}# Set environment variable
export TELEGRAM_BOT_TOKEN="123456:ABC-..."
# Optional: enable debug logging
export VISOR_DEBUG=true
# Start the bot
visor --config workflow.yaml --telegramThe bot will:
- Initialize via
getMeAPI call - Start long polling with concurrent update processing
- Filter messages based on chat type, allowlist, and mention settings
- Process messages through your workflow
- Post formatted responses back to the originating chat
visor --config workflow.yaml --telegram --watchThe --watch flag enables hot reload — YAML changes are picked up automatically without restarting the bot.
Telegram bots default to Privacy Mode, which limits what group messages they receive. If the bot must see all group messages:
- Option A: Disable privacy mode via
/setprivacyin @BotFather - Option B: Make the bot a group admin (admins always see all messages)
When toggling privacy mode, remove and re-add the bot in each group so Telegram applies the change.
Useful @BotFather commands for configuration:
| Command | Description |
|---|---|
/setprivacy |
Toggle privacy mode (group message visibility) |
/setjoingroups |
Allow or deny the bot being added to groups |
/setcommands |
Set the bot's command menu |
/setdescription |
Set the bot's description (shown on profile) |
/setabouttext |
Set the "About" text |
To find a chat ID for the chat_allowlist:
- DMs: Start the bot, send a message, check logs for
chat_id=... - Groups: Add the bot to the group, send a message, check logs
- API method:
Look for
curl "https://api.telegram.org/bot<TOKEN>/getUpdates"chat.idin the response.
Group IDs are negative numbers (e.g., -1001234567890).
"TELEGRAM_BOT_TOKEN is required"
- Ensure the
TELEGRAM_BOT_TOKENenvironment variable is set - Or set
telegram.bot_tokenin your config file
Bot starts but never receives messages
- Verify the token is correct (test with
curl https://api.telegram.org/bot<TOKEN>/getMe) - Ensure no other bot instance is polling with the same token (only one poller per token)
- Check network connectivity to
api.telegram.org
Bot not responding in groups
- Check that Privacy Mode is disabled (via
/setprivacyin @BotFather), or make the bot an admin - If
require_mention: true, ensure you @mention the bot or reply to its message - Check
chat_allowlistif configured — the group's chat ID must be listed - After toggling privacy mode, remove and re-add the bot to the group
Bot not responding in channels
- The bot must be added as a channel admin
- Channel support uses
channel_postevents, notmessage
Bot responding to its own messages
- This is handled automatically — the bot filters out messages from its own user ID
Duplicate responses
- The deduplication system handles this automatically
- If issues persist, check for multiple bot instances running with the same token
"can't parse entities" errors in logs
- The bot automatically retries with plain text when HTML parsing fails
- This is non-fatal and handled gracefully
Messages truncated
- Messages over 4096 characters are automatically chunked
- Very long single lines are force-split at the character limit
Reactions not appearing
- The bot needs admin permissions in groups to set reactions
- Reaction failures are non-fatal and silently ignored
- DMs may not support reactions depending on Telegram client version
Enable verbose logging for troubleshooting:
# Via environment variable
VISOR_DEBUG=true visor --config workflow.yaml --telegram
# Or via CLI flag
visor --config workflow.yaml --telegram --debugLog messages include:
[TelegramPolling]— Polling, message dispatch, and filtering[telegram-frontend]— Message posting, reactions, and errors
- Slack Integration — Bidirectional Slack integration via Socket Mode
- Event Triggers — GitHub events and how to trigger checks
- Liquid Templates — Template syntax for dynamic content in prompts
- Configuration — Core configuration reference
- Recipes — Common workflow patterns including chat loops
- Bot Transports RFC — Technical design document for bot integrations
- examples/telegram-simple-chat.yaml — Simple Telegram chat assistant example