Discourse-Telegram chat bridge

:information_source: Summary Real-time, two-way bridge between Discourse Chat and Telegram, with first-class support for Telegram forum topics
:hammer_and_wrench: Repository Link GitHub - babylai/discourse-telegram-chat-bridge: Real-time two-way bridge between Discourse Chat and Telegram (design phase / POC) · GitHub
:open_book: Install Guide How to install plugins in Discourse

Features

Each Discourse chat channel is mapped to a Telegram chat — either a plain group, or a specific topic in a supergroup with Topics enabled. A message posted on one side shows up on the other within a second or two.

Discourse → Telegram Telegram → Discourse
Text (with formatting) :white_check_mark: real HTML formatting :white_check_mark: entities → Markdown
Emojis :white_check_mark: :white_check_mark:
Replies :white_check_mark: :white_check_mark:
Edits :white_check_mark: :white_check_mark:
Deletions :white_check_mark: :cross_mark: (Bot API limitation, see below)
Photos :white_check_mark: photos & albums :white_check_mark: downloaded and re-uploaded
Other files :white_check_mark: :white_check_mark: documents, video, audio, voice
Stickers :white_check_mark: static as image; animated degrade to their emoji
  • Author attribution: bots can’t impersonate users on either platform, so messages carry the author as a bold prefix — **Maria:** hello in Discourse, maria: in Telegram.
  • Loop-safe: messages posted by the bridge itself are never relayed back.
  • Idempotent jobs: retries and webhook redeliveries never produce duplicate messages.
  • Rate-limit aware: on HTTP 429 the job re-enqueues after exactly the wait Telegram asks for.
  • Graceful degradation: files over the Bot API limits (20 MB download / 50 MB upload) become an [file omitted: name (size)] note; unsupported formatting degrades to plain text.
  • /id setup command: type /id in any group or topic the bot can see and it replies with the ids plus a ready-to-paste mapping line.

Known limitations

  • Deletions in Telegram are not synced to Discourse — the Telegram Bot API has no deletion event. This is a platform limitation, not a configuration issue.
  • Telegram only lets bots edit their own messages for 48 hours; Discourse edits of older messages are not reflected on the Telegram side.
  • Reactions are not bridged.
  • Discourse chat threads are not mapped to Telegram topics; thread replies are bridged flat.

Configuration

1. Create the Telegram bot

  1. Create a bot via @BotFather and copy the token.
  2. Disable privacy mode (/setprivacy → Disable), or the bot only sees /commands. :warning: If the bot is already in a group, remove and re-add it — the change doesn’t apply to existing memberships otherwise.
  3. Add the bot to your group as an admin (it needs Delete messages for deletion sync).
  4. To bridge into specific topics, enable Topics in the group settings.

2. Configure the site settings (Admin → Plugins → Telegram Bridge): enable the plugin, paste the bot token, and set a random webhook secret (e.g. openssl rand -hex 24).

3. Register the webhook — easiest through the plugin’s own client, which sets the correct allowed_updates for you:

cd /var/discourse
./launcher enter app
rails runner "puts DiscourseTelegramChatBridge::TelegramClient.new.set_webhook(
  url: 'https://YOUR-SITE/telegram-bridge/webhook',
  secret_token: SiteSetting.telegram_bridge_webhook_secret)"

:warning: allowed_updates lives in the webhook registration stored at Telegram, not in the plugin code. If you register manually and omit edited_message, Telegram silently never delivers edits.

4. Map channels — type /id in each group/topic, then add one line per bridged channel to telegram_bridge_mappings:

chat_channel_id:telegram_chat_id:telegram_thread_id

The Discourse channel id is the number at the end of the channel URL (/chat/c/<slug>/<id>); leave the thread id blank for the General topic or a plain group. On every boot and mapping change the plugin logs one active mappings summary line you can grep to confirm what is bridged.

5. Verify — send a message in each direction. If nothing happens, check in order: the active mappings log line, the webhook info (get_webhook_info), and privacy mode.

Settings

Name Description
telegram_bridge_enabled Master on/off switch for the bridge.
telegram_bridge_bot_token Telegram Bot API token, issued by @BotFather (secret).
telegram_bridge_webhook_secret Secret validated against Telegram’s X-Telegram-Bot-Api-Secret-Token header on incoming webhook requests (secret).
telegram_bridge_mappings Channel mappings, one per line: chat_channel_id:telegram_chat_id:telegram_thread_id (thread id optional).

:lock: Privacy note: content from bridged channels leaves your Discourse instance and is stored with Telegram (and vice versa). Only channels explicitly listed in the mappings are ever bridged — but do tell the members of those channels.

1 Like