WhatsApp Bot With Python: Build a Working Bot Step by Step
By Erfan Ahmed, founder of Erfan MD · Updated October 2026
You can build a WhatsApp bot in Python with about 60 lines of code. This guide shows how to make a Python WhatsApp bot with Flask and the official WhatsApp Business Cloud API, how Twilio offers a shortcut, why the popular browser-automation libraries are risky, and how to test, secure and host your bot. It is written for beginners who know basic Python and for developers who want a clean starting structure.
Three Ways to Build a Python WhatsApp Bot
| Approach | How it works | Good for | Main catch |
|---|---|---|---|
| Cloud API + Flask or FastAPI | Meta calls your webhook; you reply through the Graph API | Real businesses and production bots | Needs a Meta developer setup |
| Twilio for WhatsApp | Twilio receives messages and forwards them to your code | Quick tests, simple replies | Twilio fees on top of Meta's |
| Browser automation (such as pywhatkit or Selenium) | Controls WhatsApp Web in a browser | Personal experiments only | Fragile, against WhatsApp's terms, ban risk |
For anything customers rely on, use the Cloud API or a provider built on it. The rest of this guide focuses on that route.
What You Need Before You Start
- Python 3.9 or newer and
pip. - A Meta developer account with an app that has the WhatsApp product added. Meta gives you a test number, a phone number ID and a temporary access token.
- A public HTTPS URL for the webhook. During development, a tunneling tool such as ngrok can expose your local server.
- Your phone added as a test recipient in the Meta dashboard.
If you have not set up the Meta side yet, our guide to creating a WhatsApp bot walks through it.
Project Setup
mkdir wa-python-bot && cd wa-python-bot
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install flask requests python-dotenv gunicornCreate a .env file for your secrets and never commit it:
VERIFY_TOKEN=choose-a-long-random-string
WA_TOKEN=your-access-token
WA_PHONE_ID=your-phone-number-id
APP_SECRET=your-meta-app-secretThe Bot Code (Flask and the Cloud API)
This version verifies the webhook, checks Meta's signature, reads text messages, and replies using simple commands. Save it as app.py:
import os, hmac, hashlib
import requests
from flask import Flask, request, abort
from dotenv import load_dotenv
load_dotenv()
app = Flask(__name__)
VERIFY = os.environ["VERIFY_TOKEN"]
TOKEN = os.environ["WA_TOKEN"]
PHONE_ID = os.environ["WA_PHONE_ID"]
SECRET = os.environ["APP_SECRET"].encode()
GRAPH = "v21.0" # use the current version from Meta's docs
MENU = ("Hi! Reply with a number:\n"
"1 - Opening hours\n2 - Prices\n0 - Talk to a person")
REPLIES = {
"1": "We are open Monday to Saturday, 9am to 6pm.",
"2": "Our price list is at example.com/prices.",
"0": "A team member will reply to you soon.",
}
def send_text(to, body):
url = f"https://graph.facebook.com/{GRAPH}/{PHONE_ID}/messages"
r = requests.post(
url,
headers={"Authorization": f"Bearer {TOKEN}"},
json={"messaging_product": "whatsapp", "to": to,
"type": "text", "text": {"body": body}},
timeout=10,
)
if r.status_code != 200:
app.logger.error("Send failed: %s", r.text)
@app.get("/webhook")
def verify():
if (request.args.get("hub.mode") == "subscribe"
and request.args.get("hub.verify_token") == VERIFY):
return request.args.get("hub.challenge", ""), 200
return "forbidden", 403
@app.post("/webhook")
def incoming():
sig = request.headers.get("X-Hub-Signature-256", "")
expected = "sha256=" + hmac.new(SECRET, request.data, hashlib.sha256).hexdigest()
if not hmac.compare_digest(sig, expected):
abort(403)
data = request.get_json(silent=True) or {}
try:
value = data["entry"][0]["changes"][0]["value"]
msg = value["messages"][0]
except (KeyError, IndexError):
return "ok", 200 # status updates and other events
sender = msg["from"]
if msg.get("type") == "text":
text = msg["text"]["body"].strip().lower()
send_text(sender, REPLIES.get(text, MENU))
else:
send_text(sender, "Sorry, I can only read text for now.\n" + MENU)
return "ok", 200
if __name__ == "__main__":
app.run(port=5000)What each part does
- GET /webhook answers Meta's one-time check when you register the URL.
- The signature check compares the
X-Hub-Signature-256header with a hash of the request body made with your app secret. It stops other people from sending fake messages to your bot. - The try/except ignores events that are not messages, such as delivery receipts.
- The REPLIES dictionary is your first rule-based bot. Add more keys as you learn what customers ask.
Test It Locally
- Run
python app.py. - In another terminal, run
ngrok http 5000and copy the HTTPS URL. - In the Meta dashboard, set the webhook callback URL to
https://your-ngrok-url/webhookand enter your verify token. - Subscribe the app to the messages field.
- Send "hi" from your test phone. You should get the menu back.
If nothing arrives, check the terminal for incoming requests first, then the error table later in this guide.
Option 2: A Python WhatsApp Bot With Twilio
Twilio removes the Meta webhook details. After joining Twilio's WhatsApp sandbox from your phone, you point the sandbox webhook at your server. Twilio sends form data, and you reply with TwiML:
from flask import Flask, request
from twilio.twiml.messaging_response import MessagingResponse
app = Flask(__name__)
@app.post("/twilio")
def twilio_reply():
text = request.form.get("Body", "").strip().lower()
resp = MessagingResponse()
resp.message("Hello! Reply 1 for hours or 2 for prices."
if text not in ("1", "2") else
{"1": "Open 9am to 6pm.", "2": "See example.com/prices"}[text])
return str(resp)This is the fastest way to a working demo. Twilio adds its own fees on top of Meta's, so compare costs in our API pricing guide before using it for production.
Why to Avoid Browser-Automation Libraries
Some tutorials use libraries that drive WhatsApp Web through a browser to send messages from a normal account. They look easy, but they depend on page layouts that change, they need a computer and a logged-in browser running all the time, and they go against WhatsApp's terms for automated use. Accounts used this way can be restricted or banned. Use them only for harmless personal experiments, never for customers or bulk messaging.
Add AI Replies
To answer open questions, call a language model inside incoming() instead of the dictionary. The pattern is the same for any provider: send the customer's text plus your instructions, take the answer, and pass it to send_text(). Keep a timeout on the call, keep answers short, and fall back to the menu if the model call fails. Our ChatGPT WhatsApp bot guide covers prompts that keep answers accurate.
Make It Production-Ready
- Return 200 quickly. Meta retries if your webhook is slow. For slow work such as AI calls, use a background queue or task worker.
- Handle duplicates. Webhooks can arrive more than once, so store message IDs and ignore repeats.
- Log errors from every API call, including the response body.
- Use a permanent token from a system user instead of the temporary test token.
- Respect the 24-hour window. Free-form text works only while the window is open. Outside it you need an approved template.
- Run with Gunicorn behind HTTPS, not the Flask development server:
gunicorn -w 2 -b 0.0.0.0:8000 app:app.
For hosting choices, see how to deploy a WhatsApp bot. A Python webhook bot suits any always-on server, a small VPS or a platform that runs web apps.
Finding Python WhatsApp Bot Code on GitHub
Searching GitHub for "python whatsapp bot" returns many projects. Before you run one, check:
- The connection method. Does it use the official Cloud API, Twilio, or a reverse-engineered or browser-based connection?
- Recent activity. Look for updates in the last year, open issues and a clear README.
- The code. Read where it sends data. Be wary of code that uploads your session or token to an unknown server.
- The license, if you plan to use it commercially.
Never paste your access token into code you have not read, and rotate any token you have exposed.
Common Errors and Fixes
| Problem | Likely cause | Fix |
|---|---|---|
| Webhook verification fails (403) | Verify token mismatch or wrong URL | Match VERIFY_TOKEN exactly and use the full /webhook URL |
| Messages never reach your server | Not subscribed to the messages field, or tunnel closed | Subscribe the field and restart ngrok |
| Signature check rejects real messages | Wrong app secret or body modified before hashing | Use the raw request body and the correct app secret |
| Send fails, recipient not allowed | Test recipient not added | Add the number in the Meta dashboard |
| Send fails after a day | The 24-hour window closed | Use an approved template message |
| Token errors | Temporary token expired | Create a permanent system-user token |
Meta's error responses include a code and message. Look the code up in Meta's error documentation, since codes and wording can change.
Security and Policy Checklist
- Keep secrets in environment variables.
- Verify every webhook signature.
- Do not log full customer messages longer than you need to.
- Honor "stop" requests.
Related guides: how to create a WhatsApp bot, WhatsApp bot with Node.js, deploy a WhatsApp bot and WhatsApp bot GitHub guide.
Frequently Asked Questions
Can I make a WhatsApp bot with Python for free?
You can build and test one for free using Meta's test number and a free tunnel. Real customer use may add message, hosting and provider costs.
Which Python framework is best, Flask or FastAPI?
Either works. Flask is simple for beginners, and FastAPI suits async code and bots that call slow APIs.
Do I need Twilio to build a Python WhatsApp bot?
No. You can use Meta's Cloud API directly. Twilio is a convenient alternative with extra fees.
Is pywhatkit safe for a business bot?
No. It automates WhatsApp Web and is unreliable and against WhatsApp's terms for automated use. Use the official API for business.
Where should I host the bot?
A small VPS or any platform that runs web apps works well, since a webhook bot only needs to answer requests.
Prefer no-code WhatsApp automation?
Erfan MD links to your WhatsApp with a pairing code and handles replies, broadcasts and follow-ups without writing code.
Explore Erfan MD