WhatsApp não oficial: protocolos, libs e gateways
Transcrição da conversa sobre evolution-go, whatsmeow, Baileys, ports para Elixir e alternativas de gateway. Escolha um tópico na barra lateral.
Como eles conseguem hackear o WhatsApp? github.com/evolution-foundation/evolution-go
Não é "hackear". O evolution-go é um cliente WhatsApp não oficial — ele se conecta da mesma forma que o WhatsApp Web/Desktop, usando a biblioteca whatsmeow (Go).
Como funciona de verdade
- Multi-Device do WhatsApp Web: seu celular é o dispositivo primário. Existe um protocolo (WebSocket + Protocol Buffers, com handshake Noise) que o WhatsApp Web usa para parear.
- O whatsmeow reimplementa esse protocolo (engenharia reversa do tráfego do Web/Desktop), não explora um bug.
- No pareamento, o celular gera um QR code com uma chave pública temporária. Você escaneia → o celular transmite as chaves de identidade/prekeys pelo canal cifrado → o novo dispositivo passa a operar como um "companion device", com suas próprias chaves, mas vinculado à mesma conta.
- Depois disso, a API REST do evolution-go manda/recebe mensagens se passando por esse dispositivo pareado.
Ou seja: exige acesso físico ao celular para escanear o QR (ou código de pareamento aprovado no aparelho). Não dá para invadir um WhatsApp alheio só rodando isso.
Riscos/alertas
- Viola os Termos de Uso do WhatsApp; a conta pode ser banida.
- Se a máquina onde roda vazar a sessão (as credenciais do dispositivo pareado), outra pessoa assume a conta — esse é o vetor real de "hack" nesse stack: servidor mal configurado (
GLOBAL_API_KEYfraca, Redis/Postgres expostos) ou backups de sessão vazados. - Bibliotecas não oficiais já tiveram falhas de confiança (o próprio Evolution teve polêmicas de licenciamento/telemetria). Trate como código sensível.
Me explique o github.com/tulir/whatsmeow
whatsmeow é a biblioteca Go que implementa o protocolo do WhatsApp Web Multi-Device. É a peça de baixo nível que projetos como o evolution-go usam para conversar com os servidores do WhatsApp. Criada por Tulir Asokan, licença MPL-2.0, ~7.4k stars.
Ponto central: não é oficial da Meta. É engenharia reversa do comportamento do WhatsApp Web/Desktop, mantida por comunidade.
O que ela faz
- Envia/recebe mensagens (texto e mídia) em chats privados e grupos
- Gerencia grupos, convites e links de convite
- Notificações de digitação, recibos de entrega/leitura
- Lê e escreve app state (lista de contatos, fixar/silenciar chats)
- Trata retry receipts quando a descriptografia falha
- Status/Stories (experimental)
Como funciona por dentro
A estrutura de pastas revela as camadas:
socket/— a conexão real. WebSocket + handshake Noise (o mesmo esquema de cifragem de transporte que o WhatsApp Web usa). Também trata keepalive e reconexão.binary/— codifica/decodifica os "nós" binários do protocolo WhatsApp (formato tokenizado, com dicionário de tokens e packing de bits). É aqui que mora a engenharia reversa do wire format.proto/— as definições Protobuf (geradas em Go) das mensagens do WhatsApp.store/— persistência. Guarda a identidade do dispositivo (par de chaves), sessões Signal, prekeys e app state. Você normalmente usasqlstore(SQLite/Postgres).appstate/— sincronização do estado do app (contatos, configurações) usando o esquema de patches/versões do WhatsApp.types/— tipos de mensagem (texto, imagem, reação, poll, etc).argo/— serialização da estrutura de mensagem para o formato compacto que o WhatsApp exige.- Raiz:
client.go(oClient),pair.go/pair-code.go(pareamento por QR e por código),prekeys.go,send.go,message.go,call.go,group.go,newsletter.go,presence.go, etc.
Fluxo típico de uso
container, _ := sqlstore.New("sqlite3", "file:session.db", nil)
deviceStore, _ := container.GetFirstDevice()
client := whatsmeow.NewClient(deviceStore, nil)
client.AddEventHandler(func(evt interface{}) { /* trata eventos */ })
if client.Store.ID == nil {
qrChan, _ := client.GetQRChannel(...)
client.Connect() // gera QR
// imprime/entrega o QR para o usuário escanear no celular
} else {
client.Connect() // já pareado, reconecta
}
client.SendMessage(ctx, jid, &waE2E.Message{ ... })
O pareamento é o mesmo do WhatsApp Web: QR (ou código de 8 dígitos) → o celular aprova → o dispositivo ganha sua própria chave de identidade mas fica vinculado à mesma conta. Tudo fim-a-fim cifrado via Signal (prekeys + double ratchet).
Limitações e observações
- Chamadas não são implementadas (
call.goexiste mas o suporte é incompleto). - Broadcast lists não funcionam (o WhatsApp Web também não suporta).
- É frágil por natureza: você quebra quando a Meta muda o protocolo, e a conta pode ser banida por uso automatizado — não é canal oficial.
- O mesmo problema resolvido em Node.js é o Baileys; o
evolution-apiusa Baileys, oevolution-gousa whatsmeow.
Se você quer entender o protocolo a fundo, comece por socket/ (transporte/handshake) e binary/ (formato dos pacotes) — o resto é consequência desses dois.
O que o Evolution adiciona em comparação com o whatsmeow?
O whatsmeow é uma biblioteca: você a importa no seu programa Go e ela vive dentro do seu processo. O evolution-go é um serviço/produto que embrulha essa biblioteca e resolve tudo que um time precisa para operar WhatsApp em produção.
Camada por camada, o Evolution adiciona
1. API REST + Swagger
Em vez de você escrever Go para cada operação, expõe endpoints prontos: POST /instance/create, GET /instance/{name}/qrcode, POST /message/sendText, POST /message/sendMedia, GET /instance/{name}/status, DELETE /instance/{name}. Documentação em /swagger/index.html.
2. Multi-instância (multi-tenant)
O whatsmeow gerencia um Client/dispositivo. O Evolution gerencia vários números simultâneos, cada um com seu store, status, webhook e ciclo de vida — nomes de instância, criação, reconexão e remoção via HTTP.
3. Distribuição de eventos
O whatsmeow entrega eventos via callback em Go (AddEventHandler). O Evolution transforma isso em canais prontos para integrar: WebSocket, Webhook HTTP, AMQP/RabbitMQ e NATS. Você recebe mensagens/eventos sem estar no processo Go.
4. Persistência
Opcional de mensagens/estado em PostgreSQL via GORM (DATABASE_SAVE_MESSAGES), com bancos separados para auth e usuários. No whatsmeow você escolhe e monta seu store manualmente.
5. Armazenamento de mídia
Integração com MinIO/S3 para upload/download de imagens, vídeos, áudios e documentos.
6. Autenticação e controle de acesso
GLOBAL_API_KEY + middlewares de auth/validação em cima da API. A biblioteca não tem noção de API key.
7. Licenciamento (gate comercial)
Registro, ativação e heartbeat periódico. Sem licença, os endpoints retornam 503. Isso é regra de negócio da Evolution Foundation, não existe no whatsmeow.
8. Manager (UI web)
Painel em /manager/login para configurar URL/chave e fazer o fluxo de pareamento/QR sem escrever código.
9. Operação/Deploy
Dockerfile, Makefile (make docker-build, make docker-run, make dev), .env.example — configuração padronizada, pronto para subir em VPS.
O que ele não muda: continua sendo cliente não oficial, o risco de ban é o mesmo, e chamadas/broadcast lists seguem sem suporte (vêm da limitação do whatsmeow).
O que são chamadas/broadcast lists?
São dois recursos do próprio WhatsApp que o whatsmeow (e portanto o Evolution) não consegue usar via API:
Chamadas (calls)
São as chamadas de voz e vídeo do WhatsApp (individuais e em grupo), incluindo o "tocar" pra avisar o outro número. No WhatsApp Web/Desktop isso aparece como aquele botão de telefone/câmera.
Por que não funciona: chamada de voz/vídeo usa um stack separado — sinalização própria, WebRTC para o áudio/vídeo e servidores de relay/STUN da Meta. O call.go existe, mas só recebe alguns eventos básicos; não implementa estabelecer, atender, áudio/vídeo nem encerrar. Ou seja, não dá para "discar" ou atender uma ligação pela API.
Broadcast lists (listas de transmissão)
É o recurso "Lista de transmissão" do WhatsApp: você cria uma lista de contatos (ex.: "Clientes") e, ao mandar uma mensagem pra ela, cada contato recebe como uma conversa individual — ninguém vê os outros destinatários nem sabe que é uma lista. Diferente de um grupo, onde todos se veem.
Por que não funciona: o WhatsApp Web/Desktop também não suporta listas de transmissão — elas só existem no app móvel e são gerenciadas no servidor a partir do celular primário, com um fluxo que os clientes web/linked não recebem. Como o whatsmeow se comporta como um dispositivo linked (igual ao Web), ele não consegue criar nem disparar para essas listas.
É muito difícil migrar o whatsmeow para Elixir?
Não é "migrar" — é reescrever. whatsmeow é Go e não existe tradução automática; o que você migra é o comportamento do protocolo, usando Baileys/whatsmeow como referência. E é difícil, mas o ecossistema Elixir já está resolvendo isso.
Quão difícil é, de fato
Reescrever do zero: muito difícil (meses a 1 ano+). Motivos:
- Volume e maturidade: whatsmeow tem ~1.667 commits e anos de engenharia reversa de casos de borda. Não é só "mandar mensagem": é token dictionary binário, handshake Noise com certificados, Signal double ratchet, retry receipts, LTHash do app state, encoding WAM (analytics), cifragem de mídia.
- Crypto tem buracos no Erlang:
:crypto(OpenSSL) cobre AES-GCM, HKDF, X25519, HMAC, SHA. Não cobre XEdDSA (o esquema de assinatura do Signal que o WhatsApp usa). Você acaba precisando de NIF (Rust/C) — exatamente o que os ports fazem. - Não dá pra embutir Go na BEAM de forma limpa: Go tem runtime próprio (goroutines), e NIF que bloqueia scheduler + panic/segfault do Go derruba a VM. NIF do whatsmeow é má ideia; sidecar é o caminho.
O que já existe (não comece do zero)
O ecossistema Elixir é todo baseado em Baileys, não em whatsmeow:
baileys_ex(jeffhuen) — port do Baileys para Elixir, com Signal Protocol em Elixir puro + NIFs Rust (snowpara Noise,xeddsa). Está em alpha, ~1.263 downloads, 6 stars. Supervisão OTP com:gen_statem.amarula(Roberto Trevisan) — outro port do Baileys, MIT, v0.3.0.irish— abordagem sidecar: roda Baileys num subprocesso Deno e conversa com ele. Muito mais simples e robusto, mas mantém processo externo.whatsapp_elixir/whatsapp_sdk— wrappers da Cloud API oficial da Meta (nada a ver com protocolo não oficial).
Por que portar Baileys e não whatsmeow
- Modelo de concorrência: Baileys é event-emitter/async → mapeia quase direto para
GenServer/Task. Go (interfaces, canais, goroutines) não traduz tão limpo para OTP. - Licença: whatsmeow é MPL-2.0 (copyleft por arquivo — um port é derivado e herda obrigações). Baileys é MIT, muito mais permissivo para derivar. Não é coincidência os ports Elixir serem MIT e citarem Baileys.
Recomendação prática
| Objetivo | Caminho | Esforço |
|---|---|---|
| Usar WhatsApp no Elixir agora | Sidecar: rodar Evolution/whatsmeow como serviço Go e chamar via HTTP/WebSocket (ou irish-style) | dias |
| Nativo na BEAM, produção | Adotar/forçar baileys_ex ou amarula e contribuir | semanas |
| Portar o whatsmeow especificamente | Não vale a pena — use Baileys como referência | 6–12+ meses |
Resumo: portar whatsmeow é hard pela via errada. Se quer Elixir nativo, o atalho real é contribuir num port de Baileys já existente (baileys_ex/amarula); se quer resultado rápido, sidecar. E em qualquer caso você assume a manutenção eterna de acompanhar as mudanças do protocolo da Meta.
O que é Baileys?
Baileys é o equivalente do whatsmeow, mas em TypeScript/Node.js: uma biblioteca que implementa o protocolo do WhatsApp Web Multi-Device direto por WebSocket, sem automação de navegador (nada de Puppeteer/headless Chrome).
Como no whatsmeow, não é oficial da Meta — é engenharia reversa — e o uso viola os Termos de Uso, com risco de ban.
Origem e manutenção
- Criada por Adiwajshing (
adiwajshing/Baileys), virou o padrão de fato para bots de WhatsApp em JS. - Hoje é mantida pela comunidade em
WhiskeySockets/Baileys(repositório atual). Versão atual da linha v7 está em RC (obaileys_exrastreia av7.0.0-rc14). - Licença MIT — por isso é a base preferida dos ports (Elixir, Rust, etc.), diferente do MPL do whatsmeow.
O que faz
- Pareamento por QR ou código (companion device)
- Envio/recebimento de mensagens — texto e mídia (imagem, vídeo, áudio, doc, sticker)
- Grupos e comunidades, convites, participantes
- Notificações de digitação, recibos de leitura/entrega
- App state sync (contatos, fixar/silenciar, arquivar)
- Status, presença, chamadas (parcial, igual ao whatsmeow)
import makeWASocket, { useMultiFileAuthState } from '@whiskeysockets/baileys'
const { state, saveCreds } = await useMultiFileAuthState('auth_info')
const sock = makeWASocket({ auth: state })
sock.ev.on('creds.update', saveCreds)
sock.ev.on('messages.upsert', m => console.log(m))
Baileys vs whatsmeow
| Baileys | whatsmeow | |
|---|---|---|
| Linguagem | TypeScript / Node | Go |
| Concorrência | Event loop único (event-emitter) | Multi-thread (goroutines) |
| Auth | useMultiFileAuthState | store SQL (sqlite/postgres) |
| Licença | MIT | MPL-2.0 |
| Ecossistema | Enorme (bots JS, Evolution API) | Go (evolution-go, mautrix-whatsapp) |
Contexto do fio: o evolution-api (Node) usa Baileys; o evolution-go usa whatsmeow. São a mesma ideia em linguagens diferentes. E, por ser MIT e por o modelo event-emitter mapear bem para OTP, Baileys é a referência que os ports Elixir estão seguindo — não o whatsmeow.
Mas na teoria, qual é melhor: Evolution Go ou Node?
"Na teoria" depende da dimensão — não existe vencedor único:
- Performance/recursos → Go (evolution-go): multi-thread real, footprint baixo (dezenas de MB), um binário só, aguenta muito mais instâncias por host.
- Maturidade/features → Node (evolution-api): é o projeto original, muito mais antigo, feature set e ecossistema enormes.
- Aposta segura hoje → Node. Go só ganha se escala/recursos forem o gargalo real.
Comparação por dimensão
| Dimensão | Evolution Go (whatsmeow) | Evolution API Node (Baileys) |
|---|---|---|
| Concorrência | Goroutines, paralelismo real | Event loop único, single-thread |
| Memória/CPU | Baixa | Alta (Node + V8 por instância) |
| Deploy | Binário único, Docker leve | Node runtime, mais pesado |
| Maturidade do produto | Nova (~19 commits no repo) | Anos de produção |
| Features/integrações | Básico (mensagens, eventos, mídia) | Amplo: Typebot, Chatwoot, OpenAI, RabbitMQ, S3, etc. |
| Comunidade | Pequena | Grande, muito material |
| Lib de protocolo | whatsmeow (Go, sólido) | Baileys (TS, MIT, ecossistema gigante) |
| Licença/gate | Requer ativação de licença, endpoints 503 até liberar + heartbeat | Mesma fundação, histórico de polêmicas de licença/telemetria |
O que pesa de verdade
- Maturidade assimétrica: os dois são da mesma fundação, mas o Node é o produto maduro. O evolution-go tem 19 commits — é early. Em teoria, a arquitetura Go é melhor; na prática, o Node entrega mais coisas hoje.
- Event loop vs goroutines: Baileys num processo Node lida com todos os números no mesmo loop. Com muitas instâncias ativas (milhares de eventos/s), isso vira head-of-line blocking. Go distribui em cores. Esse é o argumento técnico mais forte do Go.
- Protocol parity: Baileys tem comunidade gigante e implementa mais cantos (mais tipos de mensagem, newsletters, etc.). O whatsmeow é excelente, mas o produto em cima é imaturo.
- Licenciamento: o
503 até ativar + heartbeatdo evolution-go é um gate comercial e um ponto de dependência externa. Se for auto-hospedar de forma crítica, isso incomoda.
Recomendação
- Precisa de features/integrações e quer algo provado → Node (evolution-api).
- Muitos números por máquina, memória/custo importam, time Go → Go, aceitando que é mais imaturo.
- Só quer o protocolo e vai construir o resto → use a lib direto: Baileys (Node) ou whatsmeow (Go), sem o Evolution por cima. Aí a escolha é de linguagem, não de produto.
Resumo: em teoria Go ganha em engenharia (concorrência/recursos); Node ganha em produto (maturidade/features). Na prática, hoje, o Node ainda é a escolha mais segura — o Go é a aposta de arquitetura.
E existem outras soluções além do Evolution?
Existem várias, em três camadas. Contexto importante: em início de 2026 a Meta intensificou a detecção de clientes não oficiais — avisos de "sua conta pode estar em risco" estão atingindo usuários de todas as libs (Baileys, whatsmeow, WEBJS), mesmo em baixo volume. Vale para qualquer opção abaixo.
1. Gateways prontos (alternativas diretas ao Evolution)
WAHA — WhatsApp HTTP API (devlikeapro/waha, ~7.3k stars, Apache-2.0)
A alternativa mais forte. É um "glue layer" Node que suporta 4 engines trocáveis por variável de ambiente:
WEBJS— whatsapp-web.js (Puppeteer/Chromium)WPP— WPPConnect (Puppeteer)NOWEB— Baileys (WebSocket, sem browser)GOWS— whatsmeow (Go), geração nova
Design esperto: se uma abordagem quebrar, você troca de engine sem reescrever a integração. Modelo: core grátis + tier pago (Plus).
GOWA (aldinokemal/go-whatsapp-web-multidevice)
Go/whatsmeow, REST API + UI, multi-account, webhooks, MCP e Chatwoot. É o "evolution-go" sem o gate de licença.
WPPConnect Server
Node, Puppeteer, comunidade brasileira grande, servidor pronto.
Cobalt (Auties00/Cobalt)
Java/Kotlin, completo, standalone, para quem está no ecossistema JVM.
Outros: chrishubert/whatsapp-api (wrapper do whatsapp-web.js), salman0ansari/whatsapp-api-nodejs, CodeChat, OpenWA, Venom.
2. Bibliotecas (você constrói o resto)
Protocolo direto (WebSocket, sem browser) — leves, mais arriscados de detecção:
- Baileys (TS/Node) — a dominante
- whatsmeow (Go)
- whatsapp-rust (Rust), baileyrs (Rust+JS)
- Elixir: baileys_ex, amarula
Automação de browser (Puppeteer/Chromium) — mais pesadas, historicamente mais "invisíveis":
Custo: browser roda Chromium, então são centenas de MB por instância vs. dezenas na via WebSocket.
3. Oficial (Meta)
- WhatsApp Business Cloud API — oficial, templates, janela de 24h, pago por conversa.
- BSPs (revendedores oficiais): Twilio, Infobip, 360dialog, Gupshup, Bird, Vonage, Wati, Zenvia.
Como escolher
| Se você quer… | Vá de |
|---|---|
| Menos lock-in e poder trocar de engine | WAHA |
| Ecossistema/integrações e comunidade BR | Evolution API (Node) |
| Go nativo sem gate de licença | GOWA |
| Customizar fundo, uma linguagem só | lib direta (Baileys/whatsmeow) |
| Compliance, sem risco de ban | Cloud API oficial / BSP |
Resumo: WAHA é a alternativa mais direta e flexível ao Evolution; GOWA é o caminho Go livre; e se ban/compliance for inegociável, a única resposta é a API oficial.
Qual é o gate de licença do evolution-go? — confirmado por inspeção do código-fonte (pkg/core/c0.go)
É uma trava de execução em runtime, separada da licença legal. O arquivo é deliberadamente ofuscado (nome c0.go, identificadores como _sn, _kni, _txz) para dificultar remoção. Detalhe crucial: o heartbeat é non-blocking.
O que é
Imagine um app que, quando você instala e abre, não deixa você usar nada até você se cadastrar no site do fabricante. Não é senha pirata nem nada — é só um "cadastre-se antes de usar".
É isso. No evolution-go, quando sobe sem licença, toda a API responde 503 (fora do ar). Você abre o painel (/manager/login), faz um cadastro na Evolution Foundation, recebe uma chave (api_key) e aí o serviço destrava e passa a funcionar.
Para que serve
É um controle comercial. Na prática, serve para:
- Saber quem está usando — quantas instalações existem, de onde vêm (métrica de adoção).
- Capturar contato — seu e-mail/empresa ficam registrados (base de leads para vender suporte/plano).
- Cobrar — permite empurrar licença comercial, tier pago, suporte pago.
- Telemetria — o servidor manda um "ping" a cada 30 min dizendo "estou vivo, na versão X, enviei Y mensagens".
Resumo: o código é aberto (Apache), mas eles colocaram uma catraca comercial no meio. É tipo um software grátis que exige login para liberar as funções.
Por que isso chama atenção
Porque é estranho para open source. Normalmente código Apache é "baixe e use". Aqui não: você depende de falar com o servidor deles pelo menos uma vez para o produto sair do 503.
A parte boa (confirmada no código)
A catraca só trava na primeira vez. Depois de ativada:
- a chave fica salva no seu banco;
- o "ping" de 30 min, se falhar, só ignora — não desliga nada;
- então, mesmo offline para sempre, continua funcionando.
Ou seja: não é assinatura mensal que expira. É mais um "cadastro obrigatório na instalação". O que dá problema é só se você nunca conseguir ativar (sem internet, ou e-mail não registrado).
O que isso significa pra você
- Se tudo bem fazer esse cadastro na Evolution Foundation → segue tranquilo, é grátis pra ativar.
- Se você não quer depender deles nem se cadastrar → use o GOWA (mesmo stack Go/whatsmeow, sem nenhuma catraca) ou monte em cima do whatsmeow direto.
Servidor de licença
https://license.evolutionfoundation.com.br — ofuscado em c0.go:35-45, montado a partir de fragmentos de string. Há um decodificador XOR (_k54v) com duas chaves (_k1/_k0) que nunca são usadas — código morto/isca.
| Endpoint | Quando |
|---|---|
POST /v1/activate | valida a licença no boot/ativação (assinado) |
POST /v1/register/init | fluxo manual (GET /license/register) |
POST /v1/register/exchange | troca authorization_code por api_key |
POST /v1/register/auto | auto-ativação por e-mail |
POST /v1/heartbeat | a cada 30 min (hbInterval, c0.go:373) |
POST /v1/deactivate | no shutdown graceful (timeout 5s) |
Requisições são assinadas: header X-Api-Key + X-Signature = HMAC-SHA256(body, api_key) (c0.go:85-107).
O gate
GateMiddleware (c0.go:638): allowlist apenas /health, /server/ok, /license/*, /manager*, /assets*, /passkey-ceremony*, /swagger*, /ws e estáticos. Todo o resto → HTTP 503:
{ "error": "service not activated", "code": "LICENSE_REQUIRED",
"register_url": "https://<host>/manager/login" }
Como ativa (ordem real no código, c0.go:441)
- Licença no banco (
runtime_configs.api_key) → ativa na hora; dispara/v1/activatenon-blocking. GLOBAL_API_KEY→ usada como token de licença: tenta/v1/activate; se OK, salva key+tier e ativa. Detalhe:_58(c0.go:891) aceita a string crua como API key se o exchange falhar.EVOLUTION_OPERATOR_EMAIL→/v1/register/auto.- Nada disso → inativo, banner "License Registration Required" e 503.
O detalhe que importa: heartbeat não derruba nada
StartHeartbeat (c0.go:839): a cada 30 min chama /v1/heartbeat; se falha, só imprime ⚠ Heartbeat failed (non-blocking) — não desativa. E ValidateContext (c0.go:623) checa apenas estado local: flag _txz + sha256(api_key + instance_id) batendo com o hash capturado na ativação.
- Depois de ativada, nunca revalida remotamente. Sem expiração, sem grace period — ficar offline indefinidamente continua funcionando.
- Só a primeira ativação precisa de rede. Se a key já está no banco, o boot nem depende do servidor deles.
- O que derruba é só: nunca ter ativado, ou adulterar
api_keyno banco (quebra o hash local).
Binding e telemetria
- instance_id = UUID determinístico de
hostname + MAC(primeira interface não-loopback), ou aleatório se indisponível (c0.go:274-307). Guardado emruntime_configs.instance_id. - Não é hardware-lock rígido: no boot o hash é recomputado com o id atual, então mover o banco para outra máquina ainda funciona (só muda a identidade reportada).
- O heartbeat envia
instance_id,uptime_seconds,versione umtelemetry_bundlecom contagens agregadasmessages_sent/messages_recvdesde o último beat (c0.go:924) — sem conteúdo de mensagem.
Licença de código (separada do gate técnico)
LICENSE:3-9 — Apache-2.0 + condições: (a) não remover LOGO/copyright do frontend; (b) Usage Notification: exibir aviso visível de que usa Evolution Go, senão pode exigir licença comercial.
Coloque uma comparação lado a lado do GOWA e Evolution.
Comparei três: GOWA (Go livre), Evolution Go (Go com gate) e Evolution API (Node, o produto maduro). A diferença mais importante não é feature — é licença e maturidade.
| Critério | GOWA | Evolution Go | Evolution API (Node) |
|---|---|---|---|
| Linguagem / stack | Go + whatsmeow | Go + whatsmeow | Node/TS + Baileys |
| Licença | MIT | Apache-2.0 + condições de marca | Apache-2.0 (+ histórico de polêmicas) |
| Gate de licença | Nenhum — baixe e use | 503 até ativar + heartbeat (30 min) | Sem gate técnico |
| Maturidade | 621 commits, ~4.8k stars | ~19 commits, ~878 stars (muito novo) | Anos de produção, comunidade grande |
| Multi-device / tenant | Sim (v8), /devices + X-Device-Id | Sim, multi-instância | Sim, multi-tenant por instância |
| UI / dashboard | gowa-ui (repo separado, baixado no boot com SHA-256) | Manager embutido (/manager/login) | Manager embutido |
| MCP / IA | Sim — /mcp + OAuth 2.1 + node n8n | Não | Não nativo (integra com OpenAI, Dify, etc.) |
| Eventos | Webhook + WebSocket | Webhook, WS, AMQP/RabbitMQ, NATS | WS, RabbitMQ, SQS, Kafka, NATS, Pusher |
| Segurança do webhook | HMAC-SHA-256 (X-Hub-Signature-256), filtro por evento e por JID, webhook por device | Webhook simples | Webhook + filtros |
| Banco | SQLite (padrão) ou Postgres | PostgreSQL (GORM) | Postgres/MySQL (Prisma) + Redis |
| Mídia / storage | Local; processa com ffmpeg/libwebp (sticker, compressão) | S3/MinIO | S3/MinIO |
| Auth da API | Basic Auth (múltiplas credenciais) + OAuth no MCP | GLOBAL_API_KEY | GLOBAL_API_KEY |
| Extras | Auto-reply, auto-mark-read, auto-download, auto-reject-call, presence pulse, proxy SOCKS5/HTTP, subpath, ARM | Telemetria, passkey, licenciamento | Typebot, Chatwoot, OpenAI, Dify, n8n, Flowise, EvoAI |
| Chatwoot | Integração nativa (inbox, histórico, mídia) | Não | Integração nativa |
| Deploy | Docker, binário (GoReleaser), docker-compose | Docker + Makefile | Docker + Redis + DB |
| Custo / sustentação | Grátis (Patreon opcional) | "Grátis" mas com cadastro obrigatório | Grátis (auto-host) |
Leitura rápida
- GOWA vence em liberdade: MIT, sem gate, MCP nativo e um cuidado de segurança acima da média (HMAC nos webhooks, filtros por evento/JID, SHA-256 pinning da UI). É o "evolution-go sem catraca".
- Evolution Go perde hoje para o GOWA em quase tudo: menos commits, sem MCP, e o gate de licença. Só ganha em brokers de eventos (RabbitMQ/NATS) e no Manager embutido.
- Evolution API (Node) continua sendo o mais completo em produto: ecossistema de integrações e maturidade que os dois Go não têm. Preço: mais memória e o event loop único.
Qual a diferença do GOWA pro WAHA?
São filosofias opostas: o GOWA é um motor só, em Go. O WAHA é uma camada de cola que roda vários motores e deixa você trocar por variável de ambiente. Detalhe importante: o motor GOWS do WAHA é o whatsmeow — ou seja, o WAHA praticamente contém o GOWA como uma de suas opções.
| Critério | GOWA | WAHA |
|---|---|---|
| Arquitetura | Um motor só, em Go | Node (NestJS) como "glue layer" sobre vários motores |
| Motores | Só whatsmeow | WEBJS e WPP (Chromium via Puppeteer), NOWEB (Baileys), GOWS (whatsmeow) — troca com 1 env var |
| Seguro contra quebra de protocolo | Não — se o whatsmeow quebrar, você espera | Sim — "se um motor falhar, tenta outro" |
| Risco de detecção/ban | Só via protocolo direto | Você escolhe: navegador (WEBJS/WPP) ou WebSocket |
| Licença | MIT | Apache-2.0 |
| Modelo comercial | Grátis (Patreon opcional) | Core grátis + WAHA Plus pago (imagem privada, login no Docker Hub) |
| Multi-contas / multi-sessão | Grátis (v8: /devices + X-Device-Id, webhook por device) | Recurso do Plus |
| Footprint | Binário Go único, levísimo | Node; leve em NOWEB/GOWS, pesado em WEBJS/WPP (Chromium) |
| MCP / IA | MCP nativo em /mcp + OAuth 2.1 + node n8n | Docs de integração com ChatGPT/IA, sem MCP nativo |
| Webhooks | HMAC-SHA-256 (X-Hub-Signature-256), por device, filtro por evento e por JID | Webhooks configuráveis por sessão, com eventos e assinatura HMAC |
| Mídia | ffmpeg/libwebp embutidos: sticker, compressão de imagem e vídeo | Envio/recebimento de mídia; conversão não é o foco |
| Chatwoot | Integração nativa completa | Não nativo |
| UI / docs | gowa-ui em repo separado, baixada no boot com SHA-256 | Dashboard + Swagger prontos, "configure in a click" |
| Configuração | Flags + env + .env | Env + API/config |
| Deploy | Binário (GoReleaser) + Docker/compose; ARM | Docker, com imagem por engine (waha, noweb, gows, arm) |
| Maturidade | ~4.8k stars, 621 commits | ~7.4k stars, 2.366 commits, comunidade grande |
Leitura rápida
- A diferença central não é feature — é arquitetura. O WAHA aposta em redundância de motor; o GOWA aposta em simplicidade e controle.
- O WAHA contém o GOWA: ao rodar
GOWS, é literalmente o whatsmeow por baixo. A vantagem do WAHA é poder cair para Baileys ou Chromium sem reescrever nada. - O GOWA entrega grátis o que no WAHA é Plus: multi-conta, MCP, webhook por device e Chatwoot nativo.
- O WAHA é mais maduro e mais testado (7.4k stars, 2.366 commits) e tem as melhores ferramentas de operação (dashboard, Swagger, imagem por engine).
Consigo usar o GOWA no Chatwoot?
Sim — e é integração nativa e de primeira classe, não gambiarra. (O Evolution também tem, mas aqui ela vem completa: histórico, multi-inbox por número, notas de edição/exclusão, read sync e fila de retry.)
Como funciona
São dois sentidos. O GOWA precisa estar publicamente acessível (HTTPS; ngrok serve para testar), porque o Chatwoot chama o GOWA de volta.
WhatsApp ──msg──► GOWA ──REST──► Chatwoot (inbox "API channel")
▲ │
└── POST /chatwoot/webhook ◄── agente responde
- Entrada: mensagem chega no WhatsApp → GOWA empurra para o Chatwoot via API, criando contato/conversa se não existir.
- Saída: o agente responde no Chatwoot → o Chatwoot chama o webhook público do GOWA → o GOWA envia pelo WhatsApp.
O que precisa
- Instância Chatwoot (self-hosted ou cloud) com admin.
- Uma inbox do tipo API channel — ou deixar o GOWA criar sozinho.
- IDs numéricos:
CHATWOOT_ACCOUNT_IDeCHATWOOT_INBOX_ID(não é o identifier, o hmac token nem o secret). - Um API access token de usuário do Chatwoot.
- O webhook da inbox apontando para
https://seu-gowa/chatwoot/webhook.
Configuração mínima
CHATWOOT_ENABLED=true
CHATWOOT_URL=https://app.chatwoot.com
CHATWOOT_API_TOKEN=seu_token
CHATWOOT_ACCOUNT_ID=12345
CHATWOOT_INBOX_ID=67890
CHATWOOT_DEVICE_ID=meu-device # obrigatório se tiver +1 device
CHATWOOT_WEBHOOK_SECRET=segredo-forte
CHATWOOT_WEBHOOK_URL=https://seu-gowa.example.com/chatwoot/webhook?secret=segredo-forte
Para o GOWA criar a inbox sozinho: CHATWOOT_AUTO_CREATE=true + CHATWOOT_INBOX_NAME=WhatsApp. Ele reusa a inbox se já existir (nunca duplica em restart) e já conecta o webhook.
Mensagens nos dois sentidos
Recebendo: texto, imagem, áudio, vídeo, documento, sticker, localização e cartão de contato (vCard).
Enviando: texto, imagem (com legenda), áudio (vira nota de voz/PTT), vídeo e qualquer arquivo.
Mensagens que você mesmo envia pelo celular também são espelhadas no Chatwoot como outgoing, então a conversa fica completa.
Grupos
Detectados pelo JID @g.us. O nome do grupo vira o nome do contato no Chatwoot, e a resposta do agente volta para o grupo certo.
Dentro do grupo, cada mensagem leva o nome do autor como prefixo (John: oi), senão não daria para saber quem falou.
Formatação traduzida
Cada app usa uma sintaxe diferente de negrito/itálico. O GOWA converte nos dois sentidos, senão o agente veria asteriscos literais.
*bold* ↔ **bold** · _italic_ ↔ *italic* · ~strike~ ↔ ~~strike~~
Edições e exclusões
Quando o cliente edita uma mensagem, entra no Chatwoot uma nota encadeada ✏️ Edited: …. Quando apaga para todos, entra 🗑️ This message was deleted.
As notas ficam presas à mensagem original, então o histórico continua legível.
Read sync (sincronia de leitura)
Recibos de leitura do WhatsApp atualizam o visto por último no Chatwoot, e quando o agente responde a última mensagem recebida no WhatsApp é marcada como lida.
Depende da tabela local de vínculos de mensagem (o famoso WAID:<id>) para casar os dois lados.
Respostas e reações encadeadas
Um reply ou um 👍 fica anexado à mensagem que ele referencia, em vez de virar uma bolha solta — de novo via o vínculo WAID:<id>.
Assinatura do agente
Com vários atendentes, é impossível saber quem respondeu. Com CHATWOOT_SIGN_MSG=true, a resposta sai como *Jane* + separador + texto.
Só afeta o que vai para o WhatsApp; no Chatwoot o agente já aparece normalmente.
Ignorar conversas
CHATWOOT_IGNORE_JIDS exclui chats do Chatwoot. Aceita JIDs exatos e coringas: @g.us (todos os grupos), @s.whatsapp.net (todas as DMs), @lid.
Ex.: @g.us,6281199999999@s.whatsapp.net — ignora grupos e um contato específico.
Fila de retry (não perde mensagem)
Se o Chatwoot cair ou responder 429/5xx, a mensagem é guardada numa fila local e reenviada em background com backoff exponencial.
Erros 4xx permanentes (payload ruim, token inválido) só são logados — não adianta reenviar.
Histórico sob demanda
CHATWOOT_IMPORT_MESSAGES=true + CHATWOOT_DAYS_LIMIT_IMPORT_MESSAGES=7 importa os últimos N dias ao conectar o device.
Também dá para disparar manual: POST /chatwoot/sync e acompanhar em /chatwoot/sync/status.
Import: REST vs banco direto
REST funciona até no Chatwoot Cloud, mas o timestamp vira a hora que você importou.
Postgres direto (CHATWOOT_IMPORT_DB_URI, só self-hosted) preserva o horário original, mantém o nome real do grupo, roda bem mais rápido (uma transação por conversa) e é idempotente — pode rodar de novo sem duplicar.
Multi-inbox por número
Cada device pode ir para uma inbox/conta/servidor diferente, configurado por REST e guardado em chatwoot_device_configs.
Depois que existe config por device, ela vira a fonte da verdade e cada device precisa da sua — o GOWA prefere falhar a rotear errado.
PUT /devices/<id>/chatwoot/config
Atribuição correta no histórico
Mensagens antigas que você mandou entram como sender_type='User' do agente dono do token — aparecem com nome e avatar em vez de "Unknown sender".
Se o token estiver revogado, importa mesmo assim, só sem atribuição (com aviso no log).
Segurança do webhook
A rota /chatwoot/webhook fica fora do Basic Auth (o Chatwoot precisa chamá-la), então proteja com secret:
header X-Chatwoot-Webhook-Secret, query ?secret= ou HMAC X-Hub-Signature-256.
Cuidados
- Sem secret, o webhook fica aberto para quem descobrir a URL — use
CHATWOOT_WEBHOOK_SECRET. - O
?secret=na query pode vazar em logs; se incomodar, ponha um proxy à frente que injeta o header. - Import direto no banco = só self-hosted (Chatwoot Cloud não expõe Postgres).
- Com vários devices, defina
CHATWOOT_DEVICE_ID, senão o envio falha comDEVICE_NOT_AVAILABLE. - O token fica guardado no banco do GOWA (mascarado nas leituras da API) — trate o banco como cofre.
Quero colocar na Hetzner. Qual a configuração para tudo? Dos dois.
Objetivo: GOWA + Chatwoot, registrados como apps no cleat. Antes de configurar, inspecionei o servidor de verdade — e isso muda a resposta.
Diagnóstico do servidor (gestaobem-cx33, verificado agora)
4 vCPU · Hetzner CX33 · fsn1 · 167.233.201.9
RAM: 7751 MB total · 2243 usados · 5507 livres
Disco: 75 GB · 19 GB usados · 54 GB livres
Docker: NÃO instalado
gh: autenticado (escopo repo) → dá para fork
Veredito: um dá, o outro não
| Via cleat? | Por quê | |
|---|---|---|
| GOWA | ✅ Sim | É Go — o cleat tem runtime golang |
| Chatwoot | ❌ Não | É Ruby on Rails e precisa de 4 processos (web + worker/Sidekiq + Postgres/pgvector + Redis). O cleat só tem golang, node, phoenix e static |
Ou seja: GOWA no cleat, Chatwoot fora do cleat — Cloud ou Docker Compose.
1. GOWA no cleat
O cleat builda a partir de um repo GitHub e lê .cleat_deploy/deploy.json. Logo: fork do upstream com esse arquivo.
.cleat_deploy/deploy.json no fork:
{
"runtime": "golang",
"build_command": "cd src && CGO_ENABLED=0 go build -tags purego -o whatsapp",
"start_command": "./src/whatsapp rest --port=4031",
"memory_max_mb": 1024
}
-tags purego evita toolchain C/libwebp no build. O GOWA exige Go 1.26+ — se o runtime do cleat tiver versão menor, o build falha (aí o caminho é Docker ou o binário do release).Registrar o app:
cleat_apps_create name=gowa repo=puppe1990/<fork> branch=main
host=gowa.apps.gestaobem.com port=4031
runtime=golang server=5
4031 está livre — o 4011 é do site publicado nesta conversa.
Dependências de sistema: ffmpeg e webp (libwebp-tools), para sticker/compressão. O campo runtime_apt_packages existe na API mas não aparece nos tools — provavelmente precisa ser setado no painel.
Env vars (cleat_env_set):
APP_PORT=4031
APP_HOST=0.0.0.0
APP_DEBUG=false
APP_OS=Chrome
APP_BASIC_AUTH=admin:<senha-forte>
DB_URI=file:/var/lib/gowa/whatsapp.db
WHATSAPP_AUTO_DOWNLOAD_MEDIA=false # economiza disco
# Chatwoot (preencher depois)
CHATWOOT_ENABLED=true
CHATWOOT_URL=https://app.chatwoot.com
CHATWOOT_API_TOKEN=<token>
CHATWOOT_ACCOUNT_ID=<id>
CHATWOOT_INBOX_ID=<id>
CHATWOOT_DEVICE_ID=<device>
CHATWOOT_WEBHOOK_SECRET=<segredo>
CHATWOOT_WEBHOOK_URL=https://gowa.apps.gestaobem.com/chatwoot/webhook?secret=<segredo>
storages/. Se ficarem dentro do release_path, cada deploy apaga o pareamento (você teria que escanear o QR toda vez). Precisa de data_dir=/var/lib/gowa no app e o DB_URI apontando para lá.2. Chatwoot — duas opções
A) Chatwoot Cloud (recomendado aqui)
5 minutos, zero infra: cria conta em app.chatwoot.com, cria a inbox API channel, pega account_id, inbox_id e o API access token. Nada para instalar — o GOWA só precisa da URL https://app.chatwoot.com.
B) Self-hosted (Docker) — exige Docker, que não está instalado
services:
chatwoot-web:
image: chatwoot/chatwoot:latest
command: bundle exec rails s -p 3000 -b 0.0.0.0
ports: ["4032:3000"]
env_file: .env
depends_on: [postgres, redis]
chatwoot-worker:
image: chatwoot/chatwoot:latest
command: bundle exec sidekiq -C config/sidekiq.yml
env_file: .env
depends_on: [postgres, redis]
postgres:
image: pgvector/pgvector:pg17 # Chatwoot exige a extensão vector
volumes: ["pgdata:/var/lib/postgresql/data"]
redis:
image: redis:alpine
volumes: { pgdata: {} }
Custo: ~2,5–3 GB de RAM e ~10 GB de disco. Cabe nos 5,5 GB livres, mas é servidor de produção com 17 apps rodando — não coloque sem monitorar. E você teria que instalar Docker + um proxy TLS próprio (o cleat só faz TLS para os hosts dele).
Ordem de execução
- Chatwoot — criar conta/inbox/token (ou subir o compose).
- Fork do GOWA +
deploy.json→cleat_apps_create→ apt packages (ffmpeg,webp) → env vars → deploy. - Parear o device (QR em
https://gowa.apps.gestaobem.com) e pegar odevice_idpara oCHATWOOT_DEVICE_ID. - Webhook da inbox →
https://gowa.apps.gestaobem.com/chatwoot/webhook?secret=...e testar com ocurl.
Riscos
- RAM: self-host do Chatwoot em servidor compartilhado de produção — evite se não for monitorar.
- Go 1.26 no build; se o runtime do cleat não tiver, cair para Docker ou binário do release.
- data_dir mal configurado = perda de sessão a cada deploy.
- Ban/ToS: o stack não oficial viola os Termos de Uso da Meta — use um número dedicado, não o principal.
golang (fork + deploy.json + envs), na porta 4031, host gowa.apps.gestaobem.com. O Chatwoot não passa pelo cleat — vá de Cloud (recomendado, zero infra) ou suba um compose com Docker fora dele, aceitando ~3 GB de RAM por conta própria.Tendo isso no cleat, eu consigo colocar nesse servidor atual tudo?
Resposta medida, não estimada. Peguei o consumo real de cada serviço no gestaobem-cx33:
RSS somado de todos os processos ....... 2.376 MB (2,4 GB)
RAM disponível .......................... ~5.848 MB (5,8 GB)
Swap .................................... 4.096 MB (256 MB usados) ← folga boa
Disco ................................... 54 GB livres
vCPU .................................... 4 (compartilhados por ~20 apps)
Maiores consumidores hoje: next-server 340 MB, painel do cleat 229 MB, prato_ai 194 MB, e uma fila de node/beam de ~100 MB cada.
Orçamento (estimativas de produção)
| Carga | RAM steady | Nota |
|---|---|---|
| GOWA | 0,3–0,5 GB | Go é leve; ffmpeg em rajada durante mídia |
| Chatwoot web (Puma) | 1,0–1,5 GB | |
| Chatwoot worker (Sidekiq) | 0,8–1,2 GB | always-on — não pode dormir (issue #74) |
| Postgres pgvector | 0,3–0,5 GB | |
| Redis | ~0,1 GB | |
| subtotal Chatwoot | ~2,5–3,5 GB | |
| build de assets (Vite) | pico 1–2 GB | transitório; o runtime rails do cleat já cria swapfile de 2 GB no build |
Total: 2,4 (atual) + ~0,4 (GOWA) + ~3,0 (Chatwoot) ≈ 5,8 GB de 7,7 GB. Sobra ~1,9 GB + 4 GB de swap.
Veredito
GOWA sozinho — ✅ tranquilo
Cabe com folga. É um binário Go com whatsmeow; o custo extra é o ffmpeg durante processamento de mídia, em rajada.
GOWA + Chatwoot self-hosted — ⚠️ cabe, mas no limite
Não é "não dá" — é "dá sem margem". Os riscos concretos:
Pico de CPU no deploy do Chatwoot (Vite / asset precompile) segura os outros ~20 apps por alguns minutos → faça deploy em horário de baixo uso.
OOM se o Puma subir muitos workers ou o Sidekiq inflar; exige MemoryMax por serviço e monitoramento.
Baseline permanente: com worker always-on, o Chatwoot não entra no sleep do waker — esses ~3 GB ficam fixos.
Tudo (+ Evolution + WAHA) — ❌ não neste servidor
Só o WAHA já é o pior caso: com o engine WEBJS ele roda Chromium, ~0,5–1 GB por sessão.
Somando Evolution API (Node/Baileys ~0,3–0,6 GB por instância) + Evolution Go + Postgres/Redis de cada um, você estoura. Seriam ~2 servidores.
Recomendação
- Agora: GOWA no
gestaobem-cx33(sobra espaço). - Chatwoot: Cloud (zero RAM, começa grátis) — ou um segundo Hetzner dedicado (CX22 ~4 GB já roda Chatwoot; CX32 ~8 GB dá folga) se quiser self-host de verdade.
- Self-host no mesmo box: só se aceitar a margem estreita, com limites por serviço e monitoramento de OOM.