Looking for the chatbot template? It's now here.
Vercel

chat-adapter-zalo

Community adapter — This package is a community-maintained Zalo adapter for Chat SDK. It is not an official @chat-adapter/* package.

Zalo Bot adapter for Chat SDK, using the Zalo Bot Platform API.

Installation

bash
pnpm add chat-adapter-zalo chat @chat-adapter/shared

Usage

typescript
import { Chat } from "chat";import { createZaloAdapter } from "chat-adapter-zalo";const bot = new Chat({  userName: "mybot",  adapters: {    zalo: createZaloAdapter(),  },});bot.onNewMention(async (thread, message) => {  await thread.post(`You said: ${message.text}`);});

When using createZaloAdapter() without arguments, credentials are auto-detected from environment variables.

Zalo Bot setup

1. Create a Zalo Bot

  1. Go to bot.zapps.me and sign in with your Zalo account
  2. Create a new bot and note your Bot Token (format: 12345689:abc-xyz)
  3. Go to Webhooks settings and set your webhook URL

2. Configure webhooks

  1. In the Zalo Bot dashboard, navigate to Webhooks
  2. Set Webhook URL to https://your-domain.com/api/webhooks/zalo
  3. Set a Secret Token of your choice (8–256 characters) — this becomes ZALO_WEBHOOK_SECRET
  4. Subscribe to the message events you need (message.text.received, message.image.received, etc.)

3. Get credentials

From your Zalo Bot dashboard, copy:

  • Bot Token as ZALO_BOT_TOKEN
  • The Secret Token you set in the webhook config as ZALO_WEBHOOK_SECRET

Configuration

All options are auto-detected from environment variables when not provided.

OptionRequiredDescription
botTokenNo*Zalo bot token. Auto-detected from ZALO_BOT_TOKEN
webhookSecretNo*Secret token for webhook verification. Auto-detected from ZALO_WEBHOOK_SECRET
userNameNoBot display name. Auto-detected from ZALO_BOT_USERNAME (defaults to zalo-bot)
loggerNoLogger instance (defaults to ConsoleLogger("info"))

*Required at runtime — either via config or environment variable.

Environment variables

bash
ZALO_BOT_TOKEN=12345689:abc-xyz      # Bot token from Zalo Bot dashboardZALO_WEBHOOK_SECRET=your-secret      # Secret token for X-Bot-Api-Secret-Token verificationZALO_BOT_USERNAME=mybot              # Optional, defaults to "zalo-bot"

Webhook setup

typescript
// Next.js App Router exampleimport { bot } from "@/lib/bot";export async function POST(request: Request) {  return bot.webhooks.zalo(request);}

Zalo delivers all events via POST requests with an X-Bot-Api-Secret-Token header. The adapter verifies this header using timing-safe comparison before processing any payload.

Features

Messaging

FeatureSupported
Post messageYes
Edit messageNo (Zalo limitation)
Delete messageNo (Zalo limitation)
StreamingBuffered (accumulates then sends)
Auto-chunkingYes (splits at 2000 chars)

Conversations

FeatureSupported
ReactionsNo (Zalo limitation)
Typing indicatorYes (sendChatAction)
DMsYes
Group chatsPending
Open DMYes

Incoming message types

TypeSupported
TextYes
ImagesYes (with optional caption)
StickersYes (rendered as [Sticker])
Unsupported typesIgnored gracefully

Message history

FeatureSupported
Fetch messagesNo (Zalo API limitation)
Fetch thread infoYes

Thread ID format

zalo:{chatId}

Example: zalo:1234567890

The chatId is the conversation ID from the Zalo webhook payload. For group chats it is the group ID; for private chats it is the user ID.

Notes

  • Zalo does not expose message history APIs to bots. fetchMessages returns an empty array.
  • All formatting (bold, italic, code blocks) is stripped to plain text — Zalo renders no markdown.
  • The bot token is embedded in the API URL path and is never logged.
  • isDM() always returns true — Zalo thread IDs do not encode chat type.

Troubleshooting

Webhook verification failing

  • Confirm ZALO_WEBHOOK_SECRET matches the value you entered in the Zalo Bot dashboard
  • The adapter compares the X-Bot-Api-Secret-Token header using a timing-safe byte comparison — ensure the secret contains only ASCII characters and has no trailing whitespace

Messages not arriving

  • Verify your webhook URL is reachable and returns 200 OK
  • Check that the event types you need are subscribed in the Zalo Bot dashboard

"Zalo API error" on send

  • Confirm ZALO_BOT_TOKEN is correct — it should be in 12345689:abc-xyz format
  • The adapter calls getMe during initialize() to validate the token; check logs for initialization errors

License

MIT