Telegram (Bot API)
Status: production-ready for bot DMs + groups via grammY. Long polling is the default mode; webhook mode is optional.Pairing
Default DM policy for Telegram is pairing.
Channel troubleshooting
Cross-channel diagnostics and repair playbooks.
Gateway configuration
Full channel config patterns and examples.
Quick setup
Create the bot token in BotFather
Open Telegram and chat with @BotFather (confirm the handle is exactly
@BotFather).Run /newbot, follow prompts, and save the token.Token resolution order is account-aware. In practice, config values win over env fallback, and
TELEGRAM_BOT_TOKEN only applies to the default account.Telegram side settings
Privacy mode and group visibility
Privacy mode and group visibility
Telegram bots default to Privacy Mode, which limits what group messages they receive.If the bot must see all group messages, either:
- disable privacy mode via
/setprivacy, or - make the bot a group admin.
Group permissions
Group permissions
Admin status is controlled in Telegram group settings.Admin bots receive all group messages, which is useful for always-on group behavior.
Helpful BotFather toggles
Helpful BotFather toggles
/setjoingroupsto allow/deny group adds/setprivacyfor group visibility behavior
Access control and activation
- DM policy
- Group policy and allowlists
- Mention behavior
channels.telegram.dmPolicy controls direct message access:pairing(default)allowlistopen(requiresallowFromto include"*")disabled
channels.telegram.allowFrom accepts numeric Telegram user IDs. telegram: / tg: prefixes are accepted and normalized.
The onboarding wizard accepts @username input and resolves it to numeric IDs.
If you upgraded and your config contains @username allowlist entries, run openclaw doctor --fix to resolve them (best-effort; requires a Telegram bot token).Finding your Telegram user ID
Safer (no third-party bot):- DM your bot.
- Run
openclaw logs --follow. - Read
from.id.
@userinfobot or @getidsbot.Runtime behavior
- Telegram is owned by the gateway process.
- Routing is deterministic: Telegram inbound replies back to Telegram (the model does not pick channels).
- Inbound messages normalize into the shared channel envelope with reply metadata and media placeholders.
- Group sessions are isolated by group ID. Forum topics append
:topic:<threadId>to keep topics isolated. - DM messages can carry
message_thread_id; OpenClaw routes them with thread-aware session keys and preserves thread ID for replies. - Long polling uses grammY runner with per-chat/per-thread sequencing. Overall runner sink concurrency uses
agents.defaults.maxConcurrent. - Telegram Bot API has no read-receipt support (
sendReadReceiptsdoes not apply).
Feature reference
Live stream preview (message edits)
Live stream preview (message edits)
OpenClaw can stream partial replies by sending a temporary Telegram message and editing it as text arrives.Requirement:
channels.telegram.streamModeis not"off"(default:"partial")
off: no live previewpartial: frequent preview updates from partial textblock: chunked preview updates usingchannels.telegram.draftChunk
draftChunk defaults for streamMode: "block":minChars: 200maxChars: 800breakPreference: "paragraph"
maxChars is clamped by channels.telegram.textChunkLimit.This works in direct chats and groups/topics.For text-only replies, OpenClaw keeps the same preview message and performs a final edit in place (no second message).For complex replies (for example media payloads), OpenClaw falls back to normal final delivery and then cleans up the preview message.streamMode is separate from block streaming. When block streaming is explicitly enabled for Telegram, OpenClaw skips the preview stream to avoid double-streaming.Telegram-only reasoning stream:/reasoning streamsends reasoning to the live preview while generating- final answer is sent without reasoning text
Formatting and HTML fallback
Formatting and HTML fallback
Outbound text uses Telegram
parse_mode: "HTML".- Markdown-ish text is rendered to Telegram-safe HTML.
- Raw model HTML is escaped to reduce Telegram parse failures.
- If Telegram rejects parsed HTML, OpenClaw retries as plain text.
channels.telegram.linkPreview: false.Native commands and custom commands
Native commands and custom commands
Telegram command menu registration is handled at startup with Rules:Device pairing commands (
When the
setMyCommands.Native command defaults:commands.native: "auto"enables native commands for Telegram
- names are normalized (strip leading
/, lowercase) - valid pattern:
a-z,0-9,_, length1..32 - custom commands cannot override native commands
- conflicts/duplicates are skipped and logged
- custom commands are menu entries only; they do not auto-implement behavior
- plugin/skill commands can still work when typed even if not shown in Telegram menu
setMyCommands failedusually means outbound DNS/HTTPS toapi.telegram.orgis blocked.
Device pairing commands (device-pair plugin)
When the device-pair plugin is installed:/pairgenerates setup code- paste code in iOS app
/pair approveapproves latest pending request
Inline buttons
Inline buttons
Telegram message actions for agents and automation
Telegram message actions for agents and automation
Telegram tool actions include:
sendMessage(to,content, optionalmediaUrl,replyToMessageId,messageThreadId)react(chatId,messageId,emoji)deleteMessage(chatId,messageId)editMessage(chatId,messageId,content)
send, react, delete, edit, sticker, sticker-search).Gating controls:channels.telegram.actions.sendMessagechannels.telegram.actions.editMessagechannels.telegram.actions.deleteMessagechannels.telegram.actions.reactionschannels.telegram.actions.sticker(default: disabled)
Reply threading tags
Reply threading tags
Forum topics and thread behavior
Forum topics and thread behavior
Forum supergroups:
- topic session keys append
:topic:<threadId> - replies and typing target the topic thread
- topic config path:
channels.telegram.groups.<chatId>.topics.<threadId>
threadId=1) special-case:- message sends omit
message_thread_id(Telegram rejectssendMessage(...thread_id=1)) - typing actions still include
message_thread_id
requireMention, allowFrom, skills, systemPrompt, enabled, groupPolicy).Template context includes:MessageThreadIdIsForum
- private chats with
message_thread_idkeep DM routing but use thread-aware session keys/reply targets.
Audio, video, and stickers
Audio, video, and stickers
Audio messages
Telegram distinguishes voice notes vs audio files.- default: audio file behavior
- tag
[[audio_as_voice]]in agent reply to force voice-note send
Video messages
Telegram distinguishes video files vs video notes.Message action example:Stickers
Inbound sticker handling:- static WEBP: downloaded and processed (placeholder
<media:sticker>) - animated TGS: skipped
- video WEBM: skipped
Sticker.emojiSticker.setNameSticker.fileIdSticker.fileUniqueIdSticker.cachedDescription
~/.openclaw/telegram/sticker-cache.json
Reaction notifications
Reaction notifications
Telegram reactions arrive as
message_reaction updates (separate from message payloads).When enabled, OpenClaw enqueues system events like:Telegram reaction added: 👍 by Alice (@alice) on msg 42
channels.telegram.reactionNotifications:off | own | all(default:own)channels.telegram.reactionLevel:off | ack | minimal | extensive(default:minimal)
ownmeans user reactions to bot-sent messages only (best-effort via sent-message cache).- Telegram does not provide thread IDs in reaction updates.
- non-forum groups route to group chat session
- forum groups route to the group general-topic session (
:topic:1), not the exact originating topic
allowed_updates for polling/webhook include message_reaction automatically.Ack reactions
Ack reactions
ackReaction sends an acknowledgement emoji while OpenClaw is processing an inbound message.Resolution order:channels.telegram.accounts.<accountId>.ackReactionchannels.telegram.ackReactionmessages.ackReaction- agent identity emoji fallback (
agents.list[].identity.emoji, else ”👀”)
- Telegram expects unicode emoji (for example ”👀”).
- Use
""to disable the reaction for a channel or account.
Config writes from Telegram events and commands
Config writes from Telegram events and commands
Channel config writes are enabled by default (
configWrites !== false).Telegram-triggered writes include:- group migration events (
migrate_to_chat_id) to updatechannels.telegram.groups /config setand/config unset(requires command enablement)
Long polling vs webhook
Long polling vs webhook
Default: long polling.Webhook mode:
- set
channels.telegram.webhookUrl - set
channels.telegram.webhookSecret(required when webhook URL is set) - optional
channels.telegram.webhookPath(default/telegram-webhook) - optional
channels.telegram.webhookHost(default127.0.0.1)
127.0.0.1:8787.If your public endpoint differs, place a reverse proxy in front and point webhookUrl at the public URL.
Set webhookHost (for example 0.0.0.0) when you intentionally need external ingress.Limits, retry, and CLI targets
Limits, retry, and CLI targets
channels.telegram.textChunkLimitdefault is 4000.channels.telegram.chunkMode="newline"prefers paragraph boundaries (blank lines) before length splitting.channels.telegram.mediaMaxMb(default 5) caps inbound Telegram media download/processing size.channels.telegram.timeoutSecondsoverrides Telegram API client timeout (if unset, grammY default applies).- group context history uses
channels.telegram.historyLimitormessages.groupChat.historyLimit(default 50);0disables. - DM history controls:
channels.telegram.dmHistoryLimitchannels.telegram.dms["<user_id>"].historyLimit
- outbound Telegram API retries are configurable via
channels.telegram.retry.
Troubleshooting
Bot does not respond to non mention group messages
Bot does not respond to non mention group messages
- If
requireMention=false, Telegram privacy mode must allow full visibility.- BotFather:
/setprivacy-> Disable - then remove + re-add bot to group
- BotFather:
openclaw channels statuswarns when config expects unmentioned group messages.openclaw channels status --probecan check explicit numeric group IDs; wildcard"*"cannot be membership-probed.- quick session test:
/activation always.
Bot not seeing group messages at all
Bot not seeing group messages at all
- when
channels.telegram.groupsexists, group must be listed (or include"*") - verify bot membership in group
- review logs:
openclaw logs --followfor skip reasons
Commands work partially or not at all
Commands work partially or not at all
- authorize your sender identity (pairing and/or numeric
allowFrom) - command authorization still applies even when group policy is
open setMyCommands failedusually indicates DNS/HTTPS reachability issues toapi.telegram.org
Polling or network instability
Polling or network instability
- Node 22+ + custom fetch/proxy can trigger immediate abort behavior if AbortSignal types mismatch.
- Some hosts resolve
api.telegram.orgto IPv6 first; broken IPv6 egress can cause intermittent Telegram API failures. - Validate DNS answers:
Telegram config reference pointers
Primary reference:-
channels.telegram.enabled: enable/disable channel startup. -
channels.telegram.botToken: bot token (BotFather). -
channels.telegram.tokenFile: read token from file path. -
channels.telegram.dmPolicy:pairing | allowlist | open | disabled(default: pairing). -
channels.telegram.allowFrom: DM allowlist (numeric Telegram user IDs).openrequires"*".openclaw doctor --fixcan resolve legacy@usernameentries to IDs. -
channels.telegram.groupPolicy:open | allowlist | disabled(default: allowlist). -
channels.telegram.groupAllowFrom: group sender allowlist (numeric Telegram user IDs).openclaw doctor --fixcan resolve legacy@usernameentries to IDs. -
channels.telegram.groups: per-group defaults + allowlist (use"*"for global defaults).channels.telegram.groups.<id>.groupPolicy: per-group override for groupPolicy (open | allowlist | disabled).channels.telegram.groups.<id>.requireMention: mention gating default.channels.telegram.groups.<id>.skills: skill filter (omit = all skills, empty = none).channels.telegram.groups.<id>.allowFrom: per-group sender allowlist override.channels.telegram.groups.<id>.systemPrompt: extra system prompt for the group.channels.telegram.groups.<id>.enabled: disable the group whenfalse.channels.telegram.groups.<id>.topics.<threadId>.*: per-topic overrides (same fields as group).channels.telegram.groups.<id>.topics.<threadId>.groupPolicy: per-topic override for groupPolicy (open | allowlist | disabled).channels.telegram.groups.<id>.topics.<threadId>.requireMention: per-topic mention gating override.
-
channels.telegram.capabilities.inlineButtons:off | dm | group | all | allowlist(default: allowlist). -
channels.telegram.accounts.<account>.capabilities.inlineButtons: per-account override. -
channels.telegram.replyToMode:off | first | all(default:off). -
channels.telegram.textChunkLimit: outbound chunk size (chars). -
channels.telegram.chunkMode:length(default) ornewlineto split on blank lines (paragraph boundaries) before length chunking. -
channels.telegram.linkPreview: toggle link previews for outbound messages (default: true). -
channels.telegram.streamMode:off | partial | block(live stream preview). -
channels.telegram.mediaMaxMb: inbound/outbound media cap (MB). -
channels.telegram.retry: retry policy for outbound Telegram API calls (attempts, minDelayMs, maxDelayMs, jitter). -
channels.telegram.network.autoSelectFamily: override Node autoSelectFamily (true=enable, false=disable). Defaults to disabled on Node 22 to avoid Happy Eyeballs timeouts. -
channels.telegram.proxy: proxy URL for Bot API calls (SOCKS/HTTP). -
channels.telegram.webhookUrl: enable webhook mode (requireschannels.telegram.webhookSecret). -
channels.telegram.webhookSecret: webhook secret (required when webhookUrl is set). -
channels.telegram.webhookPath: local webhook path (default/telegram-webhook). -
channels.telegram.webhookHost: local webhook bind host (default127.0.0.1). -
channels.telegram.actions.reactions: gate Telegram tool reactions. -
channels.telegram.actions.sendMessage: gate Telegram tool message sends. -
channels.telegram.actions.deleteMessage: gate Telegram tool message deletes. -
channels.telegram.actions.sticker: gate Telegram sticker actions — send and search (default: false). -
channels.telegram.reactionNotifications:off | own | all— control which reactions trigger system events (default:ownwhen not set). -
channels.telegram.reactionLevel:off | ack | minimal | extensive— control agent’s reaction capability (default:minimalwhen not set). - Configuration reference - Telegram
- startup/auth:
enabled,botToken,tokenFile,accounts.* - access control:
dmPolicy,allowFrom,groupPolicy,groupAllowFrom,groups,groups.*.topics.* - command/menu:
commands.native,customCommands - threading/replies:
replyToMode - streaming:
streamMode(preview),draftChunk,blockStreaming - formatting/delivery:
textChunkLimit,chunkMode,linkPreview,responsePrefix - media/network:
mediaMaxMb,timeoutSeconds,retry,network.autoSelectFamily,proxy - webhook:
webhookUrl,webhookSecret,webhookPath,webhookHost - actions/capabilities:
capabilities.inlineButtons,actions.sendMessage|editMessage|deleteMessage|reactions|sticker - reactions:
reactionNotifications,reactionLevel - writes/history:
configWrites,historyLimit,dmHistoryLimit,dms.*.historyLimit