Has visto el indicador de "alguien está escribiendo..." de WhatsApp. Tu pantalla lo muestra en el mismo instante en que pasa, sin que tú pidas nada. Eso no es magia: es tu app manteniendo una conexión abierta con el servidor por donde ambos se envían mensajes cuando quieren.

En este post te explico cómo funciona esa pieza — el protocolo WebSocket — con diagramas y un video donde lo recorremos completo.

El problema: HTTP fue diseñado para pedir, no para escuchar

HTTP funciona así: tu app abre una conexión, hace un pedido (request), recibe una respuesta y la conexión se cierra. Listo. Para la mayoría de las cosas — cargar una página, traer un listado, guardar un formulario — es perfecto.

El problema aparece cuando la información la produce el servidor, no tú: un mensaje nuevo, un cambio de precio, el estado de un pedido. Con HTTP puro tu app no tiene forma de enterarse salvo preguntar una y otra vez:

Diagrama: con HTTP la app pregunta cada pocos segundos y recibe "nada nuevo"; con WebSocket el evento llega apenas ocurre

Ese ciclo de preguntar cada X segundos se llama polling, y tiene tres costos que se pagan siempre:

  • Latencia: si preguntas cada 5 segundos, en promedio te enteras 2.5 segundos tarde. En un chat, eso se siente roto.
  • Tráfico inútil: la mayoría de las respuestas son "no hay nada nuevo". Estás pagando por transmitir silencio.
  • Carga del servidor: miles de clientes preguntando cada pocos segundos, aunque casi nunca haya nada que decirles.

La idea del WebSocket: una conexión que no se cierra

Un WebSocket resuelve el problema con un cambio conceptual simple: una sola conexión que queda abierta, y por la que cualquiera de los dos lados puede escribir cuando quiera.

Lo elegante es cómo nace esa conexión: empieza siendo un HTTP normal. Tu app hace un pedido especial diciendo "no quiero una respuesta y chau — quiero que esta conexión se transforme en un canal bidireccional":

Diagrama de secuencia: el handshake Upgrade, el 101 Switching Protocols, los frames en ambas direcciones, ping/pong y el cierre

Paso a paso:

  1. El handshake: el navegador manda un GET con el header Upgrade: websocket. Es HTTP común, con la salvedad de que pide cambiar de protocolo.
  2. El servidor acepta: responde 101 Switching Protocols. A partir de esa línea, la conexión ya no habla HTTP — habla WebSocket.
  3. El canal abierto: desde ahí, ambos extremos envían frames (mensajes livianos) en cualquier momento, sin pedido previo.
  4. Mantenimiento: ping/pong periódicos mantienen viva la conexión a través de proxies y firewalls.
  5. El cierre: cualquiera de los dos puede mandar un close frame cuando termina.

Dos detalles que valen oro:

  • Corre sobre el mismo puerto que HTTPS (443). No hay que abrir nada nuevo en el firewall — el canal atraviesa la misma puerta que el resto de tu tráfico.
  • El servidor puede iniciar mensajes. Esto es lo que no existe en HTTP y es la razón entera del protocolo: el evento llega apenas ocurre.

Cómo se ve en el navegador:

// Abrir el canal (nota la wss:// — es el https de WebSockets)
const socket = new WebSocket("wss://api.tuapp.com/chat");

// Escuchar lo que el servidor empuja
socket.onmessage = (evento) => {
  const mensaje = JSON.parse(evento.data);
  mostrarEnPantalla(mensaje);
};

// Enviar sin pedir permiso
socket.send(JSON.stringify({ texto: "hola" }));

¿Cuándo conviene cada cosa?

WebSocket no reemplaza HTTP — lo complementa. La regla práctica:

Necesitas... Usa
Cargar páginas, formularios, CRUD HTTP normal
Que el cliente reciba un stream de datos del servidor, sin enviar de vuelta SSE (Server-Sent Events)
Comunicación en ambas direcciones, en vivo: chat, multiplayer, presencia, notificaciones, cotizaciones WebSocket

SSE merece mención honesta: si tu caso es "el servidor habla, el cliente solo escucha" (un feed de noticias, un ticker), SSE es más simple y se reconecta solo. WebSocket gana cuando el cliente también necesita hablar por el mismo canal — que es exactamente el caso de un chat.

Lo que nadie te cuenta: la vida en producción

Los tutoriales terminan donde empieza el trabajo real. Tres cosas que solo aprendes cuando un WebSocket te falla un viernes:

1. La conexión se corta. Y se corta seguido. Redes wifi inestables, proxies corporativos que matan conexiones "inactivas", el teléfono que cambia de red. Tu app necesita reconexión automática con backoff (reintentar cada vez más espaciado), y tu protocolo necesita soportar que un mensaje llegue dos veces o ninguna (idempotencia).

2. El heartbeat no es opcional. Sin ping/pong periódicos, un proxy intermedio puede dar por muerta una conexión perfectamente sana — y te enteras cuando el usuario deja de recibir mensajes "sin razón". Es el bug clásico de "funciona en la oficina, muere en producción".

3. Necesitas un plan B. Hay redes (hoteles, empresas, algunos móviles) donde los WebSockets simplemente no conectan o se degradan. Las apps serias no apuestan todo al canal: mantienen un fallback por HTTP que entregue lo mismo, más lento, cuando el socket no está disponible.

Un caso real: el turno de un chatbot por WebSocket

Esto no es teoría. En UseFlowy, el widget de chat de los bots vive exactamente sobre este patrón — y aprendimos las tres lecciones de arriba por el camino difícil:

Diagrama de secuencia: un turno completo de chat — usuario, widget, gateway WebSocket y bot engine — con el fallback HTTP cuando el socket no conecta

Cuando escribes en el chat de un bot:

  1. El widget mantiene su canal WebSocket abierto con nuestro gateway.
  2. Tu mensaje viaja por ese canal y despierta al engine del bot (el que decide si responde el flujo o la IA).
  3. Cuando el engine termina, la respuesta llega como push por el mismo canal — no hay polling, no hay espera artificial.
  4. Y si el socket no conecta (esa red de hotel), el mismo turno sale por HTTP normal, con el mismo contrato de datos. El usuario no nota la diferencia.

Detalles de producción que tuvimos que construir para que esto sea serio: indicador de "escribiendo..." en vivo por el mismo canal, timeout de turno (un engine colgado no puede dejar el typing eterno), y reconexión automática transparente. Es la diferencia entre una demo y un producto.

Lo recorremos completo en video

Si prefieres la versión hablada, grabamos un video recorriendo todo esto — el problema del polling, el handshake y los frames, con ejemplos:

👉 WebSocket explicado: así hablan las apps en tiempo real

En resumen

  • HTTP es pedir y esperar; para tiempo real te deja pagando latencia y tráfico inútil con polling.
  • Un WebSocket nace de un HTTP (Upgrade → 101) y queda abierto: ambos lados escriben cuando quieren.
  • Corre sobre el 443, así que atraviesa firewalls sin pedir nada nuevo.
  • En producción lo serio no es abrir el canal: es reconectarse, mantenerse vivo y saber degradar a HTTP cuando el canal no está.

Si tienes un negocio que atiende clientes por chat, todo esto trabaja para ti sin que lo toques: el widget de UseFlowy usa este patrón para que cada respuesta llegue en el instante en que el bot la produce. Crea tu bot gratis y pruébalo tú mismo.