Instalación
openclaw onboard y openclaw channels add --channel whatsapp solicitan instalar el plugin la primera vez que lo seleccionas; openclaw channels login --channel whatsapp ofrece el mismo flujo de instalación si falta el plugin. Los checkouts de desarrollo usan la ruta local del plugin; las instalaciones estables/beta instalan primero @openclaw/whatsapp desde ClawHub, con fallback a npm. El runtime de WhatsApp se distribuye fuera del paquete npm principal de OpenClaw, por lo que sus dependencias de runtime permanecen con el plugin externo. Instalación manual:
@openclaw/whatsapp) solo para el fallback del registro; fija una versión exacta solo para una instalación reproducible.
Emparejamiento
Solución de problemas de canales
Configuración del Gateway
Configuración rápida
Vincular WhatsApp (QR)
Patrones de despliegue
Número dedicado (recomendado)
Número dedicado (recomendado)
- identidad de WhatsApp separada para OpenClaw
- listas de permitidos de DM y límites de enrutamiento más claros
- menor probabilidad de confusión por autochat
Fallback de número personal
Fallback de número personal
dmPolicy: "allowlist", allowFrom con tu propio número incluido, selfChatMode: true. Las protecciones de autochat en runtime se basan en el número propio vinculado más allowFrom.Modelo de runtime
- El Gateway es propietario del socket de WhatsApp y del bucle de reconexión.
- Un watchdog rastrea dos señales de forma independiente: la actividad sin procesar del transporte de WhatsApp Web y la actividad de mensajes de la aplicación. Una sesión silenciosa pero conectada no se reinicia solo porque no haya llegado ningún mensaje recientemente; fuerza la reconexión solo cuando los frames de transporte dejan de llegar durante una ventana interna fija (no configurable por el usuario) o los mensajes de la aplicación permanecen en silencio más allá de 4 veces el timeout normal de mensajes. Justo después de una reconexión de una sesión recientemente activa, esa primera ventana usa el timeout normal de mensajes más corto en lugar de la ventana de 4 veces. OpenClaw puede responder automáticamente a mensajes sin conexión que Baileys entrega al inicio de esa reconexión, limitado por la duración de deduplicación de los ID de mensajes entrantes; el arranque inicial conserva la protección corta contra historial obsoleto.
- Los tiempos del socket de Baileys son explícitos bajo
web.whatsapp.*:keepAliveIntervalMs(intervalo de ping de la aplicación),connectTimeoutMs(timeout del handshake de apertura),defaultQueryTimeoutMs(esperas de consultas de Baileys, además de los timeouts de envío/presencia salientes y confirmación de lectura entrante de OpenClaw). - Los envíos salientes requieren un listener de WhatsApp activo para la cuenta de destino; de lo contrario, los envíos fallan rápidamente.
- Los envíos a grupos adjuntan metadatos nativos de mención para tokens
@+<digits>y@<digits>(en texto y pies de medios) cuando el token coincide con los metadatos actuales de participantes, incluidos grupos respaldados por LID. - Los chats de estado y difusión (
@status,@broadcast) se ignoran. - Los chats directos usan reglas de sesión de DM (
session.dmScope; el valor predeterminadomaincolapsa los DM en la sesión principal del agente). Las sesiones de grupo se aíslan por JID (agent:<agentId>:whatsapp:group:<jid>). - Los canales/boletines de WhatsApp pueden ser destinos salientes explícitos mediante su JID nativo
@newsletter, usando metadatos de sesión de canal (agent:<agentId>:whatsapp:channel:<jid>) en lugar de semántica de DM. - El transporte de WhatsApp Web respeta las variables de entorno de proxy estándar en el host del Gateway (
HTTPS_PROXY,HTTP_PROXY,NO_PROXY, variantes en minúsculas). Prefiere la configuración de proxy a nivel de host sobre los ajustes por canal. - Con
messages.removeAckAfterReplyhabilitado, OpenClaw borra la reacción de acuse una vez que se entrega una respuesta visible.
Llamar al solicitante actual con MeowCaller (experimental)
El plugin puede exponerwhatsapp_call en turnos de agente originados en WhatsApp. Usa MeowCaller para realizar una llamada de voz de WhatsApp al solicitante autorizado actual y reproducir un mensaje TTS de OpenClaw después de que responda. La herramienta no tiene parámetro de número de destino, por lo que un prompt no puede redirigir la llamada. Deshabilitado de forma predeterminada.
Habilitar llamadas experimentales
actions.calls: true a la configuración del canal de WhatsApp y reinicia el Gateway:false, OpenClaw no expone la herramienta whatsapp_call.Instalar la CLI de MeowCaller revisada
meowcaller en el PATH del host del Gateway. Hasta que se fusione MeowCaller PR #7, compila la rama revisada:$HOME/.local/bin esté en el PATH del servicio del Gateway. Esta revisión tiene comandos explícitos pair y notify solo de envío; notify no abre micrófono, altavoz, dispositivo de vídeo ni captura de diagnóstico. No sustituyas el comando play de la CLI de ejemplo upstream.Emparejar el dispositivo vinculado de MeowCaller
whatsapp_call informa del directorio de estado específico de la cuenta y del comando de emparejamiento). Para la cuenta predeterminada:MeowCaller linked device ready. Mantén wa-voip.db privado: es la sesión de MeowCaller. Las cuentas no predeterminadas obtienen su propia ruta de almacén desde la acción de estado; en Windows, ejecuta su comando de PowerShell.Configurar TTS y llamar desde WhatsApp
Call me and say the build finished. La herramienta resuelve el remitente desde contexto entrante de confianza, sintetiza un archivo WAV temporal privado, ejecuta MeowCaller durante una ventana de llamada acotada y elimina el archivo de audio después. OpenClaw pasa explícitamente el almacén de la cuenta, espera un estado de salida cero después de responder/reproducir/colgar y trata un timeout o una salida distinta de cero como una llamada de herramienta fallida.Prompts de aprobación
WhatsApp puede renderizar prompts de aprobación de ejecución y plugin como reacciones👍/👎, controladas por la configuración de reenvío de aprobaciones de nivel superior:
approvals.exec y approvals.plugin son independientes; habilitar WhatsApp como canal solo vincula el transporte y no envía nada salvo que la familia de aprobaciones correspondiente esté habilitada y enrutada allí. El modo de sesión entrega aprobaciones nativas con emoji solo para aprobaciones que se originan en WhatsApp. El modo de destino usa la canalización compartida de reenvío para destinos explícitos y no crea un fanout de DM de aprobador separado.
Las reacciones de aprobación de WhatsApp requieren aprobadores explícitos en allowFrom (o "*"). defaultTo establece destinos predeterminados ordinarios de mensajes, no una lista de aprobadores. Los comandos manuales /approve siguen pasando por la ruta normal de autorización de remitente de WhatsApp antes de la resolución de la aprobación.
Hooks de Plugin y privacidad
Los mensajes entrantes de WhatsApp pueden llevar contenido personal, números de teléfono, identificadores de grupo, nombres de remitentes y campos de correlación de sesión. WhatsApp no difunde payloads de hookmessage_received entrantes a plugins salvo que lo actives:
channels.whatsapp.accounts.<id>.pluginHooks.messageReceived. Habilita esto solo para plugins en los que confíes con contenido e identificadores entrantes de WhatsApp.
Control de acceso y activación
- Política de DM
- Política de grupos y listas de permitidos
- Menciones y /activation
channels.whatsapp.dmPolicy:| Valor | Comportamiento |
|---|---|
pairing (predeterminado) | Los remitentes desconocidos solicitan emparejamiento; el propietario aprueba |
allowlist | Solo se admiten remitentes de allowFrom |
open | Requiere que allowFrom incluya "*" |
disabled | Bloquea todos los DM |
allowFrom acepta números de estilo E.164 (normalizados internamente). Es solo una lista de control de acceso de remitentes de DM; no bloquea envíos salientes explícitos a JID de grupos ni JID de canal @newsletter.Anulación para varias cuentas: channels.whatsapp.accounts.<id>.dmPolicy (y .allowFrom) tienen prioridad sobre los valores predeterminados de nivel de canal para esa cuenta.Notas de runtime:- los emparejamientos persisten en el almacén de permitidos del canal y se fusionan con el
allowFromconfigurado - la automatización programada y la reserva de destinatarios de Heartbeat usan destinos de entrega explícitos o el
allowFromconfigurado; las aprobaciones de emparejamiento por DM no son destinatarios implícitos de Cron/Heartbeat - si no se configura ninguna lista de permitidos, el número propio vinculado se permite de forma predeterminada
- OpenClaw nunca empareja automáticamente DMs salientes
fromMe(mensajes que te envías a ti mismo desde el dispositivo vinculado)
Enlaces ACP configurados
WhatsApp admite enlaces ACP persistentes mediantebindings[] de nivel superior:
Comportamiento de número personal y chat propio
Cuando el número propio vinculado también está presente enallowFrom, se activan las protecciones de chat propio: se omiten confirmaciones de lectura para turnos de chat propio, se ignora el comportamiento de activación automática por JID de mención que te haría ping a ti mismo, y las respuestas predeterminadas usan [{identity.name}] (o [openclaw]) cuando messages.responsePrefix no está definido.
Normalización de mensajes y contexto
Envoltorio entrante y contexto de respuesta
Envoltorio entrante y contexto de respuesta
ReplyToId, ReplyToBody, ReplyToSender, JID/E.164 del remitente) se rellenan cuando están disponibles. Si el destino citado es contenido multimedia descargable, OpenClaw lo guarda mediante el almacén normal de multimedia entrante y expone MediaPath/MediaType para que el agente pueda inspeccionarlo directamente en lugar de ver solo <media:image>.Marcadores de posición multimedia y extracción de ubicación/contacto
Marcadores de posición multimedia y extracción de ubicación/contacto
<media:image>, <media:video>, <media:audio>, <media:document>, <media:sticker>.Las notas de voz de grupo autorizadas se transcriben antes del control de mención cuando el cuerpo es solo <media:audio>, de modo que decir la mención del bot en la nota de voz puede activar la respuesta. Si la transcripción aun así no menciona al bot, permanece en el historial de grupo pendiente en lugar del marcador de posición sin procesar.Los cuerpos de ubicación se representan como texto breve de coordenadas. Las etiquetas/comentarios de ubicación y los detalles de contacto/vCard se representan como metadatos no confiables en bloque delimitado, no como texto de prompt en línea.Inyección de historial de grupo pendiente
Inyección de historial de grupo pendiente
- límite predeterminado:
50 - configuración:
channels.whatsapp.historyLimit, reservamessages.groupChat.historyLimit 0desactiva
[Chat messages since your last reply - for context] y [Current message - respond to this].Confirmaciones de lectura
Confirmaciones de lectura
channels.whatsapp.accounts.<id>.sendReadReceipts. Los turnos de chat propio omiten confirmaciones de lectura incluso cuando están activadas globalmente.Entrega, fragmentación y multimedia
Fragmentación de texto
Fragmentación de texto
- límite de fragmento predeterminado:
channels.whatsapp.textChunkLimit = 4000 channels.whatsapp.chunkMode = "length" | "newline";newlineprefiere límites de párrafo (líneas en blanco) y luego recurre a fragmentación segura por longitud
Comportamiento de multimedia saliente
Comportamiento de multimedia saliente
- admite cargas útiles de imagen, video, audio (nota de voz PTT) y documento
- el audio se envía como la carga útil
audiode Baileys conptt: true, representándose como una nota de voz push-to-talk;audioAsVoicese conserva en cargas útiles de respuesta para que la salida de nota de voz TTS permanezca en esta ruta independientemente del formato de origen del proveedor - el audio Ogg/Opus nativo se envía como
audio/ogg; codecs=opus; cualquier otra cosa (incluida la salida MP3/WebM de TTS de Microsoft Edge) se transcodifica conffmpega Ogg/Opus mono de 48 kHz antes de la entrega PTT /tts latestenvía la última respuesta del asistente como una nota de voz y suprime envíos repetidos para la misma respuesta;/tts chat on|off|defaultcontrola el TTS automático para el chat actualgifPlayback: trueen envíos de video habilita la reproducción de GIF animadoforceDocument/asDocumentenruta imágenes, GIFs y videos salientes mediante la carga útil de documento de Baileys para evitar la compresión multimedia de WhatsApp, conservando el nombre de archivo resuelto y el tipo MIME- los pies de foto se aplican al primer elemento multimedia en una respuesta con varios medios, excepto las notas de voz PTT: el audio se envía primero sin pie de foto y luego el pie de foto se envía como un mensaje de texto separado (los clientes de WhatsApp no renderizan de forma consistente los pies de foto de notas de voz)
- la fuente multimedia puede ser HTTP(S),
file://o una ruta local
Límites de tamaño de multimedia y comportamiento de reserva
Límites de tamaño de multimedia y comportamiento de reserva
- límite de guardado entrante y límite de envío saliente:
channels.whatsapp.mediaMaxMb(predeterminado50) - anulación por cuenta:
channels.whatsapp.accounts.<id>.mediaMaxMb - las imágenes se optimizan automáticamente (barrido de redimensionamiento/calidad) para ajustarse a los límites salvo que
forceDocument/asDocumentsolicite entrega como documento - ante un fallo de envío multimedia, la reserva del primer elemento envía una advertencia de texto en lugar de descartar la respuesta silenciosamente
Citas de respuesta
channels.whatsapp.replyToMode controla las citas de respuesta nativas (las respuestas salientes citan visiblemente el mensaje entrante):
| Valor | Comportamiento |
|---|---|
"off" (predeterminado) | Nunca citar; enviar como mensaje simple |
"first" | Citar solo el primer fragmento de respuesta saliente |
"all" | Citar cada fragmento de respuesta saliente |
"batched" | Citar respuestas en cola por lotes; dejar sin cita las respuestas inmediatas |
channels.whatsapp.accounts.<id>.replyToMode.
Nivel de reacción
channels.whatsapp.reactionLevel controla con qué amplitud el agente usa reacciones emoji:
| Nivel | Reacciones de acuse | Reacciones iniciadas por el agente |
|---|---|---|
"off" | No | No |
"ack" | Sí | No |
"minimal" (predeterminado) | Sí | Sí, guía conservadora |
"extensive" | Sí | Sí, guía fomentada |
channels.whatsapp.accounts.<id>.reactionLevel.
Reacciones de acuse
channels.whatsapp.ackReaction envía una reacción inmediata al recibir un entrante, controlada por reactionLevel (suprimida cuando es "off"):
ackReaction está presente sin emoji, WhatsApp usa el emoji de identidad del agente enrutado y recurre a ”👀” (omite ackReaction o define emoji: "" para no enviar acuse); los fallos se registran, pero no bloquean la entrega de la respuesta; el modo de grupo mentions reacciona solo en turnos activados por mención, mientras que la activación de grupo always omite esa comprobación; WhatsApp usa solo channels.whatsapp.ackReaction (messages.ackReaction heredado no se aplica aquí).
Reacciones de estado del ciclo de vida
Definemessages.statusReactions.enabled: true para permitir que WhatsApp reemplace la reacción de acuse durante un turno en lugar de dejar un emoji de recibo estático, recorriendo estados como en cola, pensando, actividad de herramienta, Compaction, completado y error:
channels.whatsapp.ackReaction sigue controlando la elegibilidad para mensajes directos y grupos; el estado en cola usa el mismo emoji efectivo que las reacciones de acuse simples; WhatsApp tiene una ranura de reacción de bot por mensaje, por lo que las actualizaciones del ciclo de vida reemplazan la reacción actual in situ; messages.removeAckAfterReply: true borra la reacción de estado final después de la retención configurada para completado/error; las categorías de emoji de herramienta incluyen tool, coding, web, deploy, build y concierge.
Varias cuentas y credenciales
Selección de cuenta y valores predeterminados
Selección de cuenta y valores predeterminados
channels.whatsapp.accounts. La selección de cuenta predeterminada es default si está presente; de lo contrario, el primer id de cuenta configurado (ordenado alfabéticamente). Los ids de cuenta se normalizan internamente para la búsqueda.Rutas de credenciales y compatibilidad heredada
Rutas de credenciales y compatibilidad heredada
- ruta de autenticación actual:
~/.openclaw/credentials/whatsapp/<accountId>/creds.json(copia de seguridad:creds.json.bak) - la autenticación predeterminada heredada en
~/.openclaw/credentials/todavía se reconoce/migra para flujos de cuenta predeterminada
Comportamiento de cierre de sesión
Comportamiento de cierre de sesión
openclaw channels logout --channel whatsapp [--account <id>] borra el estado de autenticación de WhatsApp para esa cuenta. Cuando se puede acceder a un Gateway, el cierre de sesión detiene primero el listener en vivo para esa cuenta, de modo que la sesión vinculada deja de recibir mensajes antes del próximo reinicio. openclaw channels remove --channel whatsapp también detiene el listener en vivo antes de deshabilitar o eliminar la configuración de la cuenta.En directorios de autenticación heredados, oauth.json se conserva mientras se eliminan los archivos de autenticación de Baileys.Herramientas, acciones y escrituras de configuración
- La compatibilidad con herramientas del agente incluye la acción de reacción de WhatsApp (
react). - Compuertas de acciones:
channels.whatsapp.actions.reactions,channels.whatsapp.actions.polls(las acciones existentes tienentruede forma predeterminada),channels.whatsapp.actions.calls(valor predeterminadofalse, consulta MeowCaller arriba). - Las escrituras de configuración iniciadas por el canal están habilitadas de forma predeterminada; deshabilítalas mediante
channels.whatsapp.configWrites: false.
Solución de problemas
No vinculado (se requiere QR)
No vinculado (se requiere QR)
Vinculado pero desconectado / bucle de reconexión
Vinculado pero desconectado / bucle de reconexión
status=408 Request Time-out Connection was lost, ajusta los tiempos del socket de Baileys en web.whatsapp. Empieza por acortar keepAliveIntervalMs por debajo del tiempo de espera por inactividad de tu red y aumentar connectTimeoutMs en enlaces lentos o con pérdidas:~/.openclaw/logs/whatsapp-health.log dice Gateway inactive, pero openclaw gateway status y openclaw channels status --probe muestran ambos un estado correcto, ejecuta openclaw doctor. En Linux, doctor advierte sobre entradas heredadas de crontab que invocan el script retirado ~/.openclaw/bin/ensure-whatsapp.sh; elimina esas entradas con crontab -e: cron puede carecer del entorno de bus de usuario de systemd y hacer que ese script antiguo informe incorrectamente del estado del Gateway.El inicio de sesión con QR agota el tiempo de espera detrás de un proxy
El inicio de sesión con QR agota el tiempo de espera detrás de un proxy
openclaw channels login --channel whatsapp falla antes de mostrar un QR utilizable con status=408 Request Time-out o una desconexión de socket TLS.El inicio de sesión de WhatsApp Web usa el entorno de proxy estándar del host del Gateway (HTTPS_PROXY, HTTP_PROXY, variantes en minúsculas, NO_PROXY). Verifica que el proceso del Gateway herede el entorno de proxy y que NO_PROXY no coincida con mmg.whatsapp.net.No hay listener activo al enviar
No hay listener activo al enviar
La respuesta aparece en la transcripción pero no en WhatsApp
La respuesta aparece en la transcripción pero no en WhatsApp
auto-reply delivery failed o auto-reply was not accepted by WhatsApp provider.Los mensajes de grupo se ignoran inesperadamente
Los mensajes de grupo se ignoran inesperadamente
groupPolicy, groupAllowFrom/allowFrom, entradas de lista de permitidos de groups, compuerta de menciones (requireMention + patrones de mención) y claves duplicadas en openclaw.json (las entradas posteriores de JSON5 anulan las anteriores: mantén un único groupPolicy por ámbito).Si channels.whatsapp.groups está presente, WhatsApp aún puede observar mensajes de otros grupos, pero OpenClaw los descarta antes del enrutamiento de sesión. Añade el JID del grupo a channels.whatsapp.groups, o añade groups["*"] para admitir todos los grupos mientras mantienes la autorización de remitentes bajo groupPolicy/groupAllowFrom.Advertencia de runtime de Bun
Advertencia de runtime de Bun
Prompts del sistema
WhatsApp admite prompts del sistema de estilo Telegram para grupos y chats directos mediante los mapasgroups y direct.
Resolución para mensajes de grupo: primero se determina el mapa groups efectivo; si la cuenta define su propia clave groups, reemplaza por completo el mapa groups raíz (sin fusión profunda). Luego, la búsqueda del prompt se ejecuta en ese único mapa resultante:
- Prompt específico de grupo (
groups["<groupId>"].systemPrompt): se usa cuando la entrada del grupo existe y su clavesystemPromptestá definida. Una cadena vacía ("") suprime el comodín y no aplica ningún prompt. - Prompt comodín de grupo (
groups["*"].systemPrompt): se usa cuando la entrada específica del grupo está ausente, o existe sin una clavesystemPrompt.
direct y direct["*"].
dms sigue siendo el contenedor ligero de anulación de historial por DM (dms.<id>.historyLimit). Las anulaciones de prompts viven bajo direct.groups/direct de cuenta, incluido un objeto vacío explícito, reemplaza el mapa raíz. Difiere de la comprobación de lista de permitidos de pertenencia a grupos descrita arriba, que tiene una red de seguridad de cuenta única para un groups: {} accidentalmente vacío.groups raíz para cada cuenta en una configuración de varias cuentas (incluso cuentas sin groups propios) para impedir que un bot reciba mensajes de grupo de grupos a los que no pertenece. WhatsApp no aplica esa protección: groups/direct raíz son heredados por cualquier cuenta sin su propia anulación, independientemente del número de cuentas. En una configuración de WhatsApp de varias cuentas, define explícitamente el mapa completo bajo cada cuenta si quieres prompts por cuenta.
Comportamiento importante:
channels.whatsapp.groupses tanto un mapa de configuración por grupo como la lista de permitidos de grupos a nivel de chat. En el ámbito raíz o de cuenta,groups["*"]significa “todos los grupos son admitidos” para ese ámbito.- Añade un
systemPromptcomodín solo cuando ya quieras que ese ámbito admita todos los grupos. Para mantener elegible solo un conjunto fijo de IDs de grupo, repite el prompt en cada entrada explícitamente incluida en la lista de permitidos en lugar de usargroups["*"]. - La admisión de grupos y la autorización de remitentes son comprobaciones separadas.
groups["*"]amplía qué grupos llegan al manejo de grupos; no autoriza a todos los remitentes de esos grupos: eso sigue controlado porgroupPolicy/groupAllowFrom. channels.whatsapp.directno tiene un efecto secundario equivalente para DMs:direct["*"]solo proporciona una configuración predeterminada después de que un DM ya haya sido admitido pordmPolicymás reglas deallowFromo del almacén de emparejamientos.
Punteros de referencia de configuración
Referencia principal: Referencia de configuración - WhatsApp| Área | Campos |
|---|---|
| Acceso | dmPolicy, allowFrom, groupPolicy, groupAllowFrom, groups |
| Entrega | textChunkLimit, chunkMode, mediaMaxMb, sendReadReceipts, ackReaction, reactionLevel |
| Varias cuentas | accounts.<id>.enabled, accounts.<id>.authDir y otras anulaciones por cuenta |
| Operaciones | configWrites, debounceMs, web.enabled, web.heartbeatSeconds, web.reconnect.*, web.whatsapp.* |
| Comportamiento de sesión | session.dmScope, historyLimit, dmHistoryLimit, dms.<id>.historyLimit |
| Prompts | groups.<id>.systemPrompt, groups["*"].systemPrompt, direct.<id>.systemPrompt, direct["*"].systemPrompt |