Web app that builds segmentation rules by combining any Chatwoot attribute (tags, Contact/Conversation custom attributes, date/time, channel/inbox) with AND/OR logic. When executed, it assigns a NNN_tag_<name> to matching contacts, creating an audience for WhatsApp Business campaigns.
No database required. The tag in Chatwoot is the saved rule — the app is stateless.
- Combine all Chatwoot attribute types: standard fields, custom attributes (Contact/Conversation/Account/Agent), labels, inbox/channel
- AND/OR flat logic matching Chatwoot's contact filter API semantics
- "Latest conversation" semantics for conversation-scoped custom attributes
- Preview matched contacts before tagging
- Split-tagging: tag only the first N contacts from the results
- Tag lifecycle management: list, count, and delete audience tags
- Chatwoot-native look & feel with light/dark mode support via
prefers-color-scheme
┌──────────────────┐ ┌──────────────────┐
│ Audience │ │ Chatwoot │
│ Builder │◄────►│ API │
│ (FastAPI) │ │ │
└──────────────────┘ └──────────────────┘
- FastAPI backend with Jinja2 templates and vanilla JS frontend
- httpx async HTTP client with retry logic for Chatwoot API
- pydantic-settings for environment-based configuration
- Multi-stage Docker build, optimized for arm64
# Clone the repo
git clone https://github.com/CrisAlva1414/Chatwoot-Tags.git
cd audience-builder
# Copy and fill in the environment variables
cp .env.example .env
# Edit .env with your Chatwoot instance details
# Run with Docker Compose
docker compose up -dOpen http://localhost:8000 in your browser.
| Variable | Required | Description |
|---|---|---|
CHATWOOT_BASE_URL |
Yes | Your Chatwoot instance URL |
CHATWOOT_ACCOUNT_ID |
Yes | Chatwoot account ID |
CHATWOOT_BOT_TOKEN |
Yes | Bot user's Personal Access Token |
ENV |
No | development (default) or production |
PORT |
No | Server port (default: 8000) |
CF_ACCESS_TEAM_DOMAIN |
No | Cloudflare Access team domain |
CF_ACCESS_AUD |
No | Cloudflare Access audience tag |
INBOX_CHANNEL_MAP |
No | JSON string mapping inbox IDs to channel names |
| Method | Endpoint | Description |
|---|---|---|
GET |
/ |
Audience builder UI |
GET |
/health |
Health check |
GET |
/api/schema |
Field schema (custom attributes, labels, inboxes) |
POST |
/api/preview |
Preview contacts matching a rule |
POST |
/api/execute |
Execute a rule and tag contacts |
GET |
/api/tags |
List existing audience tags |
GET |
/api/tags/next-number |
Get next available tag number |
DELETE |
/api/tags/by-name?name= |
Delete a tag from all contacts |
# Install dependencies
pip install -r requirements.txt -r requirements-dev.txt
# Run tests
pytest tests/ -v
# Run linter
ruff check .
# Run formatter
ruff format --check .MIT — see LICENSE for details.