WaClient recebe um objeto WaClientOptions e um logger opcional:
store e sessionId são obrigatórios; todo o resto tem um valor padrão sensato.
Opções obrigatórias
WaStore
obrigatório
A instância da store construída por
createStore. Mantém cada domínio por sessão (auth, signal, app-state, …).string
obrigatório
Identificador lógico da sessão — ele indexa cada domínio dentro da
store. Use uma string estável por dispositivo/conta. Trocá-lo entre execuções deixa as credenciais anteriores órfãs e força um novo pareamento.Sessões e multi-tenancy
Como cada domínio da store é indexado porsessionId, uma única store pode conter muitas contas independentes. Para rodar várias contas em um processo, crie um WaClient por sessionId sobre a mesma store:
Fingerprint do dispositivo
Estes controlam como o dispositivo aparece em Dispositivos conectados no celular:string
padrão:"'chrome'"
Id do navegador anunciado durante o pareamento (
'chrome', 'firefox', 'safari', …; veja WA_BROWSERS). Define o rótulo em Dispositivos conectados.string
Sobrescrita do id numérico de plataforma companion (
WA_COMPANION_PLATFORM_IDS). Inferido de deviceBrowser quando omitido; defina explicitamente para plataformas não-navegador.string
Nome legível do OS mostrado em Dispositivos conectados (
'Windows', 'Mac OS', 'Linux', …). Default: o OS atual do runtime.string
Versão do OS anunciada em
DeviceProps.version ('10', '14.6', …). Default: a versão detectada do OS de runtime. Defina junto com deviceOsDisplayName quando anunciar um OS que o processo não está rodando, para o nome e a versão baterem. Valores que não são dotted-numeric deixam o campo em branco — igual ao próprio WhatsApp Web.Para o MCP server as mesmas sobrescritas ficam disponíveis como as variáveis de ambiente
MCP_DEVICE_OS_DISPLAY / MCP_DEVICE_OS_VERSION — quando só a versão é setada o display name ainda é derivado do host, então fixe os dois pra manter o par anunciado consistente.Sincronização de histórico
WaHistorySyncOptions
Controla o processamento dos chunks de
historySyncNotification — tanto o bootstrap inicial que o WhatsApp envia após o pareamento quanto o backfill sob demanda disparado por message.requestHistorySync.enabled?: boolean— processa os chunks de histórico recebidos. Padrãotrue. Defina comofalsepara descartá-los silenciosamente (útil quando você não persiste mailbox/threads/contacts e o download da conversa só gastaria banda). A lib ainda envia ack do chunk para o servidor parar de re-enviar, igual ao wa-web.requireFullSync?: boolean— solicita o arquivo completo em vez de apenas os chats recentes.groupBundles?: boolean— opta por baixar o bundle de histórico de grupo que um membro pode compartilhar depois que alguém entra em um grupo; emitegroup_history_bundle. Off por padrão — um bundle é mídia que um terceiro empurra para esta conta sem solicitação, então o fetch é opt-in. Bundles endereçados a outros membros são descartados de qualquer forma. Veja Grupos → compartilhando histórico do grupo.
conversations, então um chat grande que materializaria em centenas de MB de objetos JS fica plano. Bundles de histórico de grupo passam pelo mesmo tratamento. Não tem knob voltado ao consumidor; o pico de memória durante o ingest simplesmente deixou de acompanhar o tamanho do chunk.history_sync_chunk.
Timeouts
Todos em milissegundos; os padrões são ajustados para produção.Versão do WhatsApp
O zapo embarca uma versão de produção testada por transporte. Ocasionalmente o WhatsApp rejeita clients antigos durante o handshake noise com HTTP405 / failure_client_too_old. Você tem três opções para se recuperar.
string | () => string | Promise<string>
Sobrescreve a string de versão anunciada pelo client. Aceita um literal ou um resolver chamado uma vez por
connect() — útil para buscar a versão atual sob demanda sem recriar o client. O formato aceito depende do transporte resolvido para o connect:- Web aceita uma versão de 3 a 5 partes (
2.3000.x[.y.z]); as 4ª e 5ª partes, quando fornecidas, são anunciadas no payload noise. - Mobile aceita exatamente uma app version Android de 4 partes (
2.26.x.y); ela sobrescrevemobileTransport.deviceInfo.appVersionno payload de login.
connect().boolean
padrão:"false"
Quando
true, ao receber failure_client_too_old o client emite um warning, busca a versão atual para o transporte ativo (fetchLatestWaWebVersion() para Web, fetchLatestWaMobileVersion() para Mobile), aplica como override de uso único e reconecta automaticamente. Em Mobile, o override é aplicado atualizando deviceInfo.appVersion para o próximo connect. Trate como paliativo até atualizar o zapo — o default embarcado continua sendo o caminho recomendado.fetchLatestWaWebVersion()
Faz scraping do client_revision atual em web.whatsapp.com/sw.js e retorna uma string de versão no formato 2.3000.x aceito por version em uma sessão Web.
timeoutMs (padrão 10s), proxy (apenas dispatcher do undici — o fetch global não honra http.Agent), signal, userAgent, headers e uma override de fetch para testes. Erros de rede e parsing são lançados — envolva em try/catch se quiser cair no default embarcado.
fetchLatestWaMobileVersion()
Faz scraping da versão atual do WhatsApp para Android em uma página pública de app-listing e retorna uma string 2.26.x.y de 4 partes adequada para version em uma sessão Mobile (ou como override para mobileTransport.deviceInfo.appVersion).
timeoutMs, proxy, signal, userAgent, headers, fetch) mais:
url?: string— sobrescreve a página a ser lida. A fonte padrão é um mirror público de app-listing porque a própria página do WhatsApp emwhatsapp.com/androidsó mostra a versão mínima obsoleta; re-aponte se o layout mudar ou for inalcançável da sua rede.versionPattern?: RegExp— sobrescreve o regex de extração. Precisa expor a versão no capture group 1. O padrão combina com um2.x.x.xde 4 partes e retorna o primeiro hit na página.
invalid wa-mobile version parsed from page). Erros de rede e parsing são lançados — envolva em try/catch se quiser cair em uma versão hardcoded conhecida.
Presença ao conectar
boolean
padrão:"false"
false(padrão) — anuncia como indisponível. Igual ao WhatsApp Web quando a aba não está em foco e mantém bots headless invisíveis por padrão. Com isso desligado, você continua recebendo notificações de mensagens enquanto está “offline”.true— anuncia o client como online (igual ao WhatsApp Web com a aba em foco no momento do login).
Linking com passkey
WaShortcakeAssertionSigner
Signer WebAuthn externo para o handshake Shortcake de passkey forçado pelo servidor. Chamado com o
PublicKeyCredentialRequestOptions bruto (Uint8Array) que o servidor emitiu; deve retornar { credentialId, webauthnAssertion }. A source da credencial (authenticator real / virtual, relay) fica fora da lib.Sem isso, uma conta que receber um passkey prologue forçado pelo servidor emite auth_passkey_required com hasSigner: false e o link fica parado — veja o deep dive de reverse engineering pro detalhe no nível do fio.Addons (reações, votos em enquetes)
{ autoDecrypt?: boolean, persistAllSecrets?: boolean }
padrão:"{ autoDecrypt: true, persistAllSecrets: false }"
Addons criptografados (votos em enquetes, reações, edições de mensagem, …) são descriptografados automaticamente e emitidos como eventos tipados
message_addon. Defina autoDecrypt: false para recebê-los criptografados e descriptografar você mesmo via client.message.tryDecryptAddon(event). O secret da mensagem-pai é procurado no cache messageSecret primeiro, depois no store messages.persistAllSecrets: true persiste o secret de 32 bytes de toda mensagem enviada e recebida, não só as de poll / event / bot-prompt que a lib sabe que terão follow-up. Addons criptografados cujo pai pode ser qualquer tipo de mensagem — reações, comentários, edições via secretEncryptedMessage — precisam do secret do pai para decifrar; sem essa flag, esses pais só continuam decifráveis depois de um restart quando o arquivo messages completo é persistente. Use para manter a decifragem possível guardando apenas o secret (messages: 'none').Sem efeito quando o cache messageSecret é 'none' — toda escrita de secret cai no noop store e é silenciosamente descartada. Com o provider 'memory' default funciona pelo tempo de vida do processo, mas perde no restart e fica limitado ao LRU e ao TTL messageSecretMs do cache; aponte messageSecret para um backend persistente para manter os secrets entre restarts.Mídia
WaMediaOptions
Processamento de mídia. Passe um
processor (de @zapo-js/media-utils) para gerar thumbnails/previews, medir dimensões e durações e construir waveforms de notas de voz antes do upload — e ligue/desligue cada etapa. Sem um processor a mídia ainda é enviada, só sem esse processamento. Veja o guia de mídia para a configuração completa.processor?: WaMediaProcessor— a instância do processorgenerateThumbnail?: boolean— thumbnails de preview de imagem/vídeogenerateProbe?: boolean— mede largura/altura/duraçãogenerateWaveform?: boolean— waveform de nota de voz (PTT)generateStickerThumbnail?: booleannormalizeVoiceNote?: boolean— recodifica o áudio PTT para o formato que o WhatsApp espera
Previews de link
WaLinkPreviewOptions
Configuração global do fetcher embutido de preview de link, usado ao enviar texto que contém uma URL. Sobrescreva por mensagem com a opção de envio
linkPreview.enabled?: boolean— liga ou desliga globalmente a busca automática de preview de linkfetchTimeoutMs?: number— quanto esperar pela página de destinouploadHqThumbnail?: boolean— envia uma thumbnail de preview em alta resoluçãoallowPrivateHosts?: boolean— permite buscar endereços privados/loopback (desligado por padrão, como proteção contra SSRF)maxHtmlBytes?: number/maxThumbnailBytes?: number— limites de tamanho para o HTML e a imagem buscadosuserAgent?: string— User-Agent enviado na buscaproxy?: WaProxyTransport— aplica proxy só a este fetcher (igual aproxy.linkPreview)fetcher?: WaLinkPreviewFetcher— substitui o fetcher padrão por completo (ex.: seu próprio pipeline de scraping)
Eventos de chat
{ emitSnapshotMutations?: boolean }
Defina
emitSnapshotMutations: true para reemitir eventos mutation para cada mudança vista durante uma sincronização de snapshot de app-state. Desligado por padrão, já que mutações de snapshot representam estado histórico, não mudanças ao vivo.Persistência write-behind
WaWriteBehindOptions
Agrupa as mensagens recebidas em lotes antes de descarregá-las nas stores
messages / threads / contacts.maxPendingKeys?: numbermaxWriteConcurrency?: numberflushTimeoutMs?: number
Proxy
WaClientProxyOptions
Roteie cada perna através de um proxy de forma independente:
ws— a conexão WebSocket.mediaUpload/mediaDownload— transferências de mídia.linkPreview— o fetcher padrão de preview de link.
WaProxyTransport, que é:
- um dispatcher do undici (
WaProxyDispatcher, por exemplo umProxyAgentdo undici) — usado para as pernas baseadas emfetch(mídia, preview de link), ou - um
Agenthttp/httpsdo Node (WaProxyAgent) — usado para a perna WebSocket (ws).
A perna
ws requer o pacote ws, porque o WebSocket nativo do runtime não consegue aceitar um Agent HTTP. Sem um proxy, nenhum pacote extra é necessário.Proxy HTTP / HTTPS
Use umProxyAgent do undici (um dispatcher) para as pernas de mídia/preview de link, e um https-proxy-agent (um http.Agent) para a perna ws:
Proxy SOCKS
Usesocks-proxy-agent (funciona como um http.Agent para todas as pernas, incluindo ws):
Hosts IPv4 e IPv6
O host do proxy pode ser um domínio ou um literal de IP. Endereços IPv6 devem ser envolvidos em colchetes:Limpeza da store no logout
WaLogoutStoreClearOptions
Controle por domínio do que o
logout() apaga.Por padrão, o arquivo da mailbox (messages, threads, contacts) é preservado para que o usuário mantenha seu histórico ao reparear. Todos os outros domínios (credenciais, estado Signal, app-state, caches, privacy tokens) são limpos para começar o próximo pareamento do zero. true / false explícitos sempre vencem o padrão.Logging
OWaClient aceita um Logger como segundo argumento do construtor. Se você omitir, um ConsoleLogger('info') padrão é usado. Níveis, do mais baixo ao mais alto: trace, debug, info, warn, error.
Duas implementações vêm com o pacote.
ConsoleLogger
Sem dependências. Escreve registros estruturados emconsole.log / console.warn / console.error. Bom para desenvolvimento, testes e funções serverless onde você não consegue adicionar um transport de logger.
createPinoLogger
Factory async que carrega dinamicamente opino (e o pino-pretty quando pretty: true), configura e envolve no adapter PinoLogger. Lança optional dependency "pino" is not installed quando o pino não está presente — instale com npm i pino pino-pretty.
PinoLogger (traga o seu Pino)
Se você já configura Pino centralmente — child loggers, transports customizados, destinos em arquivo — construaPinoLogger diretamente para envolver sua instância existente. A factory é uma conveniência; a classe é o adapter de fato, e usá-la evita o import dinâmico do pino.
new PinoLogger(logger, level = 'info'). O nível é encaminhado pra logger.level e usado como o level reportado pelo adapter.
Logger customizado
Precisa de um sink que as implementações nativas não cobrem — Datadog, OpenTelemetry, syslog, um pipeline de observabilidade interno? Implemente a interfaceLogger e passe a instância pro WaClient. A interface é pequena:
LogLevel é 'trace' | 'debug' | 'info' | 'warn' | 'error'. A biblioteca chama os cinco métodos de level diretamente — não há uma camada de level-gating à frente, então sua implementação é responsável por filtrar contra this.level se quiser pular chamadas baratas.
Um exemplo mínimo que encaminha para um sink externo e rastreia bindings por child():
child() é usado internamente para anexar bindings por componente (ex.: { component: 'noise' }, { component: 'signal', sessionId }). Retornar uma nova instância com bindings mesclados — em vez de mutar — mantém esses tags com escopo no subsistema que os produziu.Plugins
readonly WaClientPluginDefinition[]
Plugins opcionais de
WaClient — hooks de comportamento e/ou coordinators expostos em client[exposeAs]. Autorados com defineWaClientPlugin. O plugin de chamadas de voz (@zapo-js/voip) é a implementação de referência; veja a página do sistema de plugins para saber como conectar e autorar plugins.Opções avançadas
Raramente necessárias — listadas para completude.chatSocketUrls?: readonly string[]— sobrescreve a lista de endpoints WebSocket de chat do WhatsApp (ex.: rotear por um servidor falso em testes, ou fixar um edge específico).privacyToken?: WaPrivacyTokenOptions— ajusta a emissão de trusted-contact-token (TC token): durações e número de buckets.testHooks?: WaClientTestHooks— fixtures só para testes (ex.: um root CA Noise customizado). Eles não burlam nenhuma verificação de segurança; para realmente pular uma checagem, use as opçõesdangerousabaixo.
Opções perigosas
As flags
dangerous desabilitam, cada uma, uma verificação de segurança que o caminho de produção aplica (verificação de assinatura, checagens de MAC do app-state, …). Elas existem para testes contra um servidor falso. Nunca as habilite em produção.