- Introduction
- What You’ll use to Build the WhatsApp Multilingual Chatbot
- How the WhatsApp Multilingual Chatbot Works: An Architecture Overview
- The Project Setup: WhatsApp Multilingual Chatbot with Python
- Setting Up the WhatsApp Business API
- Building the WhatsApp Multilingual Chatbot with Python: Writing the Code
- Language Detection Nuances
- Conversation Memory
- Testing Your WhatsApp Multilingual Chatbot
- Deploying the WhatsApp Multilingual Chatbot to Production
- Security Best Practices
- Additional Feature Ideas
- Quick Reference
- Common Errors & How to Fix Them
- 1. Webhook Verification Fails (403 Forbidden)
- 2. Messages Arrive but No Reply Is Sent
- 3. Claude API AuthenticationError (401)
- 4. ngrok Tunnel Expires or URL Changes
- 5. Bot Sends Duplicate Replies
- 6. Bot Always Responds in English
- 7. Port Already in Use on Startup
- 8. Claude Returns 529 ‘Overloaded’ Error
- Quick Reference: Error Lookup Table
- Conclusion
Introduction
Imagine messaging a WhatsApp multilingual chatbot in Swahili, Arabic, or French and getting an instant reply in the same language.
For companies serving global audiences, language barriers are one of the biggest obstacles to good customer support. Yet most chatbots still respond only in English.
WhatsApp has over 3.3 billion active users worldwide. A large portion of them do not primarily use English. From Swahili speakers in East Africa to Arabic speakers in the Middle East, global messaging is multilingual.
If you’re building a WhatsApp chatbot for a global audience, responding only in English means leaving most of your potential users behind. A bot that automatically detects what language someone is speaking and replies in kind feels like magic and with modern AI, it’s surprisingly straightforward to build.
In this tutorial, you’ll learn how to build a WhatsApp multilingual chatbot using Python and Claude AI. It is an easy to follow step-by-step guide to deploying an AI-powered bot that automatically detects and responds in any language.
What You’ll use to Build the WhatsApp Multilingual Chatbot
In this tutorial, you’ll build a production-ready WhatsApp multilingual chatbot using:
- Python + Flask for the webhook server
- Meta’s WhatsApp Business Cloud API for messaging
- Anthropic’s Claude AI for intelligent, multilingual responses
- In-memory conversation history so the bot remembers context
By the end, you’ll have a working bot you can deploy and share and a solid foundation to add more features. Some of the features will include:
- Detecting the user’s language automatically
- Replying naturally using Claude AI
- Remembering the conversation context
- Working inside WhatsApp in real time
- Supporting languages like English, Swahili, Arabic, French, Spanish, and more
You could even include a sample conversation:

Prerequisites
Before you start, make sure you have the following:
- Python 3.10 or higher installed
- A Meta Developer account (free) at developers.facebook.com
- An Anthropic API key from console.anthropic.com
- ngrok installed for local testing (ngrok.com/download)
- Basic Python and HTTP knowledge. We have a guide that can help you get started on how long it can take you to master Python.
You do not need a paid WhatsApp Business account to follow this tutorial. Meta provides a free test number with sandbox access that is more than enough for development.
How the WhatsApp Multilingual Chatbot Works: An Architecture Overview
Before writing any code, it helps to understand the complete flow. We have added a high-level flow that can help you visualise how the WhatsApp chatbot is structured:

Every time someone sends your bot a message, Meta sends an HTTP POST request to your server (the web hook). Your Flask app processes it, calls Claude AI with the message and some context, and sends the reply back through the WhatsApp API.
The key insight for multilingual support is the system prompt you give Claude. Rather than manually detecting languages with a library and routing to different handlers, you simply tell Claude: ‘Always detect the language of the user’s message and respond in that same language.‘ Claude handles the rest.
The Project Setup: WhatsApp Multilingual Chatbot with Python
Now that you understand the architecture, let’s start building the bot step by step.
1. Create the Project Structure
When creating the project structure, you must organize your files as follows to keep the app modular as shown below:

2. Install Dependencies
Create a virtual environment and install the required packages as shown below:

3. Set Up Environment Variables
Create a .env file at the root of your project. Always remember to never commit this file to GitHub as it contains your secret API keys. We don’t want anyone on the internet to me messing around with your secret keys.

You’ll find WHATSAPP_ACCESS_TOKEN and WHATSAPP_PHONE_NUMBER_ID in the Meta Developer Console under WhatsApp → API Setup. VERIFY_TOKEN is a string you choose yourself and it must match what you configure in the Meta Dashboard.
Setting Up the WhatsApp Business API
Step 1: Create a Meta App
To create a Meta app you will need to follow the steps outlined below:
- Go to https://developers.facebook.com and log in.
- Click Create App → Choose Business type → Name your app.
- On the dashboard, scroll to find the WhatsApp product and click Set Up.
Step 2: Get Your Credentials
Upon successful creation of the app in the WhatsApp section of your app, go to API Setup. You will see the following:
- A temporary access token (valid for 24 hours during development)
- A Phone Number ID for the test number Meta provides
- The test WhatsApp number you can message from your personal phone
For production, you will need a permanent system user token. However, for this tutorial the temporary token is fine.
Step 3: Configure the Webhook
Once you have your temporary access token, phone number ID and the test WhatsApp number you can message you will need to configure the webhook. A webhook is a lightweight, event-driven HTTP callback that allows one application to automatically push real-time data to another system when a specific event occurs. This webhook is where Meta sends messages to your server. You will need a public HTTPS URL. During development, you can use ngrok as shown below:

ngrok will give you a URL like https://abc123.ngrok.io. In the Meta Developer Console:
- Go to WhatsApp → Configuration → Webhook
- Set Callback URL to: https://abc123.ngrok.io/webhook
- Set Verify Token to match your VERIFY_TOKEN env variable
- Subscribe to the messages event
Building the WhatsApp Multilingual Chatbot with Python: Writing the Code
The Flask App Factory (main.py)
We will start with the Flask application factory. This pattern makes the app easier to test and deploy because it separates configuration from runtime.

The Webhook Routes (routes.py)
The webhook has two endpoints:
- GET for verification
- POST for receiving messages

WhatsApp API Helpers (whatsapp.py)
This module handles all communication with the Meta Graph API sending messages and parsing incoming payloads as shown below:

The Multilingual Brain (chatbot.py)
This is the heart of the application. We use a Python deque to store the last 10 exchanges (20 items) per user to maintain context without overflowing memory. Here is where language detection and reply generation happen as shown below:

Language Detection Nuances
While Claude handles multilingual responses gracefully, there are a few edge cases to be aware of:
Short Messages Are Ambiguous
A one-word message like ‘Hi’ or ‘Ok’ could be in any language. Our system prompt tells Claude to default to English in these cases, which is usually the safest fallback. However in a real product, you could track the last detected language per user and use that as a hint.
Code Switching
Many people naturally mix languages (e.g., Swahili and English, French and Wolof). Claude handles this gracefully if you send a mixed-language message, it typically replies in the dominant language or matches the pattern of the input.
Regional Variants
Claude is aware of regional variants like Brazilian Portuguese vs European Portuguese, or Mexican Spanish vs Castilian Spanish. If the user’s writing style suggests a regional variant, Claude tends to mirror it.
Sensitive Languages
Some languages, like Arabic and Hebrew, are right-to-left. WhatsApp handles the rendering on the user’s device automatically, so your bot just needs to return the correct Unicode text which Claude does.
Conversation Memory
The chatbot maintains per-user conversation history using Python’s deque with a maximum length as shown below:

This means that:
- Each user has their own independent conversation thread
- The bot remembers the last 10 message pairs (20 items = 10 exchanges)
- Memory resets when the server restarts (in-memory only)
For a production system, you would replace the in-memory store with Redis or a database. The interface is the same just swap the deque for a Redis list or a database table.

Testing Your WhatsApp Multilingual Chatbot
A thorough test strategy covers three layers: automated unit tests that run without any API calls, manual curl tests that simulate real WhatsApp payloads, and structured logging so you can see exactly what your bot receives and sends at every step.
Unit Tests with Pytest
We have the project available on our Github repo (https://github.com/RootedDreamsBlog/WhatsApp-Multilingual-Chatbot) which you can fork to get started. The project includes a full test suite. You can run tests with:

You should see output like this when all tests pass:

The tests cover webhook verification, message parsing, conversation memory, and the chatbot reply function (mocked to avoid real API calls). Claude API calls are mocked in tests so they run instantly without consuming API credits or needing a live connection.
Adding Structured Logging
Good logging is essential for a webhook app you cannot set a breakpoint when Meta sends you a live message. Add a logger at every key step in routes.py:

With this in place, every exchange produces clean, timestamped terminal output:

Manual Testing via curl
Simulate any incoming WhatsApp message without a real phone; great for testing specific languages or edge cases before going live:

The bot should detect French and reply in French. Run the same command with different message bodies to verify language detection. Here are example inputs and expected outputs:
| Language | You Send | Expected Reply Language |
| French | Bonjour, pouvez-vous m’aider ? | French |
| Spanish | Hola, puedes ayudarme con algo? | Spanish |
| Swahili | Habari, unaweza kunisaidia? | Swahili |
| Arabic | Hello in Arabic script | Arabic |
| Portuguese | Ola, pode me ajudar com uma pergunta? | Portuguese |
| English | Hi there, can you help me? | English |
| Shona | Mhoro, ungandibatsira here? | Shona |
Testing Conversation Memory
Send a sequence of curl requests from the same phone number to verify that the bot carries context across messages:

Health Check
The /health endpoint lets you instantly confirm your server is running useful in deployment pipelines and uptime monitors:

Deploying the WhatsApp Multilingual Chatbot to Production
Option A: Railway (Recommended for Beginners)
Railway is the fastest way to deploy a Python app with a public URL. To do so you can follow the steps outlined below:
- Push your code to GitHub
- Go to railway.app → New Project → Deploy from GitHub Repo
- Select your repository
- In the Variables tab, add all your .env variables
- Railway auto-detects the Procfile and deploys
Railway will give you a permanent public URL like https://whatsapp-bot-production.up.railway.app which you can use as your webhook URL in the Meta Developer Console (instead of the ngrok URL).
Option B: Render
Render is another excellent free-tier option. You can do so by following the steps below:
- Connect your GitHub repo at render.com
- Choose Web Service → Python environment
- Set Start Command to: gunicorn “app.main:create_app()” –bind 0.0.0.0:$PORT
- Add environment variables in the Render dashboard
Option C: AWS / GCP / Azure
For enterprise deployments, you must containerize the app with Docker and deploy to any cloud provider. The Procfile doubles as a Heroku-compatible deployment config, and the app is stateless by design.
Security Best Practices
When you move from development to a public-facing production bot, security is non-negotiable. WhatsApp bots handle real user conversations, and your webhook is publicly accessible on the internet. Here is what you need to lock down before going live.
1. Never Commit .env Files to GitHub
Your .env file contains secret API keys. A single accidental git push can expose your WhatsApp token and Anthropic key, allowing anyone to send messages as your bot or burn through your API credits.

2. Validate WhatsApp Webhook Signatures
Anyone who discovers your webhook URL can send fake POST requests to it injecting arbitrary messages into your bot. Meta signs every legitimate request with an HMAC-SHA256 signature using your App Secret. You should verify this signature before processing any payload.

Add WHATSAPP_APP_SECRET to your .env file. You find this value in Meta Developer Console → Your App → Settings → Basic → App Secret.
3. Always Use HTTPS
Meta’s webhook will only POST to HTTPS endpoints it will refuse plain HTTP. During development, ngrok provides HTTPS automatically. In production, Railway and Render provide HTTPS by default. If you’re deploying to a raw server (e.g. an EC2 instance), use Nginx with a free Let’s Encrypt certificate:

4. Rate-Limit Users
Without rate limiting, a single user (or a bot hammering your endpoint) can send thousands of messages per minute, exhausting your Anthropic API credits and potentially hitting WhatsApp’s own messaging limits. A simple per-user rate limiter using a dictionary of timestamps is enough for most use cases:

For production, use Redis with a sliding window algorithm instead of the in-memory dict this survives server restarts and works across multiple instances.
5. Store Secrets Securely in Production
A .env file works for local development, but in production your secrets should live in your hosting platform’s secret manager not in a file that could be accidentally exposed:

6. Input Validation
Although Claude handles arbitrary text gracefully, you should still validate and sanitize inputs at the webhook layer enforce a maximum message length to avoid unexpectedly large payloads, and skip processing messages that are clearly empty or whitespace-only:

Security Checklist
| Practice | Why It Matters | Status |
| .env in .gitignore | Prevents accidental key exposure on GitHub | Must have |
| Webhook signature verification | Blocks spoofed requests from bad actors | Must have |
| HTTPS only | Encrypts traffic; required by Meta | Must have |
| Per-user rate limiting | Prevents abuse and API credit exhaustion | Must have |
| Secrets in platform vault | Safer than file-based secrets in production | Recommended |
| Input length validation | Prevents oversized payloads from crashing app | Recommended |
| Rotate tokens regularly | Limits damage if a token is ever leaked | Recommended |
Additional Feature Ideas
Once your bot is running, here are some powerful extensions:
Voice Message Transcription
WhatsApp users frequently send voice notes. You can extend the bot to transcribe them using Whisper (OpenAI) or another STT service, then pass the transcribed text to Claude.
Image Understanding
Claude is multimodal. When a user sends an image, you can download it from the WhatsApp media API, base64-encode it, and pass it to Claude’s vision endpoint along with a prompt to describe or analyze it.
Persistent User Profiles
Store user preferences (preferred language, name, location) in a database so the bot personalizes responses across sessions.
Handover to Human Agent
Detect phrases like ‘speak to a human’ in any language and route the conversation to a live agent platform like Intercom or Freshdesk.
Rate Limiting
Add per-user rate limiting to prevent abuse. A simple Redis-based token bucket works well for this.
Quick Reference
Just to help you with a quick checklist of what you need to build your very first Python WhatsApp chatbot, the tables below outline the key files you need and the environment variables.
Key Files
| File | Purpose |
| app/main.py | Flask app factory which is the entry point |
| app/routes.py | Webhook GET (verify) and POST (receive message) |
| app/whatsapp.py | Send messages and parse incoming payloads |
| app/chatbot.py | Claude AI integration with conversation memory |
| .env | Secret API keys (never commit to GitHub) |
| Procfile | Tells Railway/Heroku how to start the app |
| tests/test_app.py | Full pytest test suite |
Environment Variables Reference
| Variable | Where to Get It | Required |
| WHATSAPP_ACCESS_TOKEN | Meta Developer Console → WhatsApp → API Setup | Yes |
| WHATSAPP_PHONE_NUMBER_ID | Meta Developer Console → WhatsApp → API Setup | Yes |
| VERIFY_TOKEN | Choose your own secure string | Yes |
| ANTHROPIC_API_KEY | console.anthropic.com → API Keys | Yes |
| PORT | Set to 5000 locally, auto-set by host in production | No |
Common Errors & How to Fix Them
This section covers the most frequent issues developers encounter when building and running this bot. Each error includes what it looks like, why it happens, and exactly how to fix it to help you resolve them should you encounter any of the errors.
1. Webhook Verification Fails (403 Forbidden)
What you see
Meta shows a red error after clicking ‘Verify and Save’ in the Developer Console, or your terminal logs a 403 response to the GET /webhook request.
Why it happens
Meta sends a GET request to your /webhook endpoint containing a hub.verify_token query parameter. Your app must return the hub.challenge value only if the token matches. A 403 almost always means the VERIFY_TOKEN in your .env doesn’t exactly match what you entered in the Meta Dashboard even a single extra space or different casing will break it.
How to fix it
- Open your .env file, copy the VERIFY_TOKEN value exactly (don’t retype it)
- In Meta Developer Console, go to WhatsApp → Configuration → Webhook and paste that exact value into the Verify Token field
- If running locally, confirm ngrok is active and the Callback URL in Meta matches your current ngrok tunnel

2. Messages Arrive but No Reply Is Sent
What you see
You message the bot, your server logs show the POST /webhook request arriving and returning 200, but the WhatsApp user receives nothing. No error is thrown in your Python app.
Why it happens
The most common causes are:
- Your WhatsApp access token has expired Meta’s development tokens expire every 24 hours;
- The WHATSAPP_PHONE_NUMBER_ID is wrong; or
- In the test environment, the recipient’s number has not been added to the list of allowed recipients.
How to fix it
- Refresh your access token: Meta Developer Console → WhatsApp → API Setup → copy the new token into .env
- Verify WHATSAPP_PHONE_NUMBER_ID it is a 15-digit number like 102391234567890, not your personal phone number
- In the Meta test sandbox, go to API Setup → ‘To’ field and add your personal WhatsApp number to the allowed recipients list

3. Claude API AuthenticationError (401)
What you see

Why it happens
The ANTHROPIC_API_KEY environment variable is missing, contains a typo, or load_dotenv() is being called after the Anthropic client is instantiated (so the client initializes with an empty key).
How to fix it
- Check that ANTHROPIC_API_KEY is present and correct in your .env file
- Make sure load_dotenv() is called at the very top of main.py, before importing app.routes (which imports chatbot.py, which creates the client)
- Verify the key is active at console.anthropic.com → API Keys

4. ngrok Tunnel Expires or URL Changes
What you see
The bot worked yesterday but today no messages come through. Your ngrok terminal shows a new URL starting with a different random subdomain, but Meta still has the old URL saved.
Why it happens
Free ngrok sessions expire after a few hours and generate a brand-new random URL every time you restart the tunnel. Meta’s webhook configuration still points to the old URL.
How to fix it
- Every time you restart ngrok, copy the new HTTPS URL and update it in Meta Developer Console → WhatsApp → Configuration → Webhook
- Sign up for a free ngrok account to get a stable subdomain that never changes
- Long-term: deploy to Railway or Render to get a permanent production URL (see Deploying to Production)

5. Bot Sends Duplicate Replies
What you see
A user sends one message and receives two or three identical replies from the bot. This happens intermittently and is worse on slow connections.
Why it happens
WhatsApp Cloud API uses an at-least-once delivery model. If your server doesn’t return a 200 OK within roughly 5 seconds, Meta retries the POST request. If your Claude API call takes longer than that which it can on first load or under load your handler processes the same message twice.
How to fix it
Return 200 immediately, then handle the message in a background thread. Also track processed message IDs to skip duplicates:

6. Bot Always Responds in English
What you see
You send a message in French, Swahili, or Spanish, but the bot replies in English every time. The language detection appears to be completely ignored.
Why it happens
Either the system prompt isn’t strong enough in its language instruction, the message is too short for confident detection (a single word like ‘Salut’ or ‘Hola’ is ambiguous), or the system prompt isn’t being passed correctly to the API call.
How to fix it
- Test with full sentences ‘Bonjour, j’ai une question sur mon compte’ is far easier to detect than ‘Salut’
- Strengthen the language instruction in your SYSTEM_PROMPT
- Add a console.log / print to verify the system prompt is being passed to client.messages.create
# Stronger system prompt; be very explicit:
SYSTEM_PROMPT = “””
You are a multilingual WhatsApp assistant.
ABSOLUTE RULE: You MUST detect the language of the user’s message
and respond ENTIRELY in that same language. No exceptions.
– User writes in French → respond in French
– User writes in Swahili → respond in Swahili
– User writes in Arabic → respond in Arabic
– User writes in Spanish → respond in Spanish
Only default to English if the message is a single character or
completely unrecognizable. Never mix languages in a single response.
“””
7. Port Already in Use on Startup
What you see

Why it happens
A previous Flask instance that wasn’t properly stopped is still holding port 5000. This commonly happens after pressing Ctrl+Z (which suspends instead of terminating) or after a crash.
How to fix it

8. Claude Returns 529 ‘Overloaded’ Error
What you see

Why it happens
The Anthropic API is experiencing unusually high traffic. This is a transient error that typically resolves within seconds to a few minutes. It is not caused by anything in your code.
How to fix it
Add exponential backoff retry logic so your bot gracefully retries rather than surfacing an error to the user:

Quick Reference: Error Lookup Table
| Symptom / Error Code | Most Likely Cause | First Thing to Check |
| 403 on webhook verify | VERIFY_TOKEN mismatch | Compare .env token vs Meta Dashboard |
| 200 OK but no reply sent | Expired token or wrong phone ID | Refresh token in Meta Console |
| 401 AuthenticationError | Missing or invalid ANTHROPIC_API_KEY | Check .env + load_dotenv() order |
| Meta error code 190 | WhatsApp access token expired | Regenerate in Meta API Setup |
| Duplicate replies to user | Server too slow → Meta retry | Return 200 immediately, process async |
| Bot always replies in English | Weak system prompt or short input | Strengthen language rule in SYSTEM_PROMPT |
| 529 Overloaded | Anthropic API high traffic (transient) | Add retry with exponential backoff |
| Address already in use | Old Flask process still on port 5000 | lsof -ti:5000 | xargs kill -9 |
Conclusion
You have now built a fully functional, production-ready WhatsApp chatbot that speaks your users’ language literally. In just a few hundred lines of Python, you have:
- A verified, secure webhook that Meta can send messages to
- Automatic language detection and multilingual responses via Claude AI
- Per-user conversation memory that maintains context across messages
- Clean error handling and a full test suite
- A deployment setup that works on Railway, Render, or any cloud provider
The multilingual capability is what makes this bot genuinely useful for global applications. Whether your users write to you in Swahili, Arabic, French, or Shona, they get a response that feels natural and local.
From here you can extend it with:
- Voice message transcription
- Image analysis
- Product search
- Customer support automation
With just a few additional integrations, this bot can become the backbone of a global messaging platform.
If you want the full code it is available on GitHub at https://github.com/RootedDreamsBlog/WhatsApp-Multilingual-Chatbot. If you have questions, open an issue or reach out directly. Happy building!



