Auto-replies to inbound WhatsApp messages from configurable FAQ rules — a self-serve chatbot for the questions customers ask most.
| Field | Value |
|---|---|
| Identifier | faq-bot |
| Version | 0.2.10 |
| Released | 2026-09-06 |
| Status | stable |
| Author | Yudhi Armyndharis |
| License | MIT |
| Type | extension |
| Requires OpenWA | ≥ 0.6.1 (tested 0.23.4) |
| Keywords | faq, auto-reply, chatbot, support, whatsapp, openwa |
| Repository | OpenWA-plugins/faq-bot |
- Per-rule matching — each rule is
contains,exact(both case-insensitive), orregex(compiled with theiflag). The first matching rule wins and its reply is sent. - Quoted replies — answers are sent as a reply to the triggering message.
- Optional fallback — a configurable reply when nothing matches (empty = stay silent), throttled per chat so a customer sending several unmatched messages isn't spammed.
- Direct-chat by default — group chats are ignored unless
respondInGroupsis enabled. - Least privilege — declares only
messages:send; it reads inbound messages and replies, nothing else. - Resilient config — an invalid
regexrule is skipped with a warning; a structurally invalidrulesconfig fails fast and shows asERRORin the dashboard.
rules is a JSON array; each entry is { "mode": "contains" | "exact" | "regex", "pattern": "...", "reply": "..." }:
[
{ "mode": "contains", "pattern": "harga", "reply": "Harga mulai Rp100.000. Ketik 'menu' untuk detail." },
{ "mode": "exact", "pattern": "menu", "reply": "1) Harga 2) Jam buka 3) Lokasi" },
{ "mode": "regex", "pattern": "^/start", "reply": "Selamat datang! Ada yang bisa kami bantu?" }
]- Have OpenWA ≥ 0.6.1 running with a logged-in WhatsApp session.
- Install and enable the plugin (see Install).
- Add your FAQ rules (see Configuration).
node package.mjs faq-bot # produces faq-bot.zip at the repo root
curl -X POST "https://your-openwa-host/api/plugins/install" \
-H "X-API-Key: <ADMIN_API_KEY>" -F "file=@faq-bot.zip"
curl -X PUT "https://your-openwa-host/api/plugins/faq-bot/config" \
-H "X-API-Key: <ADMIN_API_KEY>" -H "Content-Type: application/json" \
-d '{ "config": { "rules": "[{\"mode\":\"contains\",\"pattern\":\"harga\",\"reply\":\"Harga mulai 100rb\"}]" } }'
curl -X POST "https://your-openwa-host/api/plugins/faq-bot/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).
| Key | Required | Default | Description |
|---|---|---|---|
rules |
yes | — | JSON array of { mode, pattern, reply } rules |
fallbackReply |
no | "" |
Reply when no rule matches; empty = stay silent |
fallbackCooldownSec |
no | 600 |
Min seconds between fallback replies per chat; 0 = always |
respondInGroups |
no | false |
Whether to reply in group chats |
Targets OpenWA ≥ 0.6.1 (sandboxed plugin runtime). Live config edits (PUT …/config) apply
immediately on builds that forward onConfigChange to sandboxed plugins (the #430 follow-ups);
on v0.6.0/v0.6.1 a disable + re-enable is needed after changing rules.
Shared contact cards and polls never match a rule and never draw fallbackReply: from OpenWA 0.23.2
both carry text in the message body, and a vCard is free text that matches ordinary contains and
regex rules by accident. Tapped business buttons and list replies are still answered.
Supported. Every config field (rules, fallbackReply, fallbackCooldownSec,
respondInGroups) 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 FAQ
rule sets.
- WhatsApp
@lidmigration: the fallback cooldown is keyed by the chat id as received. If a contact migrates between a@lidprivacy id and a phone-based@c.usid, the old entry is orphaned and the new id is treated as a fresh chat (the cooldown simply resets — harmless). A proper fix needs a host-side lid↔phone resolver; tracked upstream.
Two controls, each covering what the other cannot.
The input cap. A regex rule is tested against at most the first 150 characters of a message.
Backtracking cost grows with the input, so capping it sets the ceiling directly, whatever the pattern
looks like. contains and exact cannot backtrack and are not capped, so they still see the whole
message: use contains when you need "mentions X anywhere in a long message".
The parse-time screen. Every pattern is checked for catastrophic-backtracking shapes: nested,
adjacent-overlapping, and repeated-variable-width quantifiers (e.g. (a+)+, .*.*.*, (a?){40}), plus
ambiguous repeated alternations ((a|a)*, (a|ab)+, ^([a-z]|[a-z0-9])+$, ^(\w|\d)+$). An unsafe
pattern is skipped with a warning.
The split matters because the two failure modes are not alike. Exponential shapes stay fatal at any input length, so only the screen can stop them, and they are the ones it recognises reliably. Polynomial shapes are the opposite: hard to see in the pattern text, but bounded by the cap. The host aborts a hook at 5 s and cannot interrupt a regex already running, so the ceiling has to hold on a slow host too.
An alternation is only rejected when two branches can consume the same text AND the repetition lands
directly on it, including through a group that adds nothing but parentheses (((a|a))+). A wrapper that
also contributes a mandatory atom is not that shape: the atom realigns every iteration, so ordinary
keyword sets like (one|two|three)+, ^(ya|tidak)$ and ^((no|nope) )+$ are unaffected even where two
branches share a first letter.
The screen is a heuristic rather than a decision procedure, and it is known to accept some polynomial
shapes: (a|b)*(a|b)*(a|b)*$ and [ab]*[bc]*[cd]*$ pass it. Those are safe because of the cap, not
because the screen understood them. Measured on the worst of them against alternating input, 1000
characters runs past 8 s while 150 takes 362 ms.
The same inbound text is answered at most once every 10 seconds per chat. A rule whose reply also matches its own pattern is a fixed point, and an autoresponder on the other end would otherwise trade messages with it indefinitely, repeating one canned line as it goes. The throttle keys on that repeated text rather than on the rule, so two different questions are both answered even when they match the same rule.
See CHANGELOG.md.
MIT © Yudhi Armyndharis & OpenWA Contributors.