An interactive, stateful auto-reply: a trigger word opens a greeting + numbered menu, replies walk a configurable menu tree, and each conversation remembers where it is — a self-serve menu bot for WhatsApp.
| Field | Value |
|---|---|
| Identifier | chat-flow |
| Version | 1.1.6 |
| Released | 2026-08-20 |
| Status | stable |
| Author | Yudhi Armyndharis |
| License | MIT |
| Type | extension |
| Requires OpenWA | ≥ 0.7.0 (tested 0.23.0) |
| Keywords | menu, flow, interactive, auto-reply, chatbot, whatsapp, openwa |
| Repository | OpenWA-plugins/chat-flow |
- Interactive menu tree — a trigger word (or any message) sends a greeting + numbered menu; the user's reply selects an option; selections traverse a menu tree of arbitrary depth. Leaf nodes end the flow.
- Stateful per conversation — each
(session, chat)remembers its position; state expires after 15 minutes of inactivity, and re-sending the trigger word restarts an active flow. - Visual flow editor — design the whole tree (add / remove / nest options) in a built-in editor
(
configUi), no JSON by hand required. - Per-session config — the flow is the resolved per-session
ctx.config; the platform owns which numbers it runs for. Edits apply live viaonConfigChange. - Safe under config drift — if the saved config changes while a user is mid-flow, the stale path is reset with bounded re-processing (never an unbounded loop).
- Least privilege — declares
messages:sendandstorage:use(flow position only); direct chats only unlessrespondInGroupsis on. No network access at all.
The flow is { trigger, greeting, respondInGroups, options }. trigger is the word that starts the flow
(case-insensitive; empty = start on any message). options is a tree — each node has a key (what the
user types, e.g. "1"), the reply text, and optional nested options (a submenu; omit for a leaf):
{
"trigger": "menu",
"greeting": "Hi! Reply with a number:\n1. Pricing\n2. Support",
"respondInGroups": false,
"options": [
{ "key": "1", "text": "Plans start at Rp100.000/mo. https://example.com/pricing" },
{ "key": "2", "text": "Support — reply with a number:\n1. Billing\n2. Technical",
"options": [
{ "key": "1", "text": "Billing: billing@example.com" },
{ "key": "2", "text": "A ticket has been created — we'll reply shortly." }
] }
]
}Editing the tree by hand is optional — the plugin ships a visual flow editor the dashboard opens in a sandboxed frame. A reply that doesn't match any option re-sends the current menu.
- Have OpenWA ≥ 0.7.0 running with a logged-in WhatsApp session.
- Install and enable the plugin (see Install).
- Design your menu tree — via the built-in visual editor or the JSON config (see Configuration).
node package.mjs chat-flow # produces chat-flow.zip at the repo root
curl -X POST "https://your-openwa-host/api/plugins/install" \
-H "X-API-Key: <ADMIN_API_KEY>" -F "file=@chat-flow.zip"
curl -X PUT "https://your-openwa-host/api/plugins/chat-flow/config" \
-H "X-API-Key: <ADMIN_API_KEY>" -H "Content-Type: application/json" \
-d '{ "config": { "trigger": "menu", "greeting": "Hi! 1. Pricing 2. Support",
"options": [ { "key": "1", "text": "Plans start at Rp100.000" },
{ "key": "2", "text": "Email support@example.com" } ] } }'
curl -X POST "https://your-openwa-host/api/plugins/chat-flow/enable" \
-H "X-API-Key: <ADMIN_API_KEY>"Or download the packaged .zip from Releases
and upload it in the dashboard Plugins → Install (or the Catalog tab), then design the tree in the
plugin's Flow editor.
| Key | Required | Default | Description |
|---|---|---|---|
greeting |
yes | — | The greeting + menu sent when the flow starts |
options |
yes | — | The menu tree: array of { key, text, options? } nodes (nests arbitrarily) |
trigger |
no | "" |
Word that starts the flow (case-insensitive); empty = any message with text starts it — a sticker, voice note or caption-less image never does |
respondInGroups |
no | false |
Whether to run in group chats (each participant walks their own flow) |
Targets OpenWA ≥ 0.7.0 — relies on per-session config resolution (sessionScoped), live
onConfigChange, and the configUi sandboxed config editor. Uses only ctx.messages.reply,
ctx.storage, ctx.logger, and ctx.config.
Supported. Every config field (trigger, greeting, respondInGroups, the options tree) may
be overridden per WhatsApp session via the dashboard; an override takes effect on the next inbound
message (config is re-read per event). For example, two sessions can run different menu trees. Flow
state is keyed per (session, chat) in storage, so flows for sessions with different menus never
interfere.
- WhatsApp
@lidmigration: flow state is keyed by the chat id as received. If a contact migrates between a@lidprivacy id and a phone-based@c.usid mid-flow, the in-progress menu state is orphaned and the contact restarts from the greeting on the new id. A proper fix needs a host-side lid↔phone resolver; tracked upstream.
Flow state lives in ctx.storage, keyed per (session, chat) and expiring after 15 minutes — no
cross-chat leakage. The plugin makes no outbound network calls and declares only messages:send and
storage:use — the latter covering that flow state, which holds a menu path and a timestamp, never
message content. A stale stored path (after a config edit) is reset with bounded re-processing, so a
hostile or looping config can never cause unbounded recursion.
See CHANGELOG.md.
MIT © Yudhi Armyndharis & OpenWA Contributors.