Production-ready Django WhatsApp Cloud Platform — Inbox, Campaigns, Templates, Analytics
Project description
django-meta-whatsapp
A production-ready Django WhatsApp Cloud Platform you can drop into any Django project.
Features
- Inbox — Real-time chat interface with media, location pins, reply threading, message status ticks
- Contacts — CSV import/export, tagging, opt-out management
- Templates — Create, edit, push to Meta, sync from Meta
- Campaigns — Bulk messaging with pluggable audience system, CSV support, scheduled sends
- Analytics — Delivery/read tracking, 30-day trend chart
- Webhooks — Automatic inbound message sync, status updates, reaction handling
- REST APIs — Send text, location, template; list chats/campaigns (API-key auth)
- Django Admin — Full admin panel for all models
- Multi-account — One Django project, multiple WhatsApp Business Accounts
- Signals — Hook into message received/sent and campaign completed events
- Celery support — Optional background campaign processing
Installation
pip install django-meta-whatsapp
# or from source:
pip install -e .
Also install django-tailwind-cli (no Node required):
pip install django-tailwind-cli
Quick Setup
1. settings.py
INSTALLED_APPS = [
...
"django_tailwind_cli",
"django_meta_whatsapp",
]
# Single-account shortcut (alternative: use WhatsAppAccount model in dashboard)
WHATSAPP = {
"ACCESS_TOKEN": "your_meta_access_token",
"PHONE_NUMBER_ID": "your_phone_number_id",
"WABA_ID": "your_waba_id", # needed for template sync
"VERIFY_TOKEN": "your_verify_token", # for webhook verification
"LOGIN_URL": "/accounts/login/", # redirect for unauthenticated users
}
2. urls.py
from django.urls import path, include
urlpatterns += [
path("whatsapp/", include("django_meta_whatsapp.urls")),
]
3. Migrate
python manage.py migrate
4. Tailwind CSS
python manage.py tailwind build
Open http://yoursite/whatsapp/ — done.
Optional Dashboard Configuration
You can customize the look and feel of the WhatsApp Dashboard directly from your settings.py. All of these settings are optional!
# settings.py
# Replace the text name in the sidebar (default: "WhatsApp")
META_WHATSAPP_DASHBOARD_NAME = "My Custom App"
# Change the Lucide icon used in the sidebar (default: "message-circle")
META_WHATSAPP_DASHBOARD_ICON = "building-2"
# Or, use a complete custom image logo instead of the icon
META_WHATSAPP_DASHBOARD_LOGO = "/static/logo.png"
# Change the primary accent color of the entire dashboard! (Provide an HSL triplet)
META_WHATSAPP_ACCENT_COLOR = "142, 72%, 45%" # Emerald green
Multi-Account Support
Add accounts in the Settings → Accounts dashboard. Each account has its own:
- Access Token
- Phone Number ID
- WABA ID
- Verify Token
The webhook endpoint (/whatsapp/webhook/) auto-routes to the correct account by phone_number_id.
Pluggable Audience System
The package never assumes your user model. You control who receives campaigns.
Option 1: Named audience providers
# myapp/whatsapp_audiences.py
from myapp.models import Customer
def vip_customers():
return Customer.objects.filter(total_orders__gt=10)
def inactive_users():
return Customer.objects.filter(is_active=False)
# settings.py
WHATSAPP = {
...
"PHONE_FIELD": "mobile", # field on your model that holds the phone number
"NAME_FIELD": "full_name", # field for the display name
"AUDIENCES": {
"VIP Customers": "myapp.whatsapp_audiences.vip_customers",
"Inactive Users": "myapp.whatsapp_audiences.inactive_users",
},
}
The campaign form will show these as audience choices.
Option 2: Full campaign resolver
# settings.py
WHATSAPP = {
...
"CAMPAIGN_RESOLVER": "myapp.whatsapp_audiences.resolve_campaign",
}
# myapp/whatsapp_audiences.py
def resolve_campaign(campaign):
"""
Return list of dicts: [{"phone": "919...", "name": "...", "params": {...}}, ...]
"""
if campaign.audience_type == "vip":
qs = Customer.objects.filter(total_orders__gt=10)
return [{"phone": c.mobile, "name": c.full_name, "params": {}} for c in qs]
return []
Option 3: Built-in WhatsAppContact list
Set audience_type = "contacts" — sends to all non-opted-out WhatsAppContact records.
Option 4: CSV Upload
Set audience_type = "csv" and upload a CSV with phone, name columns in the campaign form.
Sending Messages Programmatically
from django_meta_whatsapp.utils import (
send_text_message,
send_location_message,
send_template_message,
send_media_message,
upload_media,
build_template_components,
)
# Text
send_text_message("919876543210", "Hello from Django!")
# Location pin
send_location_message(
"919876543210",
latitude=24.5854,
longitude=73.7125,
name="Udaipur Office",
address="Hiran Magri, Udaipur, Rajasthan",
)
# Template with variables
components = build_template_components(body_params=["Rakesh", "ORD-1234"])
send_template_message("919876543210", "order_confirmation", components=components)
# Media
with open("invoice.pdf", "rb") as f:
media_id = upload_media(f, "application/pdf")
send_media_message("919876543210", media_id, "document", filename="invoice.pdf")
Signals
from django.dispatch import receiver
from django_meta_whatsapp.signals import (
whatsapp_message_received,
whatsapp_message_sent,
whatsapp_campaign_completed,
)
@receiver(whatsapp_message_received)
def on_inbound(sender, message, **kwargs):
print(f"New message from {message.phone_number}: {message.message_body}")
@receiver(whatsapp_campaign_completed)
def on_campaign_done(sender, campaign, sent, failed, **kwargs):
print(f"Campaign '{campaign.name}' finished: {sent} sent, {failed} failed")
Celery (optional)
# settings.py
WHATSAPP_USE_CELERY = True
Campaigns will be queued as Celery tasks instead of running synchronously.
REST API
All endpoints require X-API-Key header (create keys in Settings → API Keys).
| Method | Endpoint | Description |
|---|---|---|
| POST | /whatsapp/api/send-message/ |
Send text message |
| POST | /whatsapp/api/send-location/ |
Send location pin |
| POST | /whatsapp/api/send-template/ |
Send approved template |
| GET | /whatsapp/api/chats/ |
List recent conversations |
| GET | /whatsapp/api/campaigns/ |
List campaigns |
Send text
POST /whatsapp/api/send-message/
X-API-Key: your-key
Content-Type: application/json
{"phone": "919876543210", "message": "Hello!"}
Send location
POST /whatsapp/api/send-location/
X-API-Key: your-key
Content-Type: application/json
{
"phone": "919876543210",
"latitude": 24.5854,
"longitude": 73.7125,
"name": "Our Store",
"address": "Udaipur, Rajasthan"
}
Send template
POST /whatsapp/api/send-template/
X-API-Key: your-key
Content-Type: application/json
{
"phone": "919876543210",
"template_name": "order_confirmation",
"language": "en",
"body_params": ["Rakesh", "ORD-1234"]
}
Webhook Configuration
Set your Meta webhook URL to:
https://yourdomain.com/whatsapp/webhook/
The verify token is either:
- The
verify_tokenfield on aWhatsAppAccount(multi-account) WHATSAPP["VERIFY_TOKEN"]in settings (single-account)
Management Commands
# Sync templates from Meta
python manage.py wa_sync_templates
# Sync for a specific account
python manage.py wa_sync_templates --account-id 1
Models Reference
| Model | Purpose |
|---|---|
WhatsAppAccount |
Multi-account credentials |
WhatsAppContact |
Contact directory |
WhatsAppConversation |
Grouped chat threads |
WhatsAppMessage |
Individual messages (text, media, location, etc.) |
WhatsAppTemplate |
Meta-approved message templates |
WhatsAppCampaign |
Bulk send campaigns |
WhatsAppCampaignRecipient |
Per-recipient status tracking |
WhatsAppMedia |
Uploaded media library |
WhatsAppWebhookLog |
Raw webhook event logs |
WhatsAppAPIKey |
REST API authentication keys |
Environment Variables (alternative to settings.py)
META_WA_ACCESS_TOKEN=EAAx...
META_WA_PHONE_NUMBER_ID=1234567890
META_WABA_ID=9876543210
META_WA_VERIFY_TOKEN=my_secret_verify_token
License
MIT
Developer
Created by Rahul Baberwal.
Repository: https://github.com/rahul-baberwal/django-meta-whatsapp/
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_meta_whatsapp-1.0.1.tar.gz.
File metadata
- Download URL: django_meta_whatsapp-1.0.1.tar.gz
- Upload date:
- Size: 68.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e49c8e93f970edf7948a11d3119eb5d3e1d37fd24f24bbc15f866e97b964cc3a
|
|
| MD5 |
2d71263857a92675a1aeaaac7f218970
|
|
| BLAKE2b-256 |
6a508f28738607999f56f49ce55554b6a52466e00a4dc6a7d2db3366d7dfbb23
|
Provenance
The following attestation bundles were made for django_meta_whatsapp-1.0.1.tar.gz:
Publisher:
publish.yml on rahul-baberwal/django-meta-whatsapp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_meta_whatsapp-1.0.1.tar.gz -
Subject digest:
e49c8e93f970edf7948a11d3119eb5d3e1d37fd24f24bbc15f866e97b964cc3a - Sigstore transparency entry: 1810288359
- Sigstore integration time:
-
Permalink:
rahul-baberwal/django-meta-whatsapp@71c1e6b3b35f7ae7c1728994e3438cf307e85c5c -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/rahul-baberwal
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@71c1e6b3b35f7ae7c1728994e3438cf307e85c5c -
Trigger Event:
push
-
Statement type:
File details
Details for the file django_meta_whatsapp-1.0.1-py3-none-any.whl.
File metadata
- Download URL: django_meta_whatsapp-1.0.1-py3-none-any.whl
- Upload date:
- Size: 82.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1128719479ef060a54974f25fcabd014c5625bb19991468a34c3a34bbaca8b5
|
|
| MD5 |
0be3974cc01eb0f86134c711384d9580
|
|
| BLAKE2b-256 |
d042414a9116bb77ea16a04872f6a1875766f86d3225b0bc1c04bd760d388597
|
Provenance
The following attestation bundles were made for django_meta_whatsapp-1.0.1-py3-none-any.whl:
Publisher:
publish.yml on rahul-baberwal/django-meta-whatsapp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_meta_whatsapp-1.0.1-py3-none-any.whl -
Subject digest:
e1128719479ef060a54974f25fcabd014c5625bb19991468a34c3a34bbaca8b5 - Sigstore transparency entry: 1810288380
- Sigstore integration time:
-
Permalink:
rahul-baberwal/django-meta-whatsapp@71c1e6b3b35f7ae7c1728994e3438cf307e85c5c -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/rahul-baberwal
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@71c1e6b3b35f7ae7c1728994e3438cf307e85c5c -
Trigger Event:
push
-
Statement type: