---
name: whatsapp_send_message
kind: function
lang: py
domain: browser
version: "1.0.0"
purity: impure
signature: "def whatsapp_send_message(name: str, text: str, *, port: int = 9222, target_url_substr: str = 'whatsapp', open_first: bool = True) -> dict"
description: "Envia un mensaje de texto a un chat de WhatsApp Web en una pestana ya logueada del navegador diario via CDP, sin abrir ventana nueva ni darle foco. Abre el chat por nombre exacto (whatsapp_open_chat), verifica que el composer apunta al destinatario correcto antes de escribir (salvaguarda anti-envio-equivocado), teclea el texto con teclado CDP real (unico metodo que funciona con el editor Lexical), comprueba que el composer tiene exactamente el texto y envia con Enter. Accion con efecto: envia un mensaje DE VERDAD, no reversible."
tags: [whatsapp, cdp, browser, automation, python, navegator]
uses_functions: [whatsapp_open_chat_py_browser, cdp_eval_py_browser, cdp_type_chars_py_browser, cdp_press_key_py_browser]
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: ["os", "sys", "time", "json"]
params_schema:
  params:
    - name: name
      desc: "Nombre EXACTO del chat o grupo destinatario tal y como aparece en la lista lateral. Se usa para abrir el chat y como salvaguarda de que el composer apunta al destinatario correcto antes de escribir."
    - name: text
      desc: "Texto a enviar. Se teclea con teclado CDP real caracter a caracter. Enter lo envia (no inserta salto de linea); multilinea no soportado."
    - name: port
      desc: "Puerto de remote debugging de Chrome. Default 9222."
    - name: target_url_substr
      desc: "Substring que debe contener la URL del target (pestana). Default 'whatsapp'."
    - name: open_first
      desc: "Si True (default), abre el chat por su nombre antes de enviar. Si False, asume el chat ya abierto pero verifica el aria-label del composer contra name antes de escribir (aborta si no coincide)."
  output: "dict {sent: bool, name: str, last_row: str (texto de la ultima fila de #main tras enviar, si sent=True), reason: str (motivo del fallo, si sent=False), composer: str (contenido real del composer cuando hubo mismatch de texto)}. sent=True solo si el composer contenia exactamente el texto y se pulso Enter. Nunca lanza: los fallos se reportan en 'sent' + 'reason'."
tested: true
tests: ["test_golden_envia_mensaje_y_devuelve_last_row", "test_edge_open_fallido_sent_false_reason", "test_seguridad_open_first_false_label_no_coincide_aborta_sin_escribir", "test_mismatch_composer_sent_false_sin_press_enter"]
test_file_path: "python/functions/browser/whatsapp_send_message_test.py"
file_path: "python/functions/browser/whatsapp_send_message.py"
---

## Ejemplo

```python
import sys, os
sys.path.insert(0, os.path.join("python", "functions"))
from browser.whatsapp_send_message import whatsapp_send_message

# Requiere WhatsApp Web abierto y logueado en un Chrome lanzado con
# --remote-debugging-port=9222.
res = whatsapp_send_message("NOTAS WASAP", "hola desde el registry")
print(res)
# -> {"sent": True, "name": "NOTAS WASAP", "last_row": "hola desde el registry 11:40"}
```

O directo por CLI: `python3 python/functions/browser/whatsapp_send_message.py "NOTAS WASAP" "hola desde el registry"`.

## Cuando usarla

Cuando necesites **enviar un texto a un contacto o grupo por su nombre exacto** en
WhatsApp Web, sin abrir ventana nueva ni robar el foco al usuario. Compone
`whatsapp_open_chat` (abre y localiza el chat) con las primitivas CDP de teclado para
escribir y enviar. Es el paso de "envio" del navegador diario: usala cuando ya tienes
el nombre exacto del destinatario y un texto que mandar.

## Gotchas

- **Accion con efecto: envia un mensaje DE VERDAD.** No es reversible (WhatsApp no permite des-enviar por API ni por CDP). Verifica que `name` es EXACTO antes de llamar.
- **Viola los ToS de WhatsApp**: automatizar la web tiene riesgo de ban del numero personal. Usar con cautela y bajo tu responsabilidad.
- **Salvaguarda anti-destinatario-equivocado**: antes de escribir, verifica que el composer apunta a `name` (via `whatsapp_open_chat` con `open_first=True`, o leyendo el aria-label con `open_first=False`). Si no coincide, aborta con `sent=False` sin teclear nada.
- **Doble salvaguarda de contenido**: tras teclear, re-lee el `innerText` del composer y solo pulsa Enter si coincide EXACTAMENTE con `text`. Si no, devuelve `sent=False`, `reason` y el `composer` real, sin enviar.
- **El texto se escribe con teclado CDP real** (`cdp_type_chars`). NO usar `execCommand`/`el.value`: el editor Lexical de WhatsApp los ignora y produce texto duplicado/intercalado (gotcha real observado en pruebas).
- **`Enter` envia** (no inserta salto de linea). Para multilinea habria que usar Shift+Enter (no implementado aqui).
- **Funciona con la ventana minimizada o sin foco**: CDP opera la pestana sin necesidad de que Chrome este en primer plano.
- El `name` debe ser **EXACTO**; un contacto no cargado en la lista lateral puede no encontrarse al abrir (ver gotchas de `whatsapp_open_chat`).
