Instalação
openclaw onboard e openclaw channels add --channel whatsapp solicitam a instalação do plugin na primeira vez que ele é selecionado; openclaw channels login --channel whatsapp oferece o mesmo fluxo de instalação se o plugin estiver ausente. Checkouts de desenvolvimento usam o caminho local do plugin; instalações stable/beta instalam primeiro o @openclaw/whatsapp pelo ClawHub, com fallback para o npm. O runtime do WhatsApp é distribuído fora do pacote npm principal do OpenClaw, portanto suas dependências de runtime permanecem com o plugin externo. Instalação manual:
@openclaw/whatsapp) somente para o fallback do registro; fixe uma versão exata somente para uma instalação reproduzível.
Pareamento
Solução de problemas de canais
Configuração do Gateway
Configuração rápida
Configurar a política de acesso
Vincular o WhatsApp (QR)
Iniciar o Gateway
Aprovar a primeira solicitação de pareamento (modo de pareamento)
Padrões de implantação
Número dedicado (recomendado)
Número dedicado (recomendado)
- identidade separada do WhatsApp para o OpenClaw
- listas de permissões de MD e limites de roteamento mais claros
- menor chance de confusão com chats consigo mesmo
Fallback para número pessoal
Fallback para número pessoal
dmPolicy: "allowlist", allowFrom incluindo seu próprio número, selfChatMode: true. As proteções de runtime para chats consigo mesmo usam como chave o próprio número vinculado mais allowFrom.Modelo de runtime
- O Gateway gerencia o socket do WhatsApp e o ciclo de reconexão.
- Um watchdog monitora dois sinais independentemente: a atividade bruta do transporte do WhatsApp Web e a atividade de mensagens do aplicativo. Uma sessão silenciosa, mas conectada, não é reiniciada apenas porque nenhuma mensagem chegou recentemente; ele força a reconexão somente quando os frames de transporte deixam de chegar durante uma janela interna fixa (não configurável pelo usuário) ou quando as mensagens do aplicativo permanecem ausentes por mais de 4x o tempo limite normal de mensagens. Logo após uma reconexão de uma sessão recentemente ativa, essa primeira janela usa o tempo limite normal de mensagens, mais curto, em vez da janela de 4x. O OpenClaw pode responder automaticamente às mensagens offline que o Baileys entrega no início dessa reconexão, limitado pelo período de vida da desduplicação de IDs de mensagens de entrada; a inicialização inicial mantém a proteção curta contra histórico obsoleto.
- Os tempos do socket do Baileys são explícitos em
web.whatsapp.*:keepAliveIntervalMs(intervalo de ping do aplicativo),connectTimeoutMs(tempo limite do handshake inicial),defaultQueryTimeoutMs(esperas de consultas do Baileys, além dos tempos limite do OpenClaw para envio/presença de saída e confirmação de leitura de entrada). - Os envios de saída exigem um listener ativo do WhatsApp para a conta de destino; caso contrário, os envios falham imediatamente.
- Os envios para grupos incluem metadados nativos de menção para tokens
@+<digits>e@<digits>(no texto e nas legendas de mídia) quando o token corresponde aos metadados atuais de participantes, inclusive em grupos baseados em LID. - Chats de status e transmissão (
@status,@broadcast) são ignorados. - Chats diretos usam regras de sessão de MD (
session.dmScope; o padrãomainreúne as MDs na sessão principal do agente). As sessões de grupo são isoladas por JID (agent:<agentId>:whatsapp:group:<jid>). - Canais/Newsletters do WhatsApp podem ser destinos explícitos de saída por meio de seu JID
@newsletternativo, usando metadados de sessão do canal (agent:<agentId>:whatsapp:channel:<jid>) em vez da semântica de MD. - O transporte do WhatsApp Web respeita as variáveis de ambiente padrão de proxy no host do Gateway (
HTTPS_PROXY,HTTP_PROXY,NO_PROXY, incluindo variantes em minúsculas). Prefira a configuração de proxy no nível do host às configurações por canal. - Com
messages.removeAckAfterReplyhabilitado, o OpenClaw remove a reação de confirmação depois que uma resposta visível é entregue.
Ligar para o solicitante atual com o MeowCaller (experimental)
O plugin pode disponibilizarwhatsapp_call em turnos do agente originados no WhatsApp. Ele usa o MeowCaller para realizar uma chamada de voz pelo WhatsApp para o solicitante autorizado atual e reproduzir uma mensagem TTS do OpenClaw após o atendimento. A ferramenta não tem parâmetro de número de destino, portanto um prompt não pode redirecionar a chamada. Desabilitado por padrão.
Habilitar chamadas experimentais
actions.calls: true à configuração do canal do WhatsApp e reinicie o Gateway:false, o OpenClaw não disponibiliza a ferramenta whatsapp_call.Instalar a CLI revisada do MeowCaller
meowcaller no PATH do host do Gateway. Até que o PR nº 7 do MeowCaller seja integrado, compile o branch revisado:$HOME/.local/bin está no PATH do serviço do Gateway. Essa revisão contém comandos explícitos pair e notify somente para envio; notify não abre microfone, alto-falante, dispositivo de vídeo nem captura de diagnóstico. Não o substitua pelo comando play da CLI de exemplo upstream.Parear o dispositivo vinculado do MeowCaller
whatsapp_call informa o diretório de estado específico da conta e o comando de pareamento). Para a conta padrão:MeowCaller linked device ready. Mantenha wa-voip.db privado — essa é a sessão do MeowCaller. Contas não padrão recebem seu próprio caminho de armazenamento pela ação de status; no Windows, execute o comando do PowerShell correspondente.Configurar o TTS e ligar pelo WhatsApp
Call me and say the build finished. A ferramenta identifica o remetente pelo contexto de entrada confiável, sintetiza um arquivo WAV privado temporário, executa o MeowCaller durante uma janela de chamada limitada e exclui o arquivo de áudio posteriormente. O OpenClaw informa explicitamente o armazenamento da conta, aguarda um status de saída zero após o atendimento/reprodução/encerramento e trata um tempo limite ou status de saída diferente de zero como uma chamada de ferramenta com falha.Solicitações de aprovação
O WhatsApp pode renderizar solicitações de aprovação de execução e plugins como reações👍/👎, controladas pela configuração de encaminhamento de aprovações no nível superior:
approvals.exec e approvals.plugin são independentes; habilitar o WhatsApp como canal apenas vincula o transporte e não envia nada, a menos que a família de aprovações correspondente esteja habilitada e roteada para ele. O modo de sessão entrega aprovações nativas por emoji somente para aprovações originadas no WhatsApp. O modo de destino usa o pipeline de encaminhamento compartilhado para destinos explícitos e não cria uma distribuição separada para MDs de aprovadores.
As reações de aprovação do WhatsApp exigem aprovadores explícitos em allowFrom (ou "*"). defaultTo define destinos de mensagens padrão comuns, não uma lista de aprovadores. Comandos manuais /approve ainda passam pelo fluxo normal de autorização de remetentes do WhatsApp antes da resolução da aprovação.
Hooks de plugins e privacidade
As mensagens de entrada do WhatsApp podem conter conteúdo pessoal, números de telefone, identificadores de grupos, nomes de remetentes e campos de correlação de sessões. O WhatsApp não transmite payloads do hook de entradamessage_received aos plugins, a menos que essa opção seja habilitada:
channels.whatsapp.accounts.<id>.pluginHooks.messageReceived. Habilite isso somente para plugins nos quais se confia para acessar o conteúdo e os identificadores de entrada do WhatsApp.
Controle de acesso e ativação
- Política de MD
- Política de grupos e listas de permissões
- Menções e /activation
channels.whatsapp.dmPolicy:allowFrom aceita números no formato E.164 (normalizados internamente). Trata-se apenas de uma lista de controle de acesso para remetentes de MD — ela não restringe envios explícitos de saída para JIDs de grupos nem JIDs de canais @newsletter.Substituição para várias contas: channels.whatsapp.accounts.<id>.dmPolicy (e .allowFrom) têm precedência sobre os padrões no nível do canal para essa conta.Observações sobre o runtime:- os pareamentos persistem no armazenamento de permissões do canal e são mesclados com
allowFromconfigurado - a automação agendada e o fallback de destinatário do Heartbeat usam destinos de entrega explícitos ou
allowFromconfigurado; aprovações de pareamento de MD não são destinatários implícitos de Cron/Heartbeat - se nenhuma lista de permissões estiver configurada, o próprio número vinculado será permitido por padrão
- o OpenClaw nunca pareia automaticamente MDs
fromMede saída (mensagens que você envia para si mesmo pelo dispositivo vinculado)
Vinculações de ACP configuradas
O WhatsApp oferece suporte a vinculações persistentes de ACP por meio debindings[] no nível superior:
Comportamento de número pessoal e conversa consigo mesmo
Quando o próprio número vinculado também está presente emallowFrom, as proteções para conversas consigo mesmo são ativadas: ignoram confirmações de leitura nesses turnos, ignoram o comportamento de acionamento automático por JID de menção que enviaria uma notificação para você mesmo e direcionam as respostas por padrão a [{identity.name}] (ou [openclaw]) quando messages.responsePrefix não está definido.
Normalização de mensagens e contexto
Envelope de entrada e contexto da resposta
Envelope de entrada e contexto da resposta
ReplyToId, ReplyToBody, ReplyToSender, JID/E.164 do remetente) são preenchidos quando disponíveis. Se o destino citado for uma mídia que pode ser baixada, o OpenClaw a salva por meio do armazenamento normal de mídia recebida e expõe MediaPath/MediaType para que o agente possa inspecioná-la diretamente, em vez de ver apenas <media:image>.Espaços reservados de mídia e extração de localização/contato
Espaços reservados de mídia e extração de localização/contato
<media:image>, <media:video>, <media:audio>, <media:document>, <media:sticker>.Mensagens de voz autorizadas em grupos são transcritas antes do controle de menção quando o corpo contém apenas <media:audio>, portanto, pronunciar a menção ao bot na mensagem de voz pode acionar a resposta. Se a transcrição ainda não mencionar o bot, ela permanecerá no histórico pendente do grupo, em vez do espaço reservado bruto.Os corpos de localização são renderizados como texto conciso de coordenadas. Rótulos/comentários de localização e detalhes de contato/vCard são renderizados como metadados não confiáveis em bloco delimitado, não como texto em linha no prompt.Injeção do histórico pendente do grupo
Injeção do histórico pendente do grupo
- limite padrão:
50 - configuração:
channels.whatsapp.historyLimit, com fallback paramessages.groupChat.historyLimit 0desativa
[Chat messages since your last reply - for context] e [Current message - respond to this].Confirmações de leitura
Confirmações de leitura
channels.whatsapp.accounts.<id>.sendReadReceipts. Turnos de conversas consigo mesmo ignoram as confirmações de leitura mesmo quando ativadas globalmente.Entrega, divisão em partes e mídia
Divisão de texto em partes
Divisão de texto em partes
- limite padrão por parte:
channels.whatsapp.textChunkLimit = 4000 channels.whatsapp.streaming.chunkMode = "length" | "newline";newlineprioriza os limites de parágrafos (linhas em branco) e depois usa como fallback uma divisão segura por tamanho
Comportamento da mídia de saída
Comportamento da mídia de saída
- oferece suporte a cargas de imagem, vídeo, áudio (mensagem de voz PTT) e documento
- o áudio é enviado como carga
audiodo Baileys comptt: true, sendo renderizado como uma mensagem de voz push-to-talk;audioAsVoiceé preservado nas cargas de resposta para que a saída de mensagem de voz por TTS permaneça nesse caminho, independentemente do formato de origem do provedor - áudio Ogg/Opus nativo é enviado como
audio/ogg; codecs=opus; qualquer outro formato (incluindo saídas MP3/WebM do TTS do Microsoft Edge) é transcodificado comffmpegpara Ogg/Opus mono de 48 kHz antes da entrega por PTT /tts latestenvia a resposta mais recente do assistente como uma única mensagem de voz e impede envios repetidos da mesma resposta;/tts chat on|off|defaultcontrola o TTS automático da conversa atualgifPlayback: trueem envios de vídeo ativa a reprodução como GIF animadoforceDocument/asDocumentencaminha imagens, GIFs e vídeos de saída pela carga de documento do Baileys para evitar a compactação de mídia do WhatsApp, preservando o nome de arquivo e o tipo MIME resolvidos- as legendas são aplicadas ao primeiro item de mídia em uma resposta com várias mídias, exceto mensagens de voz PTT: o áudio é enviado primeiro sem legenda, e depois a legenda é enviada como uma mensagem de texto separada (os clientes do WhatsApp não renderizam legendas de mensagens de voz de forma consistente)
- a origem da mídia pode ser HTTP(S),
file://ou um caminho local
Limites de tamanho de mídia e comportamento de fallback
Limites de tamanho de mídia e comportamento de fallback
- limite para salvar mídias de entrada e enviar mídias de saída:
channels.whatsapp.mediaMaxMb(padrão:50) - substituição por conta:
channels.whatsapp.accounts.<id>.mediaMaxMb - as imagens são otimizadas automaticamente (redimensionamento/variação de qualidade) para respeitar os limites, a menos que
forceDocument/asDocumentsolicite a entrega como documento - em caso de falha no envio de mídia, o fallback do primeiro item envia um aviso de texto, em vez de descartar silenciosamente a resposta
Citação de respostas
channels.whatsapp.replyToMode controla a citação nativa de respostas (as respostas de saída citam visivelmente a mensagem recebida):
channels.whatsapp.accounts.<id>.replyToMode.
Nível de reações
channels.whatsapp.reactionLevel controla a abrangência do uso de reações com emojis pelo agente:
channels.whatsapp.accounts.<id>.reactionLevel.
Reações de confirmação
channels.whatsapp.ackReaction envia uma reação imediata ao receber uma mensagem, controlada por reactionLevel (suprimida quando "off"):
ackReaction estiver presente sem emoji, o WhatsApp usará o emoji de identidade do agente encaminhado, com fallback para ”👀” (omita ackReaction ou defina emoji: "" para não enviar confirmação); as falhas são registradas, mas não bloqueiam a entrega da resposta; o modo de grupo mentions reage apenas em turnos acionados por menção, enquanto a ativação de grupo always ignora essa verificação; o WhatsApp usa apenas channels.whatsapp.ackReaction (o messages.ackReaction legado não se aplica aqui).
Reações de status do ciclo de vida
Definamessages.statusReactions.enabled: true para permitir que o WhatsApp substitua a reação de confirmação durante um turno, em vez de manter um emoji de recebimento estático, alternando entre estados como na fila, pensando, atividade de ferramenta, Compaction, concluído e erro:
channels.whatsapp.ackReaction ainda controla a elegibilidade para mensagens diretas e grupos; o estado na fila usa o mesmo emoji efetivo das reações de confirmação simples; o WhatsApp tem um slot de reação do bot por mensagem, portanto, as atualizações do ciclo de vida substituem a reação atual no mesmo lugar; messages.removeAckAfterReply: true remove a reação de status final após o período configurado de permanência do estado concluído/erro; as categorias de emoji de ferramentas incluem tool, coding, web, deploy, build e concierge.
Várias contas e credenciais
Seleção de conta e padrões
Seleção de conta e padrões
channels.whatsapp.accounts. A seleção da conta padrão é default, se estiver presente; caso contrário, é o primeiro id de conta configurado (em ordem alfabética). Os ids de conta são normalizados internamente para consulta.Caminhos de credenciais e compatibilidade legada
Caminhos de credenciais e compatibilidade legada
- caminho de autenticação atual:
~/.openclaw/credentials/whatsapp/<accountId>/creds.json(backup:creds.json.bak) - a autenticação padrão legada em
~/.openclaw/credentials/ainda é reconhecida/migrada para fluxos da conta padrão
Comportamento de logout
Comportamento de logout
openclaw channels logout --channel whatsapp [--account <id>] limpa o estado de autenticação do WhatsApp dessa conta. Quando um gateway está acessível, o logout primeiro interrompe o listener ativo dessa conta, para que a sessão vinculada pare de receber mensagens antes da próxima reinicialização. openclaw channels remove --channel whatsapp também interrompe o listener ativo antes de desabilitar ou excluir a configuração da conta.Em diretórios de autenticação legados, oauth.json é preservado enquanto os arquivos de autenticação do Baileys são removidos.Ferramentas, ações e gravações de configuração
- O suporte a ferramentas do agente inclui a ação de reação do WhatsApp (
react). - Controles de ações:
channels.whatsapp.actions.reactions,channels.whatsapp.actions.polls(as ações existentes usamtruepor padrão),channels.whatsapp.actions.calls(padrãofalse, consulte MeowCaller acima). - As gravações de configuração iniciadas pelo canal são habilitadas por padrão; desabilite-as por meio de
channels.whatsapp.configWrites: false.
Solução de problemas
Não vinculado (QR necessário)
Não vinculado (QR necessário)
Vinculado, mas desconectado/loop de reconexão
Vinculado, mas desconectado/loop de reconexão
status=408 Request Time-out Connection was lost repetidamente, ajuste os tempos do socket do Baileys em web.whatsapp. Comece reduzindo keepAliveIntervalMs para um valor inferior ao tempo limite de inatividade da sua rede e aumentando connectTimeoutMs em conexões lentas ou com perdas:~/.openclaw/logs/whatsapp-health.log indicar Gateway inactive, mas openclaw gateway status e openclaw channels status --probe mostrarem que tudo está íntegro, execute openclaw doctor. No Linux, o doctor alerta sobre entradas legadas no crontab que invocam o script descontinuado ~/.openclaw/bin/ensure-whatsapp.sh; remova essas entradas com crontab -e — o cron pode não ter o ambiente do barramento de usuário do systemd e fazer com que esse script antigo informe incorretamente a integridade do gateway.O login por QR expira atrás de um proxy
O login por QR expira atrás de um proxy
openclaw channels login --channel whatsapp falha antes de exibir um QR utilizável, com status=408 Request Time-out ou uma desconexão de socket TLS.O login do WhatsApp Web usa o ambiente de proxy padrão do host do gateway (HTTPS_PROXY, HTTP_PROXY, variantes em minúsculas, NO_PROXY). Verifique se o processo do gateway herda as variáveis de ambiente do proxy e se NO_PROXY não corresponde a mmg.whatsapp.net.Nenhum listener ativo durante o envio
Nenhum listener ativo durante o envio
A resposta aparece na transcrição, mas não no WhatsApp
A resposta aparece na transcrição, mas não no WhatsApp
auto-reply delivery failed ou auto-reply was not accepted by WhatsApp provider.Mensagens de grupo ignoradas inesperadamente
Mensagens de grupo ignoradas inesperadamente
groupPolicy, groupAllowFrom/allowFrom, entradas da lista de permissões groups, controle por menção (requireMention + padrões de menção) e chaves duplicadas em openclaw.json (entradas posteriores do JSON5 substituem as anteriores — mantenha apenas um groupPolicy por escopo).Se channels.whatsapp.groups estiver presente, o WhatsApp ainda poderá observar mensagens de outros grupos, mas o OpenClaw as descartará antes do roteamento da sessão. Adicione o JID do grupo a channels.whatsapp.groups ou adicione groups["*"] para admitir todos os grupos, mantendo a autorização do remetente em groupPolicy/groupAllowFrom.Aviso do runtime Bun
Aviso do runtime Bun
node:sqlite usada pelo armazenamento de estado canônico, e o doctor migra serviços Bun legados para Node.Prompts de sistema
O WhatsApp oferece suporte a prompts de sistema no estilo do Telegram para grupos e conversas diretas por meio dos mapasgroups e direct.
Resolução para mensagens de grupo: primeiro, determina-se o mapa groups efetivo — se a conta definir sua própria chave groups, ela substituirá completamente o mapa raiz groups (sem mesclagem profunda). Em seguida, a consulta do prompt é executada nesse único mapa resultante:
- Prompt específico do grupo (
groups["<groupId>"].systemPrompt): usado quando a entrada do grupo existe e sua chavesystemPromptestá definida. Uma string vazia ("") suprime o curinga e não aplica nenhum prompt. - Prompt curinga do grupo (
groups["*"].systemPrompt): usado quando a entrada específica do grupo está ausente ou existe sem uma chavesystemPrompt.
direct e em direct["*"].
dms continua sendo o contêiner leve de substituição do histórico por mensagem direta (dms.<id>.historyLimit). As substituições de prompt ficam em direct.groups/direct da conta, incluindo um objeto vazio explícito, substitui o mapa raiz. Ele difere da verificação da lista de permissões de participação em grupos descrita acima, que possui uma proteção para uma única conta no caso de um groups: {} acidentalmente vazio.groups raiz para todas as contas em uma configuração com várias contas (até mesmo para contas sem um groups próprio), para impedir que um bot receba mensagens de grupos dos quais não participa. O WhatsApp não aplica essa proteção — groups/direct raiz são herdados por qualquer conta sem uma substituição própria, independentemente da quantidade de contas. Em uma configuração do WhatsApp com várias contas, defina explicitamente o mapa completo em cada conta se quiser prompts específicos por conta.
Comportamentos importantes:
channels.whatsapp.groupsé tanto um mapa de configuração por grupo quanto a lista de permissões de grupos no nível da conversa. No escopo raiz ou da conta,groups["*"]significa “todos os grupos são admitidos” nesse escopo.- Adicione um curinga
systemPromptsomente quando já quiser que esse escopo admita todos os grupos. Para manter apenas um conjunto fixo de ids de grupo elegíveis, repita o prompt em cada entrada explicitamente permitida em vez de usargroups["*"]. - A admissão do grupo e a autorização do remetente são verificações separadas.
groups["*"]amplia quais grupos chegam ao processamento de grupos; isso não autoriza todos os remetentes nesses grupos — esse controle continua sendo feito porgroupPolicy/groupAllowFrom. channels.whatsapp.directnão tem efeito colateral equivalente para mensagens diretas:direct["*"]apenas fornece uma configuração padrão depois que uma mensagem direta já foi admitida pordmPolicyem conjunto comallowFromou com as regras do armazenamento de pareamento.