Automated patient reactivation engine with deduplication, opt-out enforcement, and Google Ads Customer Match integration
Automated patient reactivation engine combining WhatsApp outreach with Google Ads Customer Match. Enforces monthly per-patient deduplication, opt-out compliance, and daily send limits — converting a dormant contact database into a continuously attributed, measurable revenue stream with full closed-loop campaign integration.
Clinics accumulate large patient bases but have no systematic way to re-engage patients who have not returned in months. Manual outreach is inconsistent, frequently reaches the same patient multiple times, and generates zero data for attribution. The result: opt-outs increase, revenue from the existing base stagnates, and the acquisition cost of new patients rises with no counterbalance.
A three-stage automation pipeline — list generation, controlled dispatch, and Customer Match export — that converts a static patient CSV into a measurable re-engagement channel. Every message is deduplicated by phone + calendar month, checked against a blacklist, and capped at 100 sends per day to protect account health.
01_fontes/ (source data)
├─ contacts.csv ← patient base
├─ blacklist.txt ← opt-outs (never contacted)
└─ informacoescliente.txt ← clinic config and message template
Stage 1 — Generate list (01_gerar_lista.py)
└─► Deduplicate by phone + current month
└─► Enforce blacklist
└─► Output: 02_disparos/lista_disparos_A_YYYYMMDD.csv
Stage 2 — Dispatch (02_sender.js via 03_disparar.ps1)
└─► Read run_*.json config (which CSV, which account, limits)
└─► Send messages respecting daily cap (100/account)
└─► Log results to 03_log/
└─► Progress bar + real-time status in terminal
Stage 3 — Customer Match export
└─► Export contacted phones as hashed SHA-256 list
└─► Upload to Google Ads → re-target existing patient base
Operational rules:
| Rule | Value |
|---|---|
| Max sends per day | 100 per account |
| Operating hours | Mon–Sat, 08:00–20:00 |
| Deduplication window | Phone + calendar month |
| Opt-out enforcement | Blacklist checked before every send |
- Dormant patient base converted into an active, attributed re-engagement channel
- Opt-out rate controlled through monthly deduplication and blacklist enforcement
- Customer Match closes the loop: reactivated patients re-enter Google Ads as a targetable audience on the landing page campaign
How it connects to the landing page:
| Stream | Tool | Google Ads |
|---|---|---|
| New patients | dradaianaferraz_gold landing page |
Conversion tracking (acquisition) |
| Existing patients | whatsappSenderHttp (this repo) |
Customer Match (retention + re-targeting) |
| Decision | Chosen | Alternative | Rationale |
|---|---|---|---|
| Dispatch method | Web automation | Official WhatsApp Business API | The official API requires WABA approval and per-message fees; web automation has zero marginal cost but requires an active WhatsApp session on a dedicated device |
| Storage | Flat files (CSV/JSON) | Relational database | A database adds infrastructure and operational overhead; flat files are portable, version-controlled, and sufficient for a single-operator workflow with auditable dispatch logs |
| Processing model | Batch (daily cap) | Real-time / event-driven | Real-time dispatch risks triggering WhatsApp rate-limiting and account suspension; a 100/day hard cap protects the account while maintaining a consistent re-engagement cadence |
| Deduplication window | Phone + calendar month | Permanent opt-out only | Monthly deduplication re-enables contact after a natural break, balancing re-engagement frequency with opt-out risk better than a permanent block |
| Layer | Technology |
|---|---|
| Dispatch engine | Node.js 18+ |
| List generation | Python 3.10+ |
| Orchestration | PowerShell 5.1 |
| Ads integration | Google Ads Customer Match (SHA-256 hashed) |
| Storage | CSV / JSON (flat-file, no database required) |
npm install # install Node.js dependenciesRun full pipeline:
.\03_disparar.ps1 # interactive menu: generate list → dispatch → exportManual stages:
python 01_gerar_lista.py # generate deduplicated dispatch list
node 02_sender.js # start dispatcher (reads run_*.json config)Operational patient reactivation tool integrating WhatsApp outreach with Google Ads Customer Match
Clinics accumulate a large patient base but have no systematic way to re-engage patients who have not returned in months. Manual outreach is time-consuming, inconsistent, and frequently reaches the same patient multiple times — causing noise and opt-outs.
This tool automates patient reactivation with deduplication by month, opt-out (blacklist) enforcement, daily send limits, and automatic Customer Match export to Google Ads — transforming an idle contact list into an active revenue channel.
Google Ads
└─► Landing page (dradaianaferraz_gold)
└─► new patient clicks WhatsApp
└─► conversion recorded in Google Ads
WhatsappSenderHttp (this repository)
└─► reactivates existing patient base via WhatsApp
└─► exports Customer Match to Google Ads
└─► Google Ads re-targets the clinic's own patient base
- This project works the existing patient base.
- The landing page captures new contacts.
- Customer Match connects both streams inside Google Ads.
| Rule | Value |
|---|---|
| Maximum sends per day | 100 messages per account |
| Operating hours | Monday–Saturday, 08:00–20:00 |
| Deduplication window | Per phone number + calendar month |
| Opt-out enforcement | Blacklist file checked before every send |
1. Update source files in 01_fontes/
2. Verify blacklist is current
3. Generate dispatch list with 01_gerar_lista.py
4. Validate CSV in 02_disparos/
5. Run dry-run before live send
6. Execute send via 03_disparar.ps1
7. Review execution log in 03_log/
8. Export Customer Match to 04_publico/ if needed
| Option | Action |
|---|---|
[1] |
Send messages |
[2] |
Dry-run (simulate without sending) |
[3] |
Send with manual limit |
[4] |
View log status |
[5] |
Clear full history |
[6] |
Clear a specific execution |
[7] |
Generate new dispatch list |
[8] |
Export Customer Match |
# Install Node.js 18+ and Python 3.10+ before proceeding
# Python script uses only standard library — no pip install required
cd C:\repositorio\whatsappSenderHttp
npm installcd C:\repositorio\whatsappSenderHttp
.\03_disparar.ps101_fontes/ source contact files
01_fontes/blacklist.txt central opt-out list
02_disparos/ generated dispatch lists
03_log/ execution history and logs
04_publico/ Google Ads Customer Match exports
Wesley Gomes da Silva · IT Manager · Agile Coach · Full-Stack Developer
Este repositório existe para operar a base da clínica com segurança e repetibilidade.
Objetivos principais:
- Gerar listas de disparo a partir dos arquivos de entrada.
- Evitar reenvio indevido para quem já recebeu no mês.
- Respeitar opt-out via blacklist.
- Enviar mensagens com cadência controlada.
- Exportar Customer Match para Google Ads.
WhatsappSenderHttp (este repositório)
└─► gera lista de disparo
└─► envia mensagens por WhatsApp
└─► exporta Customer Match
dradaianaferraz_gold (repositório irmão)
└─► capta novos leads no site
└─► mede conversões de clique no WhatsApp
Resumo operacional:
- Este projeto trabalha a base já existente da clínica.
- O projeto da landing page trabalha novos contatos.
- Os dois se conectam no Google Ads.
Ordem normal de operação:
- Atualizar os arquivos em
01_fontes/. - Conferir se a
01_fontes/blacklist.txtestá atualizada. - Gerar uma nova lista com
01_gerar_lista.py. - Validar o CSV gerado em
02_disparos/. - Fazer
dry-runantes do envio real. - Executar o envio.
- Conferir o log em
03_log/. - Se necessário, exportar Customer Match em
04_publico/.
Instale antes de usar:
| Ferramenta | Versão mínima | Download |
|---|---|---|
| Node.js | 18+ | https://nodejs.org |
| Python | 3.10+ | https://www.python.org |
| PowerShell | 5.1+ | já incluso no Windows 10/11 |
Instale as dependências do projeto (só na primeira vez):
cd C:\repositorio\whatsappSenderHttp
npm installO script Python usa apenas bibliotecas padrão — nenhum
pip installnecessário.
Abra o PowerShell na pasta do projeto:
cd C:\repositorio\whatsappSenderHttp
.\03_disparar.ps1O menu principal oferece:
| Opção | Uso |
|---|---|
[1] |
enviar mensagens |
[2] |
simular envio sem enviar |
[3] |
enviar com limite manual |
[4] |
ver status do log |
[5] |
limpar histórico completo |
[6] |
limpar uma execução específica |
[7] |
gerar nova lista de disparo |
[8] |
exportar Customer Match |
- Máximo de 100 mensagens por dia por conta.
- Envio apenas entre 08h e 20h, de segunda a sábado.
- Deduplicação por telefone + mês.
- Quem já recebeu no mês atual não entra de novo na lista.
- Quem está em
01_fontes/blacklist.txtnão recebe mensagem e não entra no Customer Match.
- Os arquivos de entrada corretos estão em
01_fontes/. - A blacklist está atualizada.
- A campanha escolhida é a correta.
- O arquivo novo foi realmente criado em
02_disparos/. - O CSV gerado não contém números inválidos ou óbvios duplicados.
- O CSV contém apenas contatos elegíveis.
- Contatos já enviados no mês atual ficaram fora da lista.
- Números da blacklist ficaram fora da lista.
- A quantidade final faz sentido para a campanha escolhida.
- O log em
03_log/registrou a execução. - O status (
[4]) mostra os números enviados. - Um novo processamento no mesmo mês não reintroduz quem já recebeu.
- O limite diário e a janela de horário foram respeitados.
- O arquivo
04_publico/clientes_google_ads_customer_match.csvfoi gerado. - Telefones da blacklist não aparecem no export.
- O arquivo está pronto para importação no Google Ads.
01_fontes/ arquivos de entrada
01_fontes/blacklist.txt lista central de opt-out
02_disparos/ listas geradas para envio
03_log/ histórico e logs de execução
04_publico/ exportações para Google Ads
Se a lista vier menor do que o esperado:
- revisar deduplicação do mês atual em
03_log/ - revisar blacklist
- revisar arquivos de entrada
Se um número que deveria sair continuar aparecendo:
- verificar se está formatado corretamente na blacklist
- verificar se o número entrou por outra fonte com formatação diferente
Se um número não deveria receber novamente:
- conferir se o envio anterior foi registrado no log
Node.js · Python 3 · PowerShell 5 · WhatsApp Web (sem API oficial)
This tool closes the last mile of a B2C reactivation funnel. Acquisition campaigns (paid ads, landing pages) target cold leads at high cost; reactivation targets an existing patient base at zero acquisition cost — the highest-ROI segment in any service business. The closed loop with Google Ads Customer Match converts each outreach event into an attribution signal, feeding the paid campaign algorithm with first-party data that reduces CPA over time. The deduplication and blacklist enforcement are not just compliance features — they are the mechanism that keeps the channel healthy and permission-based.
| Dimension | Decision | Alternative Rejected | Rationale |
|---|---|---|---|
| API layer | Unofficial WA Web automation | Meta Business API (official) | Official API requires business verification (weeks), a dedicated number, and per-conversation cost; this tool operates at personal/clinic scale under personal account limits |
| Architecture | Node.js (sender) + Python (data) | Python-only | The WhatsApp Web automation library ecosystem (Baileys) lives in Node.js; Python excels at data processing; polyglot pipeline plays to each runtime's strength |
| Daily cap | 100 sends/day hard limit | Unlimited / maximum throughput | Mirrors human messaging behaviour; prevents spam classification by WhatsApp's rate detection; protects the account that is the clinic's primary contact channel |
| Attribution | Google Ads Customer Match export | No attribution | Converts outreach into a paid campaign signal; the reactivation list becomes a lookalike audience source, lowering new patient CPA over successive campaigns |