WhatsApp (canale Web)

Stato: pronto per la produzione via WhatsApp Web (Baileys). Il Gateway possiede le sessioni collegate.

Setup rapido

Step 1: Configura la policy di accesso WhatsApp

{
  channels: {
    whatsapp: {
      dmPolicy: "pairing",
      allowFrom: ["+15551234567"],
      groupPolicy: "allowlist",
      groupAllowFrom: ["+15551234567"],
    },
  },
}

Step 2: Collega WhatsApp (QR)

openclaw channels login --channel whatsapp
Per un account specifico:
openclaw channels login --channel whatsapp --account work

Step 3: Avvia il gateway

openclaw gateway

Step 4: Approva la prima richiesta di pairing (se in modalita pairing)

openclaw pairing list whatsapp
openclaw pairing approve whatsapp <CODE>
Le richieste di pairing scadono dopo 1 ora. Le richieste in sospeso sono limitate a 3 per canale.

Nota: OpenClaw consiglia di usare WhatsApp su un numero separato quando possibile. (I metadati del canale e il flusso di onboarding sono ottimizzati per quella configurazione, ma anche i setup con numero personale sono supportati.)

Pattern di deployment

Numero dedicato (consigliato)
La modalita operativa piu pulita:

- identita WhatsApp separata per OpenClaw
- allowlist DM e confini di routing piu chiari
- minore possibilita di confusione con self-chat

Pattern policy minimale:

```json5
{
  channels: {
    whatsapp: {
      dmPolicy: "allowlist",
      allowFrom: ["+15551234567"],
    },
  },
}
```
Fallback numero personale
L'onboarding supporta la modalita numero personale e scrive una baseline compatibile con self-chat:

- `dmPolicy: "allowlist"`
- `allowFrom` include il tuo numero personale
- `selfChatMode: true`

In runtime, le protezioni self-chat si basano sul numero self collegato e `allowFrom`.
Ambito canale solo WhatsApp Web
Il canale della piattaforma di messaggistica e basato su WhatsApp Web (`Baileys`) nell'architettura attuale dei canali OpenClaw.

Non esiste un canale di messaggistica WhatsApp Twilio separato nel registro dei canali chat integrati.

Modello runtime

  • Il Gateway possiede il socket WhatsApp e il loop di riconnessione.
  • Gli invii in uscita richiedono un listener WhatsApp attivo per l’account target.
  • Le chat di stato e broadcast sono ignorate (@status, @broadcast).
  • Le chat dirette usano le regole di sessione DM (session.dmScope; il main predefinito collassa i DM nella sessione principale dell’agent).
  • Le sessioni di gruppo sono isolate (agent:<agentId>:whatsapp:group:<jid>).

Controllo degli accessi e attivazione

Policy DM

`channels.whatsapp.dmPolicy` controlla l'accesso alle chat dirette:

- `pairing` (predefinito)
- `allowlist`
- `open` (richiede `allowFrom` che includa `"*"`)
- `disabled`

`allowFrom` accetta numeri in stile E.164 (normalizzati internamente).

Sovrascrittura multi-account: `channels.whatsapp.accounts.<id>.dmPolicy` (e `allowFrom`) hanno la precedenza sui default a livello canale per quell'account.

Dettagli comportamento runtime:

- i pairing sono persistiti nel channel allow-store e uniti con `allowFrom` configurato
- se nessuna allowlist e configurata, il numero self collegato e consentito per impostazione predefinita
- i DM `fromMe` in uscita non vengono mai auto-paired

Policy gruppi + allowlist

L'accesso ai gruppi ha due livelli:

1. **Allowlist appartenenza gruppo** (`channels.whatsapp.groups`)
   - se `groups` e omesso, tutti i gruppi sono idonei
   - se `groups` e presente, agisce come allowlist dei gruppi (`"*"` consentito)

2. **Policy mittente gruppi** (`channels.whatsapp.groupPolicy` + `groupAllowFrom`)
   - `open`: allowlist mittente bypassata
   - `allowlist`: il mittente deve corrispondere a `groupAllowFrom` (o `*`)
   - `disabled`: blocca tutti i messaggi di gruppo in ingresso

Fallback allowlist mittente:

- se `groupAllowFrom` non e impostato, il runtime torna a `allowFrom` quando disponibile
- le allowlist mittente sono valutate prima dell'attivazione per menzione/risposta

Nota: se non esiste alcun blocco `channels.whatsapp`, il fallback runtime della policy di gruppo e `allowlist` (con un avviso nel log), anche se `channels.defaults.groupPolicy` e impostato.

Menzioni + /activation

Le risposte nei gruppi richiedono menzione per impostazione predefinita.

Il rilevamento menzione include:

- menzioni WhatsApp esplicite dell'identita del bot
- pattern regex di menzione configurati (`agents.list[].groupChat.mentionPatterns`, fallback `messages.groupChat.mentionPatterns`)
- rilevamento implicito di risposta-al-bot (il mittente della risposta corrisponde all'identita del bot)

Nota di sicurezza:

- la citazione/risposta soddisfa solo il gating menzione; **non** concede autorizzazione al mittente
- con `groupPolicy: "allowlist"`, i mittenti non in allowlist sono comunque bloccati anche se rispondono al messaggio di un utente in allowlist

Comando di attivazione a livello sessione:

- `/activation mention`
- `/activation always`

`activation` aggiorna lo stato della sessione (non il config globale). E riservato al proprietario.

Comportamento numero personale e self-chat

Quando il numero self collegato e presente anche in allowFrom, le protezioni self-chat di WhatsApp si attivano:

  • salta le conferme di lettura per i turni di self-chat
  • ignora il comportamento auto-trigger del mention-JID che altrimenti ti menzionerebbe
  • se messages.responsePrefix non e impostato, le risposte self-chat usano per impostazione predefinita [{identity.name}] o [openclaw]

Normalizzazione messaggi e contesto

Envelope in ingresso + contesto di risposta
I messaggi WhatsApp in ingresso sono wrappati nell'envelope in ingresso condiviso.

Se esiste una risposta citata, il contesto viene aggiunto in questa forma:

```text
[Replying to <sender> id:<stanzaId>]
<quoted body or media placeholder>
[/Replying]
```

I campi metadati di risposta sono anche popolati quando disponibili (`ReplyToId`, `ReplyToBody`, `ReplyToSender`, JID/E.164 del mittente).
Placeholder media ed estrazione posizione/contatti
I messaggi in ingresso solo media sono normalizzati con placeholder come:

- `<media:image>`
- `<media:video>`
- `<media:audio>`
- `<media:document>`
- `<media:sticker>`

I payload di posizione e contatti sono normalizzati in contesto testuale prima del routing.
Iniezione storico gruppi in sospeso
Per i gruppi, i messaggi non elaborati possono essere bufferizzati e iniettati come contesto quando il bot viene finalmente attivato.

- limite predefinito: `50`
- config: `channels.whatsapp.historyLimit`
- fallback: `messages.groupChat.historyLimit`
- `0` disabilita

Marcatori di iniezione:

- `[Chat messages since your last reply - for context]`
- `[Current message - respond to this]`
Conferme di lettura
Le conferme di lettura sono abilitate per impostazione predefinita per i messaggi WhatsApp in ingresso accettati.

Disabilita globalmente:

```json5
{
  channels: {
    whatsapp: {
      sendReadReceipts: false,
    },
  },
}
```

Sovrascrittura per account:

```json5
{
  channels: {
    whatsapp: {
      accounts: {
        work: {
          sendReadReceipts: false,
        },
      },
    },
  },
}
```

I turni di self-chat saltano le conferme di lettura anche quando abilitate globalmente.

Consegna, segmentazione e media

Segmentazione testo
- limite segmento predefinito: `channels.whatsapp.textChunkLimit = 4000`
- `channels.whatsapp.chunkMode = "length" | "newline"`
- la modalita `newline` preferisce i confini di paragrafo (righe vuote), poi torna alla segmentazione sicura per lunghezza
Comportamento media in uscita
- supporta payload immagine, video, audio (nota vocale PTT) e documento
- `audio/ogg` viene riscritto in `audio/ogg; codecs=opus` per compatibilita con le note vocali
- la riproduzione GIF animata e supportata via `gifPlayback: true` sugli invii video
- le didascalie sono applicate al primo elemento media quando si inviano payload multi-media
- la sorgente media puo essere HTTP(S), `file://` o percorsi locali
Limiti dimensione media e comportamento fallback
- limite salvataggio media in ingresso: `channels.whatsapp.mediaMaxMb` (predefinito `50`)
- limite invio media in uscita: `channels.whatsapp.mediaMaxMb` (predefinito `50`)
- sovrascritture per account usano `channels.whatsapp.accounts.<accountId>.mediaMaxMb`
- le immagini sono auto-ottimizzate (ridimensionamento/sweep qualita) per rientrare nei limiti
- in caso di fallimento dell'invio media, il fallback del primo elemento invia un avviso testuale invece di eliminare silenziosamente la risposta

Reazioni di conferma

WhatsApp supporta reazioni di conferma immediate alla ricezione in ingresso via channels.whatsapp.ackReaction.

{
  channels: {
    whatsapp: {
      ackReaction: {
        emoji: "👀",
        direct: true,
        group: "mentions", // always | mentions | never
      },
    },
  },
}

Note sul comportamento:

  • inviate immediatamente dopo l’accettazione del messaggio in ingresso (pre-risposta)
  • i fallimenti sono registrati ma non bloccano la consegna normale della risposta
  • la modalita gruppo mentions reagisce sui turni attivati da menzione; l’attivazione gruppo always agisce come bypass per questo controllo
  • WhatsApp usa channels.whatsapp.ackReaction (il legacy messages.ackReaction non viene usato qui)

Multi-account e credenziali

Selezione account e predefiniti
- gli id account provengono da `channels.whatsapp.accounts`
- selezione account predefinito: `default` se presente, altrimenti il primo id account configurato (ordinato)
- gli id account sono normalizzati internamente per il lookup
Percorsi credenziali e compatibilita legacy
- percorso auth attuale: `~/.openclaw/credentials/whatsapp/<accountId>/creds.json`
- file backup: `creds.json.bak`
- l'auth legacy predefinita in `~/.openclaw/credentials/` e ancora riconosciuta/migrata per i flussi dell'account predefinito
Comportamento logout
`openclaw channels logout --channel whatsapp [--account <id>]` cancella lo stato di autenticazione WhatsApp per quell'account.

Nelle directory auth legacy, `oauth.json` e preservato mentre i file auth Baileys sono rimossi.

Strumenti, azioni e scritture configurazione

  • Il supporto strumenti dell’agent include l’azione reazione WhatsApp (react).
  • Gate delle azioni:
    • channels.whatsapp.actions.reactions
    • channels.whatsapp.actions.polls
  • Le scritture di configurazione iniziate dal canale sono abilitate per impostazione predefinita (disabilita via channels.whatsapp.configWrites=false).

Risoluzione problemi

Non collegato (QR necessario)
Sintomo: lo stato del canale riporta non collegato.

Soluzione:

```bash
openclaw channels login --channel whatsapp
openclaw channels status
```
Collegato ma disconnesso / loop di riconnessione
Sintomo: account collegato con disconnessioni ripetute o tentativi di riconnessione.

Soluzione:

```bash
openclaw doctor
openclaw logs --follow
```

Se necessario, ricollega con `channels login`.
Nessun listener attivo per l'invio
Gli invii in uscita falliscono immediatamente quando non esiste un listener gateway attivo per l'account target.

Assicurati che il gateway sia in esecuzione e che l'account sia collegato.
Messaggi di gruppo ignorati inaspettatamente
Controlla in questo ordine:

- `groupPolicy`
- `groupAllowFrom` / `allowFrom`
- voci allowlist `groups`
- gating menzione (`requireMention` + pattern di menzione)
- chiavi duplicate in `openclaw.json` (JSON5): le voci successive sovrascrivono le precedenti, quindi mantieni un singolo `groupPolicy` per ambito
Avviso runtime Bun
Il runtime del gateway WhatsApp dovrebbe usare Node. Bun e segnalato come incompatibile per l'operazione stabile del gateway WhatsApp/Telegram.

Riferimenti configurazione

Riferimento primario:

Campi WhatsApp ad alto segnale:

  • accesso: dmPolicy, allowFrom, groupPolicy, groupAllowFrom, groups
  • consegna: textChunkLimit, chunkMode, mediaMaxMb, sendReadReceipts, ackReaction
  • multi-account: accounts.<id>.enabled, accounts.<id>.authDir, sovrascritture a livello account
  • operazioni: configWrites, debounceMs, web.enabled, web.heartbeatSeconds, web.reconnect.*
  • comportamento sessione: session.dmScope, historyLimit, dmHistoryLimit, dms.<id>.historyLimit

Correlati