What Is zalo-tg?
zalo-tg is a TypeScript/Node.js messaging bridge built by williamcachamwri that synchronizes Zalo and Telegram through a single long-running process for developers and teams that need cross-platform chat parity. zalo-tg is one of the best Messaging Bridges tools for developers and teams syncing Zalo with Telegram. It covers more than 20 message and event flows, including text, media, polls, reactions, recalls, and forum-topic routing.
The practical value is simple: one Zalo conversation maps to one Telegram Forum Topic, so message history stays separated instead of collapsing into a noisy group feed. That design makes zalo-tg useful for support desks, internal ops groups, and Vietnamese teams that already live in Zalo but want Telegram-grade automation and bot workflows.
Quick Overview
| Attribute | Details |
|---|---|
| Type | Messaging Bridges |
| Best For | developers and teams syncing Zalo with Telegram |
| Language/Stack | TypeScript, Node.js, Telegraf, zca-js, ffmpeg |
| License | N/A |
| GitHub Stars | N/A |
| Pricing | Open-Source |
| Last Release | N/A |
Who Should Use zalo-tg?
- Platform engineers who need a self-hosted relay between Zalo and Telegram without building protocol adapters from scratch.
- Indie hackers shipping customer support bots or community bridges where message state, replies, and media handling matter.
- Ops teams running Telegram supergroups with forum topics and wanting each Zalo conversation isolated by topic.
- Vietnamese product teams that treat Zalo as the primary user channel but want Telegram as the operational console.
Not ideal for:
- Teams that want SaaS simplicity and do not want to manage bot tokens, Zalo sessions, or server uptime.
- Groups that cannot grant admin permissions in Telegram, because zalo-tg needs topic creation, deletion, pinning, and group management rights.
- Use cases that require durable historical mappings across restarts, because message-ID links are in memory and can be lost on process restart.
Key Features of zalo-tg
-
Forum Topic per conversation — zalo-tg maps each Zalo direct message or group to a dedicated Telegram Forum Topic inside a supergroup. Topic metadata is persisted in
data/topics.json, which keeps the conversation layout stable across restarts. -
Stateful message translation — it converts Zalo events into Telegram API calls like
sendMessage,sendPhoto,sendVideo,sendAnimation,sendDocument,sendVoice, andsendLocation. That gives you native Telegram rendering instead of a dumb text dump. -
Reply-chain preservation — replies on Telegram are resolved into Zalo quote objects, and reverse lookups use
sentMsgStoreso a Telegram reply can map back to the original Zalo message. The result is coherent threaded context instead of flat, context-free forwarding. -
Reaction forwarding — Telegram
message_reactionupdates are translated through an emoji table and forwarded to Zalo viaaddReaction. Zalo reactions are echoed back to Telegram as short text replies so the two sides stay readable even when one platform lacks a perfect native equivalent. -
Poll synchronization — zalo-tg syncs Zalo polls to Telegram native polls plus an editable score message, and it mirrors Telegram poll creation back to Zalo with a bot-owned clone poll for
poll_answerupdates. That means vote changes remain visible without manual reconciliation. -
Media group buffering — photo and video albums are buffered for a few hundred milliseconds before sending, which prevents fragmented uploads and preserves album semantics across platforms. The bridge also handles voice notes by converting OGG Opus to M4A with
ffmpegwhen needed. -
Mention and alias resolution — Zalo
@mentionspans are wrapped for Telegram rendering, while Telegram usernames, plain-text names, and Zalo address-book aliases are resolved to stable Zalo UIDs. That reduces false mentions when display names differ from contact aliases.
zalo-tg vs Alternatives
| Tool | Best For | Key Differentiator | Pricing |
|---|---|---|---|
| zalo-tg | Zalo and Telegram bidirectional sync | Conversation-to-topic mapping, reply/reaction/poll fidelity, self-hosted state | Open-Source |
| n8n | General workflow automation | Visual orchestration for many services, but chat-state handling needs custom nodes | Freemium / Open-Source |
| Make | SaaS automation pipelines | Fast no-code integrations, but less control over protocol-specific edge cases | Freemium / Paid |
| Custom Telegraf + zca-js relay | Teams building a bespoke bridge | Full control, but you must implement persistence, mapping, and sync logic yourself | N/A |
Pick n8n when your main problem is broad automation across HTTP APIs and you do not need deep conversation state. Pick Make when your team wants a hosted builder and accepts SaaS pricing for convenience. Pick a custom Telegraf + zca-js relay when you need a one-off internal system and can absorb the engineering cost.
If your integration work is broader than chat bridges, browse all DevOps Automation tools. If you mostly want scriptable glue for deployments and bot ops, browse all CLI Tools tools.
How zalo-tg Works
zalo-tg uses a single long-running Node.js process with two transport layers: a Telegram bot built on Telegraf and a Zalo client built on zca-js. Telegram side traffic arrives through long polling on the Bot API, while Zalo side traffic arrives through an internal WebSocket connection. That design keeps the bridge event-driven and avoids polling both platforms with brittle cron jobs.
The key abstraction is the mapping store. store.ts maintains in-memory maps such as msgStore, sentMsgStore, pollStore, mediaGroupStore, zaloAlbumStore, userCache, aliasCache, friendsCache, and topicStore. data/topics.json persists topic mapping on disk, but message-ID links are intentionally ephemeral and use LRU-style eviction, so a restart degrades gracefully instead of corrupting state.
Here is the startup path most developers will use:
git clone https://github.com/williamcachamwri/zalo-tg
cd zalo-tg
npm install
cp .env.example .env
npm run dev
That sequence installs dependencies, creates local configuration, and starts the bridge in watch mode. After the process is live, you supply a Telegram bot token, point it at a forum-enabled supergroup, and authenticate Zalo through /loginweb or /loginapp so the bridge can begin translating events.
The architecture choices are practical, not academic. The project uses HTML parse mode for Zalo text rendering, buffers album messages to preserve media grouping, and calls ffmpeg only when the source format needs conversion for Telegram voice notes. That keeps the implementation close to platform-native behavior instead of forcing every payload into a lowest-common-denominator text format.
Pros and Cons of zalo-tg
Pros:
- True bidirectional sync between Zalo and Telegram instead of one-way forwarding.
- Forum topic isolation keeps each Zalo conversation in its own Telegram thread, which makes moderation and support workflows much easier.
- Media-aware translation handles photos, albums, videos, stickers, documents, voice, polls, locations, and contact cards with platform-specific APIs.
- Reply and reaction propagation preserves conversation context better than simple webhook relays.
- Self-hosted control means no vendor lock-in and no external SaaS dependency for core message flow.
- Multiple Zalo auth paths let operators switch between web and app login flows when one session method is more stable.
Cons:
- Requires Telegram supergroup forum mode and admin permissions, so it is not plug-and-play in a normal group.
- In-memory message mapping is fragile across restarts, which means old reply chains can degrade after process recovery.
- Depends on Zalo internal APIs, so upstream changes in Zalo behavior can break assumptions faster than a public, stable API would.
- Needs
ffmpegfor voice conversion, which adds one more runtime dependency and one more thing to package in deployment images. - Operational ownership is on you, because zalo-tg is a self-hosted bridge, not a managed integration service.
Getting Started with zalo-tg
git clone https://github.com/williamcachamwri/zalo-tg
cd zalo-tg
npm install
cp .env.example .env
npm run build
npm start
After the first run, edit .env with TG_TOKEN, TG_GROUP_ID, and an optional DATA_DIR if you want persistent files somewhere other than ./data. You also need to make the Telegram bot an admin in a forum-enabled supergroup, then authenticate the Zalo side through the bot command flow before message sync begins.
If you are testing locally, start with a single Telegram supergroup topic and one Zalo chat so you can verify topic mapping, mention resolution, and reply chaining before opening the bridge to more users. That avoids debugging multiple variables at once when a message does not appear where you expect.
Verdict
zalo-tg is the strongest option for teams that need a self-hosted Zalo–Telegram bridge when they must preserve message state, topics, and poll behavior without SaaS lock-in. Its best strength is protocol-aware synchronization; its biggest caveat is operational complexity and in-memory mapping loss on restart. Choose it if you value control over convenience.



