3 WhatsApp + n8n Workflow Varieties — Ready to Import and Run
The One Template, Three Jobs
Every workflow in this post starts from the same webhook trigger. OpenWA receives a WhatsApp message, forwards it to n8n, and the IF nodes decide what happens next.
The three branches handle completely different scenarios:
1. A specific person gets a private AI assistant
2. Anyone in a group can summon the AI with @agent
3. Multiple keywords route to multiple handlers
All three share the same base stack: OpenWA as the WhatsApp gateway, Ollama running llama3.2:3b locally for AI, a 30-message memory buffer so the conversation doesn't reset every reply, and n8n's HTTP Request node sending the AI's response back through OpenWA.
The Stack That Powers All Three
OpenWA runs at http://openwa-api:2785 inside your Docker network. This is not localhost:2785 — if you're debugging why n8n can't reach OpenWA, the hostname is almost always the problem.
Ollama serves llama3.2:3b at http://localhost:11434 on your machine. No API key, no data leaving your server, no cost per message.
Simple Memory stores the last 30 messages per session. The session key is the WhatsApp chatId — so personal chats and group chats have separate memory automatically.
Variety 1: The Personal AI Chat Bot
Use when: One person — you, a cofounder, a specific client — gets a private WhatsApp AI assistant that remembers your conversation.
The IF node fires when body.data.contact.pushName equals the name you've configured. Everyone else is silently ignored.
The three mistakes I made the first time:
Wrong pushName. WhatsApp has two names per contact — the display name in your phone's contact list, and pushName which comes from the sender's WhatsApp profile. I configured my cofounder's contact name in my phone. The IF never fired. Check the webhook payload to find the actual pushName value.
Same memory for everyone. The template uses body.data.chatId as the session key. If you want the AI to remember conversations with multiple people separately, you're already covered — each person has a different chatId.
No system prompt customization. The default "You are a helpful assistant" produces generic, forgettable responses. The first thing I changed: "You are a product photography assistant. When asked about lighting or gear, recommend specific setups with approximate budget ranges." The bot went from useless to actually useful overnight.
Variety 2: The Group @agent Bot
Use when: You want to drop an AI bot into a WhatsApp group and let anyone in the group ask it questions — but not have it reply to every single message and create chaos.
The IF node fires when body.data.isGroup == true AND the message body contains "@agent". Everything else passes through silently.
"@agent" is your activation token. Someone types "@agent what's the status of my order?" and the bot responds. They type "thanks" and nothing happens. No loop, no spam, no annoyance.
The three mistakes I made:
Responding in every group. Without the "@agent" filter, the bot fires on every group message — including its own previous responses. You get an infinite loop within three messages.
Boring group prompts. Groups are noisy — multiple people are reading. I changed the system prompt to: "Keep responses short. Direct answers without preamble. Format lists with numbers. If you're unsure, say so briefly." Engagement went up immediately.
30-message memory in a busy group. In an active group, that's 30 messages from 15 different people with significant gaps between them. The AI was getting confused mid-conversation. I dropped the buffer to 10 messages. Context improved noticeably.
Variety 3: The Keyword Router
Use when: One group, multiple functions. You want @order to trigger an order-status handler, @help to trigger a help workflow, and @status to trigger something else — all from the same group, all from the same bot.
The pattern replaces the single Simple Agent with a chain of IF nodes or a Switch node, each checking for a different keyword.
Two gotchas I hit:
Keyword collision. If someone types "@orders" and your keyword is "@order", most routing logic won't match. Use distinct keywords. A good pattern: use the "@agent" prefix as a namespace. "@agent order", "@agent status", "@agent help" — clean separation between bot commands and regular chat.
The fallback branch. Without a fallback, unmatched messages go nowhere — no response, no feedback. Add a default branch that tells the user which keywords are valid.
Prerequisites (Same for All Three)
1. OpenWA running and accessible from n8n's Docker network — see OpenWA Docker Setup
2. n8n credential for OpenWA set up — see Connecting n8n to OpenWA
3. The n8n webhook registered in OpenWA — in the OpenWA dashboard → Webhooks → Add Webhook. URL: https://n8n.yourdomain.com/webhook/wa-webhook. Event: message.received
4. Ollama running locally with llama3.2:3b pulled:
curl -fsSL https://ollama.ai/install.sh | sh
ollama pull llama3.2:3b
5. The Ollama credential in n8n. Base URL: http://localhost:11434. No API key required.
The Workflow JSON
Copy the JSON below, then in n8n: Workflows → three dots menu → Import from JSON → paste → import.
This is the combined template with all three IF branches. Delete the branches you don't need, or leave them all active.
{
"name": "WhatsApp AI Bot — 3 Varieties",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "wa-webhook",
"options": {}
},
"id": "321adc8a-c16f-4b60-baa3-3c51d7f748d6",
"name": "WA Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [112, 544],
"webhookId": "49cae27c-b557-4d0c-a7ab-101a3d83c8ac"
},
{
"parameters": {
"method": "POST",
"url": "=http://openwa-api:2785/api/sessions/{{ $('WA Webhook').item.json.body.sessionId }}/messages/send-text",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [{ "name": "Content-Type", "value": "=application/json" }]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{ "name": "chatId", "value": "={{ $json.chatId }}" },
{ "name": "text", "value": "={{ $json.output }}" }
]
},
"options": {}
},
"id": "52d1f993-69fb-461b-abf6-e683c288e505",
"name": "Send WhatsApp Message",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [1632, 544],
"credentials": { "httpHeaderAuth": { "id": "REPLACE_ME", "name": "OpenWA API Key" } }
},
{
"parameters": { "model": "llama3.2:3b", "options": {} },
"type": "@n8n/n8n-nodes-langchain.lmChatOllama",
"typeVersion": 1,
"position": [1008, 784],
"id": "f731fc8d-6965-45a3-82bc-0ffe634a1173",
"name": "Ollama Chat Model",
"credentials": { "ollamaApi": { "id": "REPLACE_ME", "name": "Ollama account" } }
},
{
"parameters": {
"sessionIdType": "customKey",
"sessionKey": "={{ $json.body.data.chatId }}",
"contextWindowLength": 30
},
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"typeVersion": 1.4,
"position": [1184, 816],
"id": "d29aeafc-0398-477c-9757-e0cb25799ac4",
"name": "Simple Memory"
},
{
"parameters": {
"conditions": {
"options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 },
"conditions": [{
"id": "6c1bd14c-82d9-4e84-9710-f7cff64ff5e7",
"leftValue": "={{ $json.body.data.contact.pushName }}",
"rightValue": "YourContactName",
"operator": { "type": "string", "operation": "equals" }
}],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [544, 288],
"id": "5d673758-ca77-4362-88b8-4f1c7c657332",
"name": "Variety 1: Personal Contact"
},
{
"parameters": {
"conditions": {
"options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 },
"conditions": [{
"id": "447c3290-2b09-4bd5-9a20-87373df3dc3d",
"leftValue": "={{ $json.body.data.isGroup }}",
"rightValue": true,
"operator": { "type": "boolean", "operation": "equals" }
}],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [560, 512],
"id": "360ee92f-467a-4feb-85c5-7688834a3b1b",
"name": "Variety 2: Group Message"
},
{
"parameters": {
"conditions": {
"options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict", "version": 3 },
"conditions": [
{
"id": "424bfcff-ef4a-4911-bdea-44eb2c4cc52e",
"leftValue": "={{ $json.body.data.isGroup }}",
"rightValue": true,
"operator": { "type": "boolean", "operation": "equals" }
},
{
"id": "f60b4be0-1c7b-4ecd-bf65-2b3124897963",
"leftValue": "={{ $json.body.data.body }}",
"rightValue": "@agent",
"operator": { "type": "string", "operation": "contains" }
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [560, 736],
"id": "b9545930-1ec0-435b-8d9a-3c757ac35f17",
"name": "Variety 3: @agent Mention"
},
{
"parameters": {
"assignments": {
"assignments": [
{ "id": "be20df00-04bc-46aa-8f26-462af1db0dcb", "name": "output", "value": "={{ $json.output }}", "type": "string" },
{ "id": "c58843cc-e1ec-4803-97c0-b3dc97557d32", "name": "chatId", "value": "={{ $('WA Webhook').item.json.body.data.chatId }}", "type": "string" }
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [1424, 544],
"id": "f021c824-6573-4ecb-a2ee-cc6c4c8cdd01",
"name": "Set Message and ID"
},
{
"parameters": {
"promptType": "define",
"text": "={{ $json.body.data.body }}",
"options": { "systemMessage": "You are a helpful assistant." }
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 3.1,
"position": [1072, 512],
"id": "19742472-9a7b-4e65-8cff-a43a37065a4b",
"name": "Simple Agent"
}
],
"pinData": {},
"connections": {
"WA Webhook": {
"main": [[
{ "node": "Variety 1: Personal Contact", "type": "main", "index": 0 },
{ "node": "Variety 2: Group Message", "type": "main", "index": 0 },
{ "node": "Variety 3: @agent Mention", "type": "main", "index": 0 }
]]
},
"Ollama Chat Model": { "ai_languageModel": [[{ "node": "Simple Agent", "type": "ai_languageModel", "index": 0 }]] },
"Simple Memory": { "ai_memory": [[{ "node": "Simple Agent", "type": "ai_memory", "index": 0 }]] },
"Variety 3: @agent Mention": { "main": [[{ "node": "Simple Agent", "type": "main", "index": 0 }]] },
"Set Message and ID": { "main": [[{ "node": "Send WhatsApp Message", "type": "main", "index": 0 }]] },
"Simple Agent": { "main": [[{ "node": "Set Message and ID", "type": "main", "index": 0 }]] }
},
"active": false,
"settings": { "executionOrder": "v1" }
}
After importing, you must re-select credentials: open the Send WhatsApp Message node → Authentication → re-select your OpenWA API Key credential. Open the Ollama Chat Model node → re-select your Ollama credential. Credentials are stored by ID and won't resolve in a different n8n instance.
For Variety 1: change YourContactName in the "Variety 1: Personal Contact" IF node to the actual pushName from your webhook payload.
Importing and Activating
1. Copy the JSON above
2. In n8n → Workflows → three dots menu → Import from JSON
3. Paste and import
4. Re-select credentials in every node that has a key icon
5. Activate the workflow
The import step trips up everyone the first time. The workflow loads, you test it, and it fails silently. It's almost always a credential mismatch. Check every node with a key icon.
The Real Constraint
The stack is not the hard part. Ollama, OpenWA, n8n, the webhook, the memory buffer — these are solved problems with documented solutions. The hard part is deciding what you actually want to automate.
A bot that answers questions is fun for a week. A bot that maintains your team's shared calendar, tracks orders, and escalates failures to Telegram — that takes planning. The workflow varieties in this post are the building blocks. The specific system prompt, the data sources you connect, and the feedback loop when the AI gets something wrong — that's where the real work is.
The good news: you only need one variety to start. Pick the simplest one that matches your actual use case. Ship it. Let people use it. Fix what breaks. That's the only process that actually works.
Series: ← Connecting n8n to OpenWA | ← Back to overview
Related Posts
Built something similar or want to talk through the architecture? Get in touch.