TG Telegram Listener ◀️
Make ComfyUI sit and wait for a Telegram message
- message_text
- chat_id
- message_image
- message_video
- message_audio
- message_id
- message_thread_id
- message_type
The old way to put a chatbot on your ComfyUI install was to run a second program - a Python bot script sitting outside ComfyUI, calling into the API, needing its own daemon and its own crash-recovery. The Listener flips that: the bot is a node in your graph. You paste a token, press Run, and your workflow becomes something people can talk to in Telegram.
It's also the node that makes the whole pack make sense. Everything else here sends, edits, or shows a typing indicator. This one is the part that listens.
What it actually does
Under the hood it's boring in the good way: long polling against api.telegram.org with the httpx client that's already a ComfyUI dependency. A background daemon thread calls getUpdates while ComfyUI is busy generating, and each complete message lands in an in-process inbox. When the node executes it takes one message off that queue, or waits up to timeout_time and then gives up quietly. No webhook, no port forwarding, no public URL, no python-telegram-bot SDK.
The pairing that makes it feel autonomous is ComfyUI's Run (Instant) mode. The node's IS_CHANGED returns float("nan"), which is the standard ComfyUI trick for "always re-run me" - NaN is not equal to anything, itself included, so the cache can't skip it (the node-plumbing layer of ComfyUI works exactly this way, and yes, it costs you the cache for that branch). The workflow completes one message, Instant submits the next run, and the loop just keeps going. Batch count stays at 1.
The four widgets
Two of them you'll touch once, two you'll actually think about.
bot_token is the string from @BotFather. It's validated on the spot: it has to match digits:letters, so a token with a stray quote or a pasted "bot" prefix fails loudly before anything hits the network.
timeout_time (1–300, default 10) is not a polling interval and not a delay added to your replies. It's how long a single run is willing to sit waiting for something to show up. A message that arrives during the wait returns immediately; only silence makes the run wait the full window.
access_mode plus chat_ids is the part nobody reads and everybody needs. Default is blacklist: listed ChatIDs are rejected, and an empty blacklist means anyone who finds your bot can use your GPU. whitelist inverts it - only listed chat IDs work, and an empty whitelist lets nobody in, which is a good way to think your bot is broken. Chat IDs go in as plain numbers separated by newlines, spaces, commas or semicolons, and group IDs keep their minus sign. Note these are chat IDs - filtering a group filters the whole group, not its members. Use DMs if you want per-person control. A bad entry is caught as a config error before any message is consumed.
The eight outputs
message_text is the text, command or media caption, empty when there isn't one. chat_id is the one you wire into literally every sender - negative for groups. message_type tells you text, image, video or audio. Then the media outputs: message_image as an IMAGE tensor, message_video as VHS_FILENAMES (feeds straight into Send Video), and message_audio decoded at 48 kHz. message_thread_id is the forum-topic ID, or -1 for ordinary chats - wire it into a sender if you want replies to land in the right topic. message_id is the incoming message's ID, which is why you should not feed it to an edit node: the bot can only edit messages the bot sent.
The clever bit is what an empty output does. Anything missing becomes a silent ExecutionBlocker, so a text-only message doesn't fake an image for your image branch - that branch simply doesn't run, the run still succeeds, and Instant queues the next one. Same story on idle timeout and on rejected chats.
Install
Manager → Custom Nodes Manager → search ComfyUI Autonomous Telegram Bot → Install → restart. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/CoolBreeze164/ComfyUI-Autonomous-Telegram-Bot
python -m pip install -r ComfyUI-Autonomous-Telegram-Bot/requirements.txt
On Windows portable, use python_embeded\python.exe for that pip line. Deps are httpx, numpy, pillow and av>=14.2.0 - all four usually already present, since PyAV is a core ComfyUI dependency. No model downloads. Nodes appear under Autonomous Telegram Bot ◀️, and you need a current ComfyUI with ExecutionBlocker support plus the Run (Instant) button.
When it doesn't reply
- Nothing arrives: the workflow tab has to be open and running in Run (Instant), batch count 1. Close the tab and requeueing stops, because the frontend owns that loop.
- "Terminated by other getUpdates request": something else is polling that token. Telegram allows one poller per token, and polling and webhooks are mutually exclusive. Clear a stale webhook with API Method +
deleteWebhook,drop_pending_updates=false. - It dies after ~90 seconds of network trouble: the poller has a 90-second outage budget, then stops and surfaces that on the next run. Restore the connection and press Run again - no ComfyUI restart needed. One wrinkle: if the workflow was paused when the error hit, the first Run reports the stored error and the second one restarts normally.
- Telegram is blocked in your country: this is plain HTTPS to the Bot API, not MTProto, so a VPN or Cloudflare WARP is the fix. There's no SOCKS path here.
- Your token is in the workflow JSON. Widget tokens get saved with the graph. Strip them before sharing, or feed the token from a text file.
One bot token, one receiver, one active workflow. Public getFile downloads cap at 20 MB, albums arrive as separate messages (one per run), and edited messages are not treated as new jobs.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| bot_token | STRING | — | |
| timeout_time | INT | 101–300 | Wait per run in seconds. Idle runs skip downstream nodes; Instant queues the next run. |
| access_mode | COMBO | blacklist | Blacklist rejects listed chats. Whitelist only accepts listed chats. |
| chat_ids | STRING | Numeric ChatIDs, separated by newlines, spaces, commas or semicolons. Keep the minus sign for groups. Empty blacklist allows everyone; empty whitelist allows nobody. |
Outputs (8)
| Name | Type | Description |
|---|---|---|
| message_text | STRING | — |
| chat_id | INT | — |
| message_image | IMAGE | — |
| message_video | VHS_FILENAMES | — |
| message_audio | AUDIO | — |
| message_id | INT | — |
| message_thread_id | INT | — |
| message_type | STRING | — |