main content

Cómo implementar streaming de datos en tiempo real con WebSockets y Server-Sent Events en tu aplicación web a medida

Pocas aplicaciones que hemos puesto en producción los últimos años trabajan con datos estáticos. Paneles financieros, plataformas logísticas, monitorización industrial, entornos colaborativos: todos comparten el mismo requisito incómodo. El dato tiene que llegar al cliente cuando cambia, no cuando al usuario se le ocurre pulsar F5.

Y resolver eso bien es una decisión de arquitectura que arrastras durante años. Afecta al rendimiento, al coste de infraestructura y a la percepción que el usuario tiene del producto. WebSockets y Server-Sent Events (SSE) son las dos herramientas principales que tenemos sobre la mesa. Elegir una, otra o ambas marca la diferencia entre una plataforma que envejece bien y otra que pide rescate cada seis meses.

El polling se queda corto antes de lo que crees

Durante años tirábamos de polling: el cliente pregunta cada X segundos si hay novedades. Es fácil de explicar, fácil de programar y todo el equipo lo entiende. También es un derroche.

Hagamos el cálculo que solemos enseñar en los kick-off técnicos. Un polling cada 5 segundos con 2.000 usuarios activos son 24.000 peticiones HTTP por minuto, y la mayoría devuelven nada nuevo. Cada una abre conexión, negocia cabeceras, espera respuesta y cierra. Multiplica eso por el coste de tus balanceadores y tu factura cloud, y verás que el sistema gasta la mayor parte de su tiempo respondiendo "no hay nada".

El long polling alivia la latencia manteniendo la conexión abierta hasta que aparece el dato, pero traslada el dolor a otra parte: timeouts mal calibrados, reconexiones que se acumulan y un patrón request-response empujado más allá de su diseño original. Los protocolos de streaming nacieron justo aquí: una conexión abierta, datos empujados desde el servidor cuando existen, y se acabó el ruido.

WebSockets: el canal de doble sentido cuando lo necesitas de verdad

WebSocket es un estándar (RFC 6455) que abre una conexión persistente full-duplex sobre TCP. Tras el handshake HTTP Upgrade inicial, cliente y servidor se hablan en cualquier dirección sin tener que pedir permiso de nuevo.

Lo que ocurre en el handshake

El cliente lanza la cabecera Upgrade: websocket con una clave aleatoria en Base64. El servidor responde con un 101 Switching Protocols y, a partir de ahí, el canal pasa a frames binarios. Todo el overhead HTTP desaparece para los siguientes mensajes, así que la latencia se reduce a la latencia de red.

GET /ws HTTP/1.1
Host: app.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

Cuándo WebSockets es la respuesta correcta

  • Aplicaciones colaborativas: editores compartidos, pizarras digitales, herramientas de diseño donde varios usuarios tocan el mismo estado a la vez.
  • Mensajería y chat: la bidireccionalidad es el producto. El servidor recibe del cliente con la misma fluidez con la que envía.
  • Trading y feeds financieros interactivos: órdenes desde el cliente y actualizaciones de precio desde el servidor por el mismo carril.
  • Juegos multijugador y simulaciones: sincronizar estado a alta frecuencia, donde cada milisegundo cuenta.
  • Control de dispositivos IoT: comandos hacia el dispositivo y telemetría de vuelta, en un único canal.

Lo que duele en operación

WebSockets exigen que la infraestructura de red soporte conexiones persistentes, y ahí es donde aparecen las sorpresas. Los balanceadores configurados para HTTP corto necesitan tocarse a mano: o usas sticky sessions, o —mejor— diseñas algo stateless con el estado de sesión viviendo en un broker externo tipo Redis Pub/Sub.

Cuando escalas horizontalmente, el servidor que recibe el mensaje del cliente A casi nunca es el que mantiene la conexión del cliente B al que hay que notificar. Si no metes un bus de mensajes en medio, la arquitectura se rompe en cuanto añades la segunda instancia. Lo hemos visto romperse exactamente así.

Server-Sent Events: streaming unidireccional sobre HTTP, sin dramas

SSE es un estándar W3C bastante más simple. Permite al servidor empujar datos al cliente sobre una conexión HTTP/1.1 o HTTP/2 persistente. Va solo en una dirección: el servidor manda, el cliente escucha. Si el cliente quiere enviar algo, lo hace por peticiones HTTP normales, aparte.

Cómo se ve el protocolo por dentro

El cliente abre la conexión con Accept: text/event-stream. El servidor contesta con Content-Type: text/event-stream y deja la conexión abierta, mandando eventos como texto plano:

data: {"precio": 142.50, "simbolo": "AAPL"}



event: alerta
data: {"mensaje": "Umbral superado", "nivel": "crítico"}



id: 1847
data: {"estado": "actualizado"}

El campo id permite retomar la conexión desde el último evento recibido usando Last-Event-ID. Y aquí viene la parte que más agradecemos: el navegador hace la reconexión automática con backoff por ti. Es código de infraestructura que no tienes que escribir ni mantener, y que en WebSockets te toca pelearte.

Dónde SSE encaja como un guante

  • Dashboards de monitorización: métricas de sistema, KPIs, alertas operativas. El cliente solo mira.
  • Notificaciones en plataformas SaaS: avisas al usuario de algo relevante sin tener que martillear el servidor con polling.
  • Progreso de procesos largos: exportaciones, generación de informes, pipelines. El cliente quiere saber por dónde va el trabajo.
  • Feeds de actividad: auditoría, logs, timelines de lo que hacen otros usuarios.
  • Integración con LLMs: el streaming de tokens cae perfectamente sobre SSE. Buena parte de las APIs públicas de modelos lo han adoptado por algo.

Cómo decidir entre WebSockets y SSE

Criterio WebSockets Server-Sent Events
Dirección del flujo Bidireccional Servidor → Cliente
Protocolo base TCP (sobre HTTP para handshake) HTTP/1.1 o HTTP/2
Soporte en navegadores Universal Universal (salvo IE11)
Reconexión automática Manual (requiere código cliente) Nativa en el navegador
Compatibilidad con proxies HTTP Problemática en algunos entornos Transparente
Complejidad de escalado horizontal Alta (requiere broker de mensajes) Media (compatible con HTTP/2 multiplexing)
Soporte HTTP/2 multiplexing No (protocolo propio)
Overhead por mensaje Muy bajo (frames binarios) Bajo (texto plano)
Caso de uso canónico Chat, colaboración, gaming Dashboards, notificaciones, feeds

No es una elección de "uno u otro" tan a menudo como parece. En proyectos grandes nos pasa que SSE resuelve el 80% del streaming servidor-a-cliente y reservamos WebSockets para los módulos donde la bidireccionalidad es real, no aspiracional. Esa combinación te quita complejidad operativa en el día a día.

Cómo montamos una arquitectura de streaming production-ready

Llevar esto a producción de verdad en una app a medida no se sostiene con cuatro líneas en el backend. Hay varias capas que tienen que encajar.

Broker de mensajes en el medio

A escala, tanto WebSockets como SSE necesitan algo que desacople la generación del evento de su entrega al cliente. Cuando el volumen es alto y queremos durabilidad del log, tiramos de Apache Kafka: un microservicio produce eventos, Kafka los retiene y los servidores de streaming consumen y reenvían.

Cuando el volumen es menor o la latencia manda, Redis Pub/Sub hace el trabajo con mucho menos peso. Un servidor recibe un evento de negocio, lo publica en un canal y todos los servidores suscritos —da igual cuál esté gestionando cada conexión cliente— lo reciben y lo empujan. Sencillo y suficiente para la mayoría de plataformas medianas.

Autenticación que aguante conexiones largas

Aquí está uno de los fallos más comunes que nos toca corregir en auditorías: el token caduca durante la vida de la conexión y nadie lo gestiona. La conexión sigue ahí, autenticada por inercia, semanas después de que el token debería haber expirado.

La práctica correcta es validar el token en el handshake y montar un mecanismo de refresco —o de expiración forzada— cuando el token vence. Para WebSockets, el token va o en el query string del handshake (asumiendo lo que eso significa en tus logs) o en una cookie HttpOnly. Para SSE, la cookie es la opción estándar y la más limpia.

Backpressure: el detalle que separa una implementación seria de un experimento

Es el error clásico de las primeras versiones. El servidor produce más rápido de lo que el cliente consume, los buffers se hinchan y el sistema se degrada en silencio hasta que cae. Hay que diseñarlo desde el principio: pausar la producción cuando el buffer supera un umbral, o descartar eventos intermedios y enviar solo el más reciente cuando hablamos de precios, posiciones o métricas que el cliente solo necesita en su último valor. Esto no es optimización tardía, es parte de la arquitectura.

Observabilidad específica de conexiones persistentes

Tu dashboard de APM con latencia HTTP y throughput no te va a contar nada útil sobre lo que está pasando aquí. Hay que instrumentar a propósito: conexiones activas, duración media de conexión, tasa de reconexiones (es el termómetro de la inestabilidad de red), eventos encolados por conexión y latencia end-to-end desde que se genera el evento hasta que llega al cliente. Sin estas métricas estás volando a ciegas.

Cómo afecta esto al equipo y al ciclo de entrega

Meter streaming en tiempo real en una app a medida no es solo una decisión técnica, y lo decimos porque hemos visto proyectos atascarse por subestimarlo. Implica formar al equipo en programación reactiva y manejo de estado asíncrono en frontend. Implica rehacer la estrategia de testing: los tests de integración tienen que simular flujos de eventos, no llamadas HTTP puntuales. Y obliga a revisar los SLA: la latencia máxima de entrega de un evento es un parámetro distinto al tiempo de respuesta de un endpoint REST y hay que negociarlo aparte con negocio.

La deuda técnica del polling, además, es invisible hasta que escalas. Migrar de polling a streaming con decenas de miles de usuarios ya en producción cuesta varios múltiplos más que diseñarlo bien desde el inicio o aprovechar una refactorización planificada. Cuanto antes lo afrontas, más barato sale.

Cuándo merece la pena meterse en esto

Respuesta directa: cuando el desfase entre que un dato cambia y el usuario lo ve tiene coste de negocio que puedes medir. En un sistema de gestión de almacén, 30 segundos de retraso en el stock generan órdenes de picking incorrectas y horas de reconciliación. En monitorización de flotas, 10 segundos pueden ser la diferencia entre una respuesta a tiempo y un incidente que escalas a dirección.

Si tu aplicación a medida gestiona datos volátiles y la frescura de esos datos importa al negocio, la pregunta deja de ser "¿implementamos streaming?" y pasa a ser "¿cuándo y con qué protocolo?".

La decisión arquitectónica que te acompaña los próximos cinco años

Elegir entre WebSockets y SSE, montar el broker adecuado, gestionar autenticación en conexiones persistentes y tener observabilidad real son decisiones que marcan la solidez de tu plataforma durante el próximo lustro. No hay receta universal. El stack correcto depende del volumen de eventos, los patrones de uso reales, la madurez del equipo y los requisitos de disponibilidad que el negocio te exija.

Si estás valorando cómo incorporar streaming de datos en tiempo real a tu aplicación a medida, o si arrastras una implementación que no rinde como prometía, podemos auditar la arquitectura contigo y trazar el camino. Habla con nuestro equipo técnico para revisar tu caso concreto.