SSE vs WebSockets en 2026: ¿cuál deberías usar?

Profile picture of Equipo Arvucore

Equipo Arvucore

September 22, 2025 · Actualizado el August 26, 2026

16 min read

Si solo necesitas enviar datos del servidor al navegador, usa Server-Sent Events: corren sobre HTTP plano, se reconectan solos, atraviesan proxies y plataformas serverless, y manejan bien notificaciones, dashboards y streaming de tokens de LLM. Usa WebSockets cuando el cliente también deba enviar muchos mensajes pequeños con baja latencia, o cuando necesites frames binarios, como en chat, edición colaborativa y juegos. El polling y el long polling siguen siendo fallbacks, no primeras opciones.

Cómo funcionan SSE y WebSockets a nivel de protocolo

Server-Sent Events es HTTP corriente. El navegador envía un GET, el servidor responde con Content-Type: text/event-stream y nunca cierra la respuesta. Los eventos son líneas de texto UTF-8: data:, event: e id: opcionales, separadas por una línea en blanco. Cualquier cosa capaz de hacer streaming de una respuesta HTTP puede servir SSE.

En HTTP/1.1 eso tiene un coste conocido: los navegadores limitan las conexiones por origen a seis. Cada EventSource abierto ocupa una, así que una página con varios streams, o un usuario con varias pestañas, puede agotar el presupuesto y bloquear las peticiones normales. Sobre HTTP/2 el problema desaparece: cada stream SSE es un stream multiplexado dentro de una única conexión TCP, y el límite por origen ronda el centenar de streams, negociado con el servidor. En 2026 el límite muerde sobre todo en desarrollo local y detrás de proxies antiguos que degradan a HTTP/1.1.

WebSockets empiezan como HTTP y dejan de ser HTTP. El cliente envía un GET con Upgrade: websocket y Connection: Upgrade; el servidor responde 101 Switching Protocols, y a partir de ahí el socket TCP transporta frames WebSocket (RFC 6455): texto o binario, con opcodes, fragmentación, enmascaramiento del cliente al servidor y frames de control ping/pong. Sobre HTTP/2 existe un mecanismo aparte (RFC 8441, el método CONNECT extendido) que tuneliza un WebSocket dentro de un stream HTTP/2, pero el soporte en servidores, proxies y librerías es inconsistente, así que la mayoría de los despliegues siguen ejecutando WebSockets en una conexión HTTP/1.1 dedicada.

Todo lo que viene después reacciona a esta diferencia: un stream SSE es una respuesta HTTP larga; un WebSocket es un socket opaco que las herramientas HTTP ya no entienden.

Reconexión, orden y Last-Event-ID

Aquí es donde SSE se gana su fama de simple. EventSource se reconecta automáticamente cuando la conexión cae, usando el intervalo retry: que el servidor puede definir. Si el servidor etiqueta los eventos con id:, el navegador devuelve el último como header Last-Event-ID al reconectar. El servidor reenvía lo que el cliente se perdió desde un log, un Redis Stream o un offset de Kafka. La reanudación forma parte de la spec.

WebSockets no tiene nada de esto. Cuando el socket se cierra, el objeto WebSocket está muerto. Tu código debe detectar el cierre, aplicar backoff con jitter para que miles de clientes no se reconecten en el mismo instante, reautenticar, resuscribir y reconciliar el estado. Si necesitas "dame lo que me perdí", lo diseñas tú con números de secuencia o un ID de sesión reanudable.

Dos notas para ambos transportes. Las conexiones inactivas mueren: operadoras, tablas NAT y balanceadores de carga tiran sockets en silencio durante decenas de segundos a unos minutos, así que envía un heartbeat (un comentario SSE : ping o un frame ping de WebSocket) dentro de esa ventana. Y EventSource reintenta para siempre por diseño, así que un error permanente como un 401 debe tratarse explícitamente.

Proxies, balanceadores de carga y CDN

SSE parece una respuesta HTTP lenta. Todo proxy L7, ingress y CDN la reenvía, pero varios hacen buffer de las respuestas por defecto, lo que convierte un stream en nada hasta que el buffer se llena. Desactiva el buffering por ruta (X-Accel-Buffering: no en Nginx, el equivalente en tu ingress o CDN), desactiva la compresión en el stream o usa un compresor que haga flush, y sube los timeouts de inactividad y lectura para esa ruta. La mayoría de los incidentes de "SSE no funciona detrás de nuestro proxy" son uno de estos tres ajustes.

WebSockets necesita que el proxy respete el handshake Upgrade y deje pasar el socket. Los proxies modernos, los balanceadores de nube y las CDN lo hacen, a menudo con condiciones: planes concretos, timeouts de inactividad que no puedes subir, o ningún soporte en un middlebox corporativo antiguo. Las redes restrictivas todavía pueden bloquear wss://, y por eso existen los fallbacks de long polling. Algunas CDN facturan las conexiones WebSocket de forma distinta a las peticiones HTTP. El passthrough L4 evita casi todo esto, pero renuncia al enrutamiento y la observabilidad L7.

HTTP/3 y QUIC cambian poco aquí por ahora: SSE funciona sobre HTTP/3 como cualquier respuesta, mientras que WebSocket sobre HTTP/3 (RFC 9220) todavía se despliega rara vez de extremo a extremo.

Autenticación: cookies vs headers

Ninguna de las dos API del navegador permite definir un header Authorization. Esto sorprende a equipos con un montaje limpio de bearer token para su API REST que luego descubren que el canal en tiempo real no puede reutilizarlo.

Tus opciones:

  • Cookies. Tanto EventSource (con withCredentials: true para cross-origin) como WebSocket envían cookies. Es el camino más simple cuando el front-end es same-site. Define SameSite, Secure y HttpOnly, y valida el header Origin en el servidor, porque WebSockets no está cubierto por CORS.
  • Token en la query string. Funciona en ambos, pero el token acaba en logs de acceso, logs de proxy e historial del navegador. Usa un ticket de corta duración y propósito único emitido por un POST autenticado, no tu token de sesión de larga duración.
  • Token en el primer mensaje (solo WebSocket). Abre el socket, envía { "type": "auth", "token": "..." } y cierra si no llega en un segundo. Es estándar en la práctica; aun así, la conexión existe brevemente sin autenticar.
  • Sustituir EventSource por fetch. Un fetch en streaming con response.body.getReader() acepta cualquier header, funciona con AbortController y puede parsear text/event-stream con unas pocas líneas de código o una librería pequeña. Pierdes la reconexión automática y Last-Event-ID, que tendrás que reimplementar. Es el patrón que usan hoy la mayoría de las interfaces de chat con LLM.

El header Sec-WebSocket-Protocol a veces se abusa para transportar un token; funciona, pero ata la autenticación a un campo pensado para negociar subprotocolos. Para tokens y sesiones en general, consulta autenticación moderna con OAuth 2.0, JWT y zero trust.

Escalado y fan-out: pub/sub, Redis, sticky sessions

Un solo nodo puede sostener de decenas a cientos de miles de conexiones inactivas, según el runtime, la memoria por conexión y TLS. El problema nunca es la cantidad; es que un mensaje producido en el nodo A debe llegar a un cliente conectado al nodo B.

La respuesta estándar es la misma para ambos transportes: mantén los nodos de conexión sin estado y pon una malla de pub/sub detrás. Redis Pub/Sub o Redis Streams, NATS o Kafka transportan los eventos; cada nodo se suscribe a los canales que interesan a sus clientes y escribe en los sockets locales. Redis Streams y Kafka también te dan el log de replay que Last-Event-ID necesita. Diseña el modelo de topics pronto; las suscripciones sin límite son la causa habitual del crecimiento de memoria.

Dónde difieren los transportes:

  • SSE se balancea como cualquier petición HTTP. Cualquier nodo puede atender a cualquier cliente, y una reconexión puede caer en cualquier sitio, porque el estado de reanudación viaja en Last-Event-ID. Las sticky sessions son opcionales.
  • WebSockets tiene estado por naturaleza. Si el servidor guarda estado por conexión (suscripciones, presencia, cursores) en memoria, una reconexión debe volver al mismo nodo, lo que implica sticky sessions, o ese estado debe externalizarse. Los gateways gestionados y los frameworks con backplane en Redis existen sobre todo para resolver esto.
  • Backpressure es una preocupación de WebSocket en ambas direcciones y de SSE en una. Acota las colas por conexión, agrupa actualizaciones para clientes lentos, y descarta o degrada en vez de dejar crecer bufferedAmount.

Los deploys son un evento de escalado disfrazado: un rollout cierra todas las conexiones del nodo, y decenas de miles de clientes se reconectan a la vez. Drena con cuidado, reparte los reinicios y asegúrate de que el backoff del cliente tenga jitter.

Serverless, navegadores y móvil

Serverless. Las funciones tienen alcance de petición y límite de tiempo. WebSockets no puede vivir dentro de una función normal; necesitas un gateway gestionado que sostenga el socket e invoque funciones por mensaje, más un almacén para los ID de conexión. SSE encaja mejor: una función de streaming o de edge devuelve un ReadableStream y lo mantiene abierto hasta el límite de la plataforma, normalmente minutos, con el cliente reconectándose después. Las primitivas tipo actor, como Durable Objects, sostienen WebSockets entre peticiones donde lo necesites. Consulta computación serverless para el modelo de costes que hace caras las conexiones largas con facturación por invocación.

Navegadores. Ambas API están soportadas en todos los navegadores actuales, de escritorio y móviles. EventSource es solo texto y solo GET; WebSocket soporta binario y no tiene esas restricciones.

Apps móviles. Las plataformas nativas suspenden las apps en segundo plano y cierran sus sockets. Ningún transporte sobrevive a eso; todo lo que deba llegar a un usuario en segundo plano u offline pasa por APNs, FCM o Web Push, con el canal en vivo usado solo en primer plano. Las librerías de WebSocket son maduras en iOS y Android; los clientes SSE son más ligeros, y muchos equipos usan una petición HTTP en streaming. El coste de batería lo marcan los despertares de la radio, así que un heartbeat de 20 segundos pesa más que la elección del protocolo.

Desventajas de WebSocket: los inconvenientes, explícitamente

WebSockets es potente y, a menudo, el valor por defecto equivocado. Los costes concretos:

  1. Sin reconexión ni reanudación integradas. Cada equipo reimplementa backoff, resuscripción y recuperación de mensajes perdidos.
  2. Sin headers personalizados desde el navegador. La auth va por cookies, query string o un handshake en el primer mensaje.
  3. Conexiones con estado. Sticky sessions o un almacén de estado externo; deploys blue-green y rolling más difíciles.
  4. Mal encaje con serverless. Necesita un gateway dedicado y un registro de conexiones; la facturación por minuto de conexión se acumula.
  5. Fuera de las herramientas HTTP. Sin caché HTTP, sin compresión estándar salvo que se negocie permessage-deflate, sin log de petición por mensaje, y la observabilidad exige instrumentación a medida.
  6. Fricción con proxies y redes. El Upgrade debe respetarse de extremo a extremo; algunas redes corporativas y planes de CDN lo bloquean o limitan.
  7. Sin protección de CORS. El secuestro de WebSocket cross-site es real si dependes de cookies sin comprobar Origin.
  8. Protocolo a medida por encima. El framing de mensajes, el versionado y la semántica de errores son tuyos para definirlos y mantenerlos compatibles hacia atrás.
  9. Head-of-line blocking en una única conexión TCP. Un frame grande retrasa todo lo que viene detrás; no hay priorización de streams.
  10. Mayor superficie operativa. Límites de conexión, file descriptors, CPU de TLS y pruebas de carga necesitan herramientas que entiendan el protocolo.

Nada de esto descalifica para chat o colaboración. Es la factura de la bidireccionalidad; págala solo cuando la uses.

Polling y long polling: los fallbacks

Short polling lanza una petición con un temporizador. Es universalmente compatible, cacheable y la respuesta correcta para datos que cambian cada pocos minutos. A una petición por segundo por cliente se convierte en la opción más cara de todas, con latencia acotada por el intervalo.

Long polling mantiene la petición abierta hasta que llegan datos o salta un timeout, y entonces el cliente vuelve a pedir. Aproxima el push sobre HTTP plano y funciona detrás de casi cualquier cosa. El coste es un round trip HTTP completo por mensaje, un hueco entre respuestas en el que se pierden eventos salvo que lleves un cursor, y los mismos límites de conexión de HTTP/1.1 que SSE, sin la reconexión definida por la spec.

En 2026 el long polling es un fallback para redes que rompen tanto SSE como WebSockets, no un diseño principal. Si tu librería todavía lo usa por defecto, averigua por qué.

Tabla comparativa: SSE vs WebSockets vs long polling

Criterio Server-Sent Events WebSockets Long polling
Dirección Servidor a cliente (el cliente usa peticiones normales) Full duplex Iniciado por el cliente, el servidor retiene
Transporte Stream de respuesta HTTP/1.1, HTTP/2, HTTP/3 Socket TCP con upgrade; túnel HTTP/2 rara vez desplegado Peticiones HTTP planas
Reconexión Automática, integrada en EventSource Manual Manual (cada petición)
Reanudación tras caída Last-Event-ID, definido en la spec Números de secuencia a medida Cursor a medida
Soporte binario No (texto, base64 si hace falta) Sí, frames nativos Sí (cuerpo de la respuesta)
Auth en el navegador Cookies, ticket en query o fetch con headers Cookies, ticket en query, primer mensaje Cualquier header
Compatibilidad con proxy y CDN Alta; desactiva buffering y sube timeouts Media; necesita soporte de Upgrade de extremo a extremo La más alta
Límite por origen en HTTP/1.1 6 conexiones; resuelto por HTTP/2 Conexión separada para cada uno 6 conexiones
Modelo de escalado Nodos sin estado más pub/sub, sin stickiness Pub/sub más sticky sessions o estado externo Sin estado
Encaje con serverless Bueno en funciones de streaming o edge Requiere un gateway gestionado Bueno
Overhead por mensaje Bajo (unos bytes por evento) El más bajo (2 a 14 bytes de framing) Alto (HTTP completo por mensaje)
Mejores casos de uso Notificaciones, dashboards, feeds, streaming de LLM Chat, edición colaborativa, juegos, trading Fallback, actualizaciones de baja frecuencia

Código: cliente EventSource, endpoint SSE en Node, echo WebSocket

Un endpoint SSE mínimo en Node sin frameworks. Fíjate en los headers que impiden que los proxies hagan buffer y en el id: que habilita la reanudación.

// server.js — Node 20+, sin dependencias
import http from "node:http";

http.createServer((req, res) => {
  if (req.url !== "/events") { res.writeHead(404).end(); return; }

  res.writeHead(200, {
    "Content-Type": "text/event-stream",
    "Cache-Control": "no-cache, no-transform",
    "Connection": "keep-alive",
    "X-Accel-Buffering": "no",
  });

  let id = Number(req.headers["last-event-id"] ?? 0);
  const timer = setInterval(() => {
    id += 1;
    res.write(`id: ${id}\nevent: tick\ndata: ${JSON.stringify({ t: Date.now() })}\n\n`);
  }, 1000);
  const heartbeat = setInterval(() => res.write(": ping\n\n"), 15000);

  req.on("close", () => { clearInterval(timer); clearInterval(heartbeat); });
}).listen(3000);

El lado del navegador son unas pocas líneas, y la reconexión sale gratis.

const es = new EventSource("/events", { withCredentials: true });
es.addEventListener("tick", (e) => console.log(JSON.parse(e.data)));
es.onerror = () => console.warn("disconnected, browser will retry");

Un echo WebSocket mínimo con el paquete ws. Compara lo que tiene que hacer el cliente cuando el socket cae.

// ws-server.js
import { WebSocketServer } from "ws";

const wss = new WebSocketServer({ port: 3001 });
wss.on("connection", (socket, req) => {
  if (req.headers.origin !== "https://app.example.com") { socket.close(1008); return; }
  socket.on("message", (data) => socket.send(data));
});
// client
let ws, attempt = 0;
function connect() {
  ws = new WebSocket("wss://api.example.com/ws");
  ws.onopen = () => { attempt = 0; ws.send("hello"); };
  ws.onmessage = (e) => console.log(e.data);
  ws.onclose = () => setTimeout(connect, Math.min(30000, 500 * 2 ** attempt++) * (0.5 + Math.random()));
}
connect();

Ambos servidores deberían ir detrás de TLS en producción; ninguno de los ejemplos gestiona autenticación más allá de una comprobación de Origin.

Checklist de decisión: cuándo usar cada uno

  • Chat (1:1, grupo, soporte). WebSockets. Los mensajes fluyen en ambas direcciones constantemente, y los indicadores de escritura y presencia son baratos en un socket abierto. SSE más POST funciona para widgets de soporte de bajo volumen.
  • Dashboards en vivo y monitorización. SSE. Unidireccional, texto, tolera un segundo de reconexión. Agrupa las actualizaciones en el servidor; consulta desarrollo de dashboards para el lado de los datos.
  • Notificaciones y feeds de actividad. SSE mientras la pestaña está abierta; Web Push, APNs o FCM cuando no lo está. Nunca un WebSocket solo para notificaciones.
  • Edición colaborativa. WebSockets. La sincronización con CRDT u OT necesita mensajes pequeños, frecuentes y bidireccionales, y a menudo codificaciones binarias.
  • Juegos multijugador. WebSockets hoy; WebTransport donde puedas exigir HTTP/3 y quieras datagramas no fiables para actualizaciones de posición.
  • Streaming de tokens de LLM. SSE, o un fetch en streaming que parsee text/event-stream cuando necesites headers y cancelación. Es lo que exponen las principales API de modelos, y compone bien con serverless.
  • Trading y datos de mercado. WebSockets para el flujo de órdenes; SSE es aceptable para tickers de solo lectura. Fan-out vía Redis o Kafka en cualquier caso.
  • Telemetría IoT al navegador. MQTT sobre WebSockets desde los dispositivos, pub/sub en medio, SSE o WebSockets hasta el dashboard según si los operadores envían comandos.
  • Voz o vídeo. Ninguno de los dos. Usa WebRTC, con WebSockets o SSE solo para la señalización.
  • Redes corporativas restrictivas. SSE primero, long polling como último recurso.

WebTransport: la opción emergente

WebTransport es la API del navegador sobre HTTP/3 y QUIC: múltiples streams independientes sin head-of-line blocking, y datagramas no fiables para datos en los que llegar tarde es peor que perderse. Para juegos, media y telemetría de alta frecuencia elimina los dos límites estructurales de WebSockets: un único stream TCP y entrega solo fiable.

La adopción es el problema. El soporte en navegadores es amplio en Chromium y mejora en el resto, pero servidores, balanceadores y CDN van por detrás, y las redes hostiles a UDP necesitan un camino WebSocket de todos modos. En 2026 se justifica para un conjunto estrecho de productos y es un tema de investigación para todos los demás. Abstrae el transporte para que pueda cambiar; no planifiques la migración todavía.

Recomendación

Empieza con SSE para todo lo que vaya del servidor al cliente, combinado con peticiones HTTP normales en la otra dirección. Sírvelo sobre HTTP/2, desactiva el buffering del proxy, define id: en cada evento y respáldalo con un log con replay para que Last-Event-ID recupere lo perdido. Mueve una funcionalidad a WebSockets solo cuando necesite tráfico bidireccional de alta frecuencia o frames binarios, y presupuesta la lógica de reconexión, un handshake de auth, una capa de pub/sub y sticky sessions o estado externalizado. Mantén el long polling como fallback detrás de una flag, no como diseño. En Arvucore solemos recomendar un transporte por funcionalidad, elegido con el checklist anterior, en lugar de uno para todo el producto; los sistemas que envejecen bien son aquellos en los que la arquitectura es la capa de pub/sub, no el socket.

¿Listo para Transformar tu Negocio?

Hablemos sobre cómo nuestras soluciones pueden ayudarte a alcanzar tus objetivos. Ponte en contacto con nuestros expertos hoy mismo.

Hablar con un Experto

Tags:

websockets vs. ssecomunicación en tiempo realnotificaciones pushserver-sent eventsdesventajas de websocketlong polling
Equipo Arvucore

Equipo Arvucore

El equipo editorial de Arvucore está formado por profesionales experimentados en desarrollo de software. Estamos dedicados a producir y mantener contenido de alta calidad que refleja las mejores prácticas de la industria e insights confiables.

Preguntas frecuentes

¿SSE es mejor que WebSockets?
Ninguno es mejor en general. SSE es más simple y encaja con flujos unidireccionales del servidor al cliente, como notificaciones, dashboards y streaming de tokens de LLM. WebSockets es la elección correcta cuando el cliente también necesita enviar mensajes frecuentes con baja latencia, o cuando necesitas frames binarios.
¿Cuáles son las principales desventajas de WebSockets?
Sin reconexión ni reanudación automática, sin headers personalizados en el handshake del navegador, conexiones con estado que necesitan sticky sessions o una capa de pub/sub, mal encaje con serverless y con algunos proxies o CDN, y un protocolo aparte que se salta las herramientas, la caché y la compresión estándar de HTTP.
¿SSE funciona sobre HTTP/2?
Sí. Sobre HTTP/2, cada stream SSE es un stream multiplexado en una única conexión TCP, lo que elimina el límite de seis conexiones por origen que perjudica a SSE en HTTP/1.1. La mayoría de los navegadores y proveedores de edge negocian HTTP/2 por defecto con TLS.
¿Puedo enviar headers personalizados con EventSource o WebSocket en el navegador?
No. Ninguna de las dos API del navegador permite definir un header Authorization. Usa cookies, un token de corta duración en la query string, o sustituye EventSource por fetch con un ReadableStream, que sí acepta headers.
¿El long polling sigue siendo relevante en 2026?
Solo como fallback para redes restrictivas o actualizaciones de muy baja frecuencia. Funciona en cualquier sitio, pero desperdicia peticiones, añade latencia y es más difícil de razonar que SSE, que todos los navegadores modernos soportan.
¿WebTransport reemplazará a WebSockets?
Todavía no. WebTransport corre sobre HTTP/3 y QUIC y ofrece datagramas no fiables y múltiples streams sin head-of-line blocking, pero el soporte en navegadores e infraestructura sigue siendo desigual. Trátalo como una opción para juegos y media, no como el valor por defecto.

Artículos relacionados

Desarrollo WebRTC en 2026: arquitectura, coste y alcance

Desarrollo WebRTC en 2026: arquitectura, coste y alcance

Qué resuelve WebRTC y qué tienes que construir tú: P2P vs SFU vs MCU, TURN, plataformas gestionadas vs self-hosted, seguridad y qué determina el coste.

Accesibilidad (A11y) en Desarrollo Web: Pautas WCAG 2.1

Accesibilidad (A11y) en Desarrollo Web: Pautas WCAG 2.1

Como guía de Arvucore, este artículo explica la Accesibilidad (A11y) en desarrollo web y las pautas WCAG 2.1, ofreciendo consejos prácticos para tomadores de decisiones europeos y equipos técnicos. Destaca cómo el desarrollo de accesibilidad web mejora la experiencia del usuario, cumplimiento legal y alcance de mercado, incluyendo consideraciones de diseño que integran accesibilidad temprano en los ciclos de vida del producto.

Arquitectura basada en eventos: sistemas resilientes y escalables

Arquitectura basada en eventos: sistemas resilientes y escalables

En Arvucore, exploramos cómo la arquitectura basada en eventos transforma los sistemas distribuidos modernos, permitiendo aplicaciones ágiles, resilientes y escalables. Este artículo examina los principios fundamentales, los patrones de diseño prácticos y las consideraciones operativas para la implementación de sistemas basados en eventos en entornos empresariales. Los lectores encontrarán orientación sobre opciones de arquitectura, estrategias de integración y beneficios mensurables para impulsar la agilidad empresarial y la solidez técnica en las implementaciones de producción.

Micro Frontends: Arquitectura Escalable para Grandes Aplicaciones

Micro Frontends: Arquitectura Escalable para Grandes Aplicaciones

En Arvucore, exploramos cómo los micro frontends permiten una arquitectura frontend resiliente y modular para aplicaciones a gran escala. Al descomponer interfaces de usuario monolíticas en partes implementables de forma independiente, los equipos ganan autonomía, lanzamientos más rápidos y una propiedad más clara. Este artículo describe patrones de diseño, estrategias de integración, ventajas y desventajas en términos de rendimiento y enfoques de gobernanza para ayudar a los líderes empresariales y equipos técnicos europeos a evaluar los micro frontends para su próximo gran proyecto.