Skip to main content
O WaClient recebe um objeto WaClientOptions e um logger opcional:
Apenas 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 por sessionId, 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:
Cada client pareia e reconecta de forma independente. Para o panorama completo — o que é por sessão vs compartilhado, a regra de single-writer entre processos, orçamento de memória, sharding e shutdown — veja Deploys multi-sessão.

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ão true. Defina como false para 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; emite group_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.
Os chunks são descriptografados, inflados e parseados incrementalmente — uma mensagem por vez fica viva enquanto o stream proto desce em 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.
O histórico chega como eventos 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 HTTP 405 / 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 sobrescreve mobileTransport.deviceInfo.appVersion no payload de login.
Uma quantidade de partes inválida para o transporte resolvido lança no 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.
Opções: 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).
Opções: tudo que o fetcher Web aceita (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 em whatsapp.com/android só 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 um 2.x.x.x de 4 partes e retorna o primeiro hit na página.
A string parseada precisa ter exatamente quatro partes numéricas; qualquer outra coisa lança (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 processor
  • generateThumbnail?: boolean — thumbnails de preview de imagem/vídeo
  • generateProbe?: boolean — mede largura/altura/duração
  • generateWaveform?: boolean — waveform de nota de voz (PTT)
  • generateStickerThumbnail?: boolean
  • normalizeVoiceNote?: boolean — recodifica o áudio PTT para o formato que o WhatsApp espera
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 link
  • fetchTimeoutMs?: number — quanto esperar pela página de destino
  • uploadHqThumbnail?: boolean — envia uma thumbnail de preview em alta resolução
  • allowPrivateHosts?: 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 buscados
  • userAgent?: string — User-Agent enviado na busca
  • proxy?: WaProxyTransport — aplica proxy só a este fetcher (igual a proxy.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?: number
  • maxWriteConcurrency?: number
  • flushTimeoutMs?: 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.
Cada perna aceita um WaProxyTransport, que é:
  • um dispatcher do undici (WaProxyDispatcher, por exemplo um ProxyAgent do undici) — usado para as pernas baseadas em fetch (mídia, preview de link), ou
  • um Agent http/https do Node (WaProxyAgent) — usado para a perna WebSocket (ws).
O zapo escolhe a forma certa por perna automaticamente.
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 um ProxyAgent 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

Use socks-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:
Aponte para o proxy apenas as pernas que você precisar — por exemplo, defina só ws para tunelar a conexão deixando a mídia transferir diretamente, ou vice-versa.

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

O WaClient 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 em console.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 o pino (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 — construa PinoLogger 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.
A assinatura é 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 interface Logger 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ções dangerous abaixo.

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.
Última modificação em 19 de agosto de 2026