Openzca
Free to use alternative zcacli for integrate Zalo with OpenClaw
Install / Use
/learn @darkamenosa/OpenzcaREADME
openzca
Free and open-source CLI for Zalo, built on zca-js. Command structure compatible with zca-cli.dev/docs.
Integrate with OpenClaw OpenZalo plugin (including legacy zalouser)
Install
npm install -g openzca@latest
Command aliases: openzca, zca.
Or run without installing:
npx openzca --help
Requires Node.js 22.13+.
The built-in DB backend now uses Node's official node:sqlite module, so no extra sqlite3 native addon is installed.
Quick start
# Login with QR code
openzca auth login
# Check your account
openzca me info
# Send a message
openzca msg send USER_ID "Hello"
# Send to a group
openzca msg send GROUP_ID "Hello team" --group
# Mention a group member by display name, username, or member id
openzca msg send GROUP_ID "Hi @Alice Nguyen" --group
openzca msg send GROUP_ID "Hi @123456789" --group
# Reply using a stored DB message id
openzca msg send USER_ID "Reply text" --reply-id MSG_ID
# Reply without DB using a listen --raw payload
openzca msg send USER_ID "Reply text" --reply-message '{"threadId":"...","msgId":"...","cliMsgId":"...","content":"...","msgType":"webchat","senderId":"...","toId":"...","ts":"..."}'
# Inspect how a formatted message expands before sending/chunking
openzca msg analyze-text GROUP_ID "- item one\n- item two" --group --json
# Listen for incoming messages
openzca listen
# Enable the local SQLite DB for this profile
openzca db enable
# Backfill full group history plus recent DM/chat windows into the DB
openzca db sync
# List stored groups
openzca db group list --json
# Show stored info for one group
openzca db group info GROUP_ID --json
# Read the last 24 hours for one group
openzca db group messages GROUP_ID --since 24h --json
# Read an explicit date range
openzca db group messages GROUP_ID --from 2026-03-21T00:00:00+07:00 --to 2026-03-22T00:00:00+07:00 --json
# Read the latest 20 stored rows by default
openzca db group messages GROUP_ID --json
# Read all matching rows
openzca db group messages GROUP_ID --all --json
Commands
auth — Authentication & cache
| Command | Description |
|---------|-------------|
| openzca auth login | Login with QR code (--qr-path <path> to save QR image, --qr-base64 for integration mode) |
| openzca auth login-cred [file] | Login using a credential JSON file |
| openzca auth logout | Remove saved credentials |
| openzca auth status | Show login status |
| openzca auth cache-refresh | Refresh friends/groups cache |
| openzca auth cache-info | Show cache metadata |
| openzca auth cache-clear | Clear local cache |
QR login renders inline in supported terminals (Ghostty, Kitty, WezTerm, iTerm2) with ASCII fallback for others.
If QR is not visible in your terminal, use openzca auth login --open-qr (macOS/Linux desktop) or set OPENZCA_QR_OPEN=1.
In non-interactive environments, openzca auto-opens the QR image by default (set OPENZCA_QR_AUTO_OPEN=0 to disable).
You can also open the saved file manually (for example: open qr.png on macOS).
msg — Messaging
| Command | Description |
|---------|-------------|
| openzca msg send <threadId> <message> | Send text with formatting (**bold**, *italic*, ~~strike~~, etc.), group @mention resolution (--raw to skip formatting), and quote replies via --reply-id or --reply-message |
| openzca msg analyze-text <threadId> <message> | Build and inspect the exact text payload msg send would hand to zca-js, including rendered text length, style count, mention count, textProperties size, and request size estimate |
| openzca msg image <threadId> [file] | Send image(s) from file or URL |
| openzca msg video <threadId> [file] | Send video(s) from file or URL; single .mp4 inputs try native video mode |
| openzca msg voice <threadId> [file] | Send voice message from local file or URL (.aac, .mp3, .m4a, .wav, .ogg) |
| openzca msg sticker <threadId> <stickerId> | Send a sticker |
| openzca msg link <threadId> <url> | Send a link |
| openzca msg card <threadId> <contactId> | Send a contact card |
| openzca msg react <msgId> <cliMsgId> <threadId> <reaction> | React to a message |
| openzca msg typing <threadId> | Send typing indicator |
| openzca msg forward <message> <targets...> | Forward text to multiple targets |
| openzca msg delete <msgId> <cliMsgId> <uidFrom> <threadId> | Delete a message |
| openzca msg edit <msgId> <cliMsgId> <threadId> <message> | Edit message (undo + resend shim) |
| openzca msg undo <msgId> <cliMsgId> <threadId> | Recall a sent message |
| openzca msg upload <arg1> [arg2] | Upload and send file(s) |
| openzca msg recent <threadId> | List recent messages (-n, --json, newest-first); defaults to live history, supports --source live|db|auto; group mode prefers direct group-history endpoint (websocket fallback) |
| openzca msg pin <threadId> | Pin a conversation |
| openzca msg unpin <threadId> | Unpin a conversation |
| openzca msg list-pins | List pinned conversations |
| openzca msg member-info <userId> | Get member/user profile info |
Media commands accept local files, file:// paths, and repeatable --url options. Add --group for group threads.
openzca msg video attempts native video send for a single .mp4 input by uploading the video and thumbnail to Zalo first. If ffmpeg is unavailable, the input is not a single .mp4, or native send fails, it falls back to the normal attachment send path. Use --thumbnail <path-or-url> to supply the preview image explicitly.
Local paths using ~ are expanded automatically (for positional file args, --url, and OPENZCA_LISTEN_MEDIA_DIR).
Group text sends via openzca msg send --group resolve unique @Name or @userId mentions against the current group member list using member ids, display names, and usernames. Mention offsets are computed after formatting markers are parsed, so messages like **@Alice Nguyen** hello work. If multiple members share the same label, the command fails instead of guessing.
When formatted text would produce an oversized outbound payload, openzca msg send automatically splits it into multiple sequential text messages using the final outbound text and rebased style/mention offsets. The split happens after formatting is parsed, using both rendered text length and estimated request payload size rather than the raw input string.
Use openzca msg analyze-text ... --json when you need to predict whether a formatted reply will expand into a large textProperties payload before attempting delivery.
Reply flows:
--reply-id <id>resolves a stored message from the local DB bymsgId,cliMsgId, or internal message uid. This requires DB persistence to be enabled for the profile.--reply-message <json>accepts either the originalmessage.dataobject fromzca-jsor the currentopenzca listen --rawpayload. Use this path when DB is disabled or when a caller already has the inbound payload in memory.- Use exactly one of
--reply-idor--reply-message.msg recentkeeps the previous live behavior by default. Use--source dbto read only from the local SQLite store, or--source autoto try DB first and fall back to live history.
Debug Logging
Use debug mode to write copyable logs for support/debugging:
# One-off debug run
openzca --debug msg image <threadId> ~/Desktop/screenshot.png
# Custom debug log path
openzca --debug --debug-file ~/Desktop/openzca-debug.log msg image <threadId> ~/Desktop/screenshot.png
# Or enable by environment
OPENZCA_DEBUG=1 openzca listen --raw
Default debug log file:
~/.openzca/logs/openzca-debug.log
Useful command to copy recent debug logs:
tail -n 200 ~/.openzca/logs/openzca-debug.log
For media debugging, grep these events in the debug log:
listen.media.detectedlisten.media.cache_error
group — Group management
| Command | Description |
|---------|-------------|
| openzca group list | List groups |
| openzca group info <groupId> | Get group details |
| openzca group members <groupId> | List members |
| openzca group create <name> <members...> | Create a group |
| openzca group poll create <groupId> | Create a poll (--question, repeatable --option, optional poll flags) |
| openzca group poll detail <pollId> | Get poll details |
| openzca group poll vote <pollId> | Vote on a poll with repeatable --option <id> |
| openzca group poll lock <pollId> | Close a poll |
| openzca group poll share <pollId> | Share a poll |
| openzca group rename <groupId> <name> | Rename group |
| openzca group avatar <groupId> <file> | Change group avatar |
| openzca group settings <groupId> | Update settings (--lock-name, --sign-admin, etc.) |
| openzca group add <groupId> <userIds...> | Add members |
| openzca group remove <groupId> <userIds...> | Remove members |
| openzca group add-deputy <groupId> <userId> | Promote to deputy |
| openzca group remove-deputy <groupId> <userId> | Demote deputy |
| openzca group transfer <groupId> <newOwnerId> | Transfer ownership |
| openzca group block <groupId> <userId> | Block a member |
| openzca group unblock <groupId> <userId> | Unblock a member |
| openzca group blocked <groupId> | List blocked members |
| openzca group enable-link <groupId> | Enable invite link |
| openzca group disable-link <groupId> | Disable invite link |
| openzca group link-detail <groupId> | Get invite link |
| openzca group join-link <linkId> | Join via invite link |
| openzca group pending <groupId> | List pending requests |
| openzca group review <groupId> <userId> <action> | Approve or deny join request |
| openzca group leave <groupId> | Leave group |
| openzca group disperse <groupId> | Disperse group |
Poll creation currently targets group threads only and maps to the existing zca-js group po
Related Skills
node-connect
347.9kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
108.7kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
347.9kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
347.9kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
