Skip to content
All projects
Agentic AI2025 · Design, build, deploy — solo

AI Chatbot for Small Businesses

A WhatsApp customer-service agent that answers in real time — running on a self-hosted model, so the business owns its data and pays nothing per message.

Channel
WhatsApp Business API
Inference
Self-hosted Ollama
Orchestration
n8n workflow

Overview

Small businesses lose customers in the gap between a message arriving and someone being free to answer it. This project closes that gap: a fully automated WhatsApp chatbot, built on n8n and the Meta WhatsApp Business API, powered by a self-hosted Ollama model that generates real-time customer responses.

Problem

A local business gets the same fifteen questions all day — hours, pricing, availability, location — usually outside working hours. Hiring for it doesn’t scale, and the obvious fix, a hosted LLM behind a chat widget, has two problems: customers don’t use widgets, they use WhatsApp; and per-token pricing on a high-volume, low-value conversation makes the economics worse than the problem.

Solution

Meet customers on the channel they already have open, and move inference in-house. Meta’s WhatsApp Business API delivers each inbound message to an n8n webhook. n8n is the orchestrator: it normalises the payload, keeps per-sender conversation context, builds the prompt, and calls a locally-hosted Ollama model. The generated reply goes back out through the WhatsApp send endpoint. Because the model runs on the business’s own machine, marginal cost per conversation is effectively zero and no customer message leaves their infrastructure.

Architecture

One inbound path, one outbound path, and a stateful orchestration layer in the middle. Deliberately boring — the interesting part is that it never needs a hosted model.

  1. Layer 01

    Channel

    • WhatsApp Business Cloud API

      Verified number, webhook subscription

    • Meta webhook

      Inbound message events

  2. Layer 02

    Orchestration

    • n8n webhook trigger

      Signature verification

    • Normalise & route

      Text / media / unsupported

    • Conversation context

      Keyed per sender

    • Prompt assembly

      System persona + business facts

  3. Layer 03

    Inference

    • Ollama

      Self-hosted, local network

    • Response post-processing

      Length + tone guardrails

  4. Layer 04

    Delivery

    • WhatsApp send message

      Typing indicator, then reply

    • Fallback to human

      Unrecognised intent escalates

Tech Stack

n8nMeta WhatsApp Business APIOllamaSelf-hosted LLMWebhooksDocker

Screenshots

Screenshot slot 1

Screenshot slot 2

Interface captures for AI Chatbot for Small Businesses aren’t published here yet — the architecture and decisions above are the substance. Available on request, or in the repository.

Challenges

  • 01

    Webhook verification and Meta’s approval path

    The WhatsApp Business API is not a drop-in integration. Getting to the first delivered message meant number verification, a permanent access token, HTTPS webhook validation with the challenge handshake, and matching Meta’s exact payload shape — which nests differently for text, media, and status events.

  • 02

    A stateless workflow engine holding a conversation

    n8n executions are independent by design, but a chatbot that forgets the previous message is useless. I keyed conversation history per sender in external storage and rehydrated it at the start of every execution, with a window cap so the prompt didn’t grow without bound.

  • 03

    Latency budget on local hardware

    A self-hosted model is cheap but not fast by default. On WhatsApp, silence reads as broken. I kept the model warm rather than cold-loading per request, trimmed the context window to what actually improved answers, and sent a typing indicator immediately so the wait was legible to the customer.

  • 04

    Keeping a small model on-topic

    Left alone, the model happily answered questions that had nothing to do with the business. Constraining it took a tight system persona, the business’s real facts injected into every prompt, and an explicit escalation path — if the intent isn’t recognised, hand off to a human instead of inventing an answer.

Lessons Learned

  • 01

    Channel choice is a product decision, not a technical one. The same bot in a website widget would have gone unused.

  • 02

    Self-hosting an LLM changes what you’re allowed to build — when marginal cost is zero, high-volume low-value conversations become worth automating.

  • 03

    Guardrails aren’t a prompt suffix. Refusal and escalation paths need to be designed as first-class branches of the workflow.

  • 04

    Perceived latency is a feature. A typing indicator bought more goodwill than a faster model would have.

Want the deeper version of this?

I’m happy to walk through the code, the trade-offs, or the parts that didn’t make the write-up.