docs/channels/zalouser.md
Status: experimental. This integration automates a personal Zalo account via native zca-js, in-process, with no external CLI binary.
Zalo Personal is an official external plugin, not bundled in core. Install it before use:
openclaw plugins install @openclaw/zalouser
openclaw plugins install @openclaw/zalouser@<version>openclaw plugins install ./path/to/local/zalouser-pluginopenclaw channels login --channel zalouser{
channels: {
zalouser: {
enabled: true,
dmPolicy: "pairing",
},
},
}
zca-js library (no external zca/openzca binary).message, error) to receive inbound messages.Channel id is zalouser to make it explicit this automates a personal Zalo user account (unofficial). zalo is reserved for a potential future official Zalo API integration.
openclaw directory self --channel zalouser
openclaw directory peers list --channel zalouser --query "name"
openclaw directory groups list --channel zalouser --query "work"
channels.zalouser.dmPolicy: pairing | allowlist | open | disabled (default: pairing).
channels.zalouser.allowFrom should use stable Zalo user IDs. It can also reference static sender access groups (accessGroup:<name>). During interactive setup, entered names can be resolved to IDs using the plugin's in-process contact lookup.
If a raw name remains in config, startup resolves it only when channels.zalouser.dangerouslyAllowNameMatching: true is enabled. Without that opt-in, runtime sender checks are ID-only and raw names are ignored for authorization.
Approve via:
openclaw pairing list zalouseropenclaw pairing approve zalouser <code>channels.zalouser.groupPolicy = "allowlist" (groups require an explicit allowlist entry).channels.zalouser.groupPolicy = "open".channels.zalouser.groupPolicy = "disabled".groupPolicy = "allowlist":
channels.zalouser.groups keys should be stable group IDs; names resolve to IDs on startup only when channels.zalouser.dangerouslyAllowNameMatching: true is enabled.channels.zalouser.groupAllowFrom controls which senders in allowed groups can trigger the bot; static sender access groups can be referenced with accessGroup:<name>.channels.zalouser.dangerouslyAllowNameMatching: true is enabled.channels.zalouser.dangerouslyAllowNameMatching: true is a break-glass compatibility mode that re-enables mutable startup name resolution and runtime group-name matching.groupAllowFrom does not fall back to allowFrom for normal group messages: leaving it empty on an allowlisted group opens that group to any sender. Authorized control commands (for example /new) are the exception; command sender checks fall back to allowFrom when groupAllowFrom is empty.Example:
{
channels: {
zalouser: {
groupPolicy: "allowlist",
groupAllowFrom: ["1471383327500481391"],
groups: {
"123456789": { enabled: true },
"Work Chat": { enabled: true },
},
},
},
}
channels.zalouser.groups.<group>.requireMention controls whether group replies require a mention.group:<id> alias -> group name/slug (name-based candidates only apply when dangerouslyAllowNameMatching: true) -> * -> default (true)./new) can bypass mention gating.channels.zalouser.historyLimit, then messages.groupChat.historyLimit, then a fallback of 50.Example:
{
channels: {
zalouser: {
groupPolicy: "allowlist",
groups: {
"*": { enabled: true, requireMention: true },
"Work Chat": { enabled: true, requireMention: false },
},
},
},
}
Accounts map to zalouser profiles in OpenClaw state. Example:
{
channels: {
zalouser: {
enabled: true,
defaultAccount: "default",
accounts: {
work: { enabled: true, profile: "work" },
},
},
},
}
Profile selection can also come from environment variables:
| Var | Purpose |
|---|---|
ZALOUSER_PROFILE | Profile name to use when no profile is set in channel or account config. |
ZCA_PROFILE | Legacy fallback, used only when ZALOUSER_PROFILE is not set. |
Profile names select the saved Zalo login credentials in OpenClaw state. Resolution order:
profile in config.ZALOUSER_PROFILE.ZCA_PROFILE.default for the default account.For multi-account setups, prefer setting profile on each account in config so one environment variable does not make multiple accounts share the same login session.
react is supported for zalouser in channel actions.
remove: true to remove a specific reaction emoji from a message.Login doesn't stick:
openclaw channels status --probeopenclaw channels logout --channel zalouser && openclaw channels login --channel zalouserAllowlist/group name didn't resolve:
allowFrom/groupAllowFrom and stable group IDs in groups. If you intentionally need exact friend/group names, enable channels.zalouser.dangerouslyAllowNameMatching: true.Upgraded from an old external zca/CLI-based setup:
zca process assumptions; the channel now runs fully in-process via zca-js, with no external CLI binary.