SSE (Server-Sent Events) es un estándar W3C que permite al servidor enviar datos en streaming al cliente a través de una única conexión HTTP en modo unidireccional. A diferencia de WebSocket, SSE funciona sobre HTTP normal y no requiere un protocolo especial ni bibliotecas en el lado del cliente. Según la especificación W3C HTML Living Standard (2025), la API EventSource es compatible con todos los navegadores modernos, incluidos Chrome, Firefox, Safari y Edge.
Puntos clave
SSE (Server-Sent Events) es una tecnología que permite a un servidor web enviar datos al cliente en cualquier momento después de establecer una conexión. Está estandarizada por WHATWG como parte del HTML Living Standard y utiliza el tipo MIME text/event-stream. SSE admite la transmisión de datos de texto con la capacidad de especificar un identificador de mensaje, tipo de evento y retardo de reconexión.
A diferencia de WebSocket, que requiere un protocolo bidireccional y una solicitud de actualización, SSE funciona sobre HTTP normal. El servidor establece el encabezado Content-Type: text/event-stream, envía datos en fragmentos y mantiene la conexión abierta. El cliente recibe los datos a través de la API EventSource del navegador, que analiza automáticamente el stream y genera eventos.
Según CanIUse (2025), la API EventSource es compatible con el 97.5% de los navegadores a nivel mundial. No es compatible con Internet Explorer y algunos navegadores móviles (Samsung Internet anterior a la versión 7.0). Para estos casos existen polyfills que emulan EventSource a través de XHR streaming. SSE no funciona con HTTP/1.1 pipelining, pero es totalmente compatible con HTTP/2 server push.
SSE fue propuesto como parte de la especificación HTML5 en 2009 bajo el nombre Server-Sent DOM Events. La primera implementación apareció en Opera 9.0, luego en Firefox 6.0 (2011), Chrome 9.0 (2011) y Safari 5.0 (2010). En 2015, la especificación se trasladó a una sección separada del HTML Living Standard. A pesar de una década de historia, SSE sigue siendo menos popular que WebSocket debido a su naturaleza unidireccional.
El funcionamiento de SSE es el siguiente: el cliente crea una instancia de EventSource con la URL del endpoint del servidor. El navegador envía una solicitud GET con el encabezado Accept: text/event-stream. El servidor responde con el estado 200 OK y el encabezado Content-Type: text/event-stream, luego comienza a enviar datos en formato event-stream. La conexión permanece abierta hasta que el servidor envía una señal de terminación o el cliente llama a close().
En el lado del servidor, los datos se envían en fragmentos (chunked transfer encoding). Cada fragmento de datos es un mensaje de texto que consta de líneas de campos (event, data, id, retry). El servidor puede enviar mensajes en cualquier momento, lo que hace que SSE sea ideal para notificaciones y actualizaciones de estado. La conexión no requiere un intercambio constante de paquetes heartbeat (como WebSocket), aunque el campo retry controla la frecuencia de reconexión.
Según pruebas de rendimiento (2024), SSE proporciona un rendimiento de hasta 10 000 mensajes por segundo por conexión con un tamaño de mensaje de 256 bytes. En el lado del servidor, cada conexión SSE consume aproximadamente 5–10 KB de memoria, lo que permite que un servidor admita más de 50 000 conexiones simultáneas con 1 GB de RAM. Esto es significativamente menos que WebSocket debido a la ausencia de un protocolo binario.
El formato text/event-stream es un protocolo de texto simple donde cada mensaje consta de campos con nombre separados por caracteres de nueva línea. Cada campo tiene el formato “NombreDelCampo: valor”. Los mensajes se separan por dos caracteres de nueva línea (\n\n).
Campos admitidos: event (tipo de evento, por defecto message), data (cadena de datos, puede ser multilínea), id (último identificador de evento, almacenado en Last-Event-ID), retry (tiempo de reconexión en milisegundos). Los comentarios comienzan con dos puntos (:) y son ignorados por el analizador, pero se pueden usar para heartbeat.
| Campo | Obligatorio | Propósito |
|---|---|---|
| event | No | Tipo de evento (message por defecto) |
| data | Sí | Cadena de datos del mensaje |
| id | No | Identificador de evento para Last-Event-ID |
| retry | No | Retardo de reconexión en ms |
: heartbeat comment
event: update
data: {"user": "Alice", "action": "typing"}
id: 1001
event: notification
data: {"type": "info", "text": "New version available"}
data: {"type": "action", "url": "/upgrade"}
retry: 3000
event: close
data: Session ended
La API EventSource es una interfaz de navegador incorporada para recibir SSE. Para crear una conexión, simplemente llama al constructor con la URL del endpoint. EventSource establece automáticamente la conexión, maneja la reconexión y analiza los mensajes entrantes en eventos de JavaScript.
Eventos de EventSource: open (conexión establecida), message (mensaje recibido sin evento especificado), error (error de conexión). Para eventos personalizados (event: custom), puedes usar addEventListener con el nombre del evento. EventSource envía automáticamente el encabezado Last-Event-ID al reconectarse, lo que permite al servidor reanudar el stream desde donde se interrumpió.
Según la documentación de MDN (2025), EventSource admite CORS y transmisión de credenciales (withCredentials). EventSource no es adecuado para enviar encabezados personalizados o cuerpos de solicitud — se necesita una implementación manual mediante fetch + ReadableStream. EventSource no admite datos binarios — solo texto y JSON.
const eventSource = new EventSource('/api/events/stream');
eventSource.addEventListener('open', () => {
console.log('Conexión SSE establecida');
});
eventSource.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
console.log('Recibido:', data);
renderUpdate(data);
});
eventSource.addEventListener('notification', (event) => {
const notification = JSON.parse(event.data);
showNotification(notification.text);
});
eventSource.addEventListener('error', (error) => {
console.error('Error de SSE:', error);
// El navegador se reconecta automáticamente
});
// Cerrar conexión
eventSource.close();
SSE y WebSocket son tecnologías diferentes para la comunicación en tiempo real, cada una con sus propias fortalezas. WebSocket es adecuado para el intercambio bidireccional de datos (chats, juegos, edición colaborativa), mientras que SSE es para flujos unidireccionales del servidor al cliente (notificaciones, feeds de noticias, tickers).
La diferencia clave es que WebSocket requiere una solicitud de actualización de HTTP/1.1 al protocolo WebSocket (ws://), que puede ser bloqueada por proxies corporativos. SSE funciona sobre HTTP normal, pasa a través de cualquier proxy y no requiere configuración especial del servidor. SSE también es más simple de implementar — el servidor no necesita una biblioteca adicional, solo formar correctamente la respuesta HTTP.
Según pruebas comparativas (2024), en un único proceso de servidor, SSE admite entre un 30 y un 50% más de conexiones que WebSocket debido al protocolo más simple. Sin embargo, SSE tiene una latencia mayor (50–200 ms frente a 10–50 ms de WebSocket) porque SSE utiliza HTTP fragmentado en lugar de un flujo bidireccional completo con tramas binarias.
| Característica | SSE | WebSocket |
|---|---|---|
| Dirección | Servidor → cliente | Bidireccional |
| Protocolo | HTTP (text/event-stream) | ws:// / wss:// (RFC 6455) |
| Navegadores | 97.5% (EventSource incorporado) | 97% (WebSocket incorporado) |
| Datos | Solo texto / JSON | Texto + binario (Blob, ArrayBuffer) |
| Manejo de proxies | Pasa por cualquier proxy | Requiere configuración de proxy |
| Reconexión | Automática (navegador) | Implementación manual |
| Historial | Last-Event-ID | Sin historial incorporado |
Implementar SSE en el servidor no requiere bibliotecas — solo hay que establecer los encabezados HTTP correctos y enviar datos en formato text/event-stream. Veamos un ejemplo en Node.js usando el módulo http incorporado. El servidor establece los encabezados Content-Type y Cache-Control, luego envía mensajes cada N segundos.
Según MDN Web Docs (2025), los encabezados requeridos para SSE son: Content-Type: text/event-stream, Cache-Control: no-cache y Connection: keep-alive. Sin Cache-Control, el navegador puede almacenar en caché el stream SSE, lo que detendrá la entrega. Connection: keep-alive indica explícitamente al navegador que mantenga la conexión abierta.
const http = require('http');
http.createServer((req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
let eventId = 0;
const interval = setInterval(() => {
eventId++;
res.write(`id: ${eventId}\n`);
res.write(`event: update\n`);
res.write(`data: {"time": "${new Date().toISOString()}", "id":${eventId}}\n\n`);
}, 2000);
req.on('close', () => {
clearInterval(interval);
});
}).listen(3000);
from flask import Response, Flask
import time
import json
app = Flask(__name__)
@app.route('/stream')
def stream():
def generate():
event_id = 0
while True:
event_id += 1
data = json.dumps(
{'ticker': 'AAPL', 'price': 150.25})
yield f'id: {event_id}\nevent: price\ndata: {data}\n\n'
time.sleep(1)
return Response(generate(),
mimetype='text/event-stream')
El uso de SSE en aplicaciones móviles está limitado por la falta de una implementación nativa de EventSource para iOS y Android. En plataformas móviles, SSE se implementa a través de bibliotecas de terceros: en iOS — mediante URLSession con NSURLProtocol, en Android — mediante OkHttp con soporte SSE (okhttp-sse). Para React Native y Flutter, hay paquetes que emulan EventSource.
En iOS, la implementación nativa de SSE es posible a través de URLSessionDataDelegate. Al recibir datos en el método urlSession(_:dataTask:didReceive:), la aplicación acumula un búfer y analiza el formato event-stream manualmente. Según el blog de desarrollo iOS (2024), el consumo de batería con SSE en iOS es un 40% menor que con una conexión WebSocket constante debido a la ausencia de paquetes heartbeat.
En Android, OkHttp proporciona la clase EventSource.Factory para suscribirse a streams SSE. Las aplicaciones Android pueden usar SSE para notificaciones cuando FCM no está disponible, o para sincronización de datos en segundo plano. SSE en Android funciona bien con WorkManager para tareas en segundo plano de larga duración. Según la documentación de OkHttp (2025), okhttp-sse admite reconexión automática con un listener personalizado.
Preguntas frecuentes
SSE es transmisión unidireccional (servidor → cliente) sobre HTTP, no requiere bibliotecas en el cliente. WebSocket es transmisión bidireccional con un protocolo binario. SSE es más simple de implementar, WebSocket es adecuado para tareas donde el cliente también envía datos.
No, SSE solo transmite datos de texto. Para datos binarios (imágenes, audio), se requiere codificación Base64, que aumenta el tamaño en un 33%. Para flujos binarios, es mejor usar WebSocket.
EventSource se reconecta automáticamente cuando ocurre una interrupción. El tiempo de retardo se establece mediante el campo retry en el stream (por defecto 1000 ms). Al reconectarse, el navegador envía el encabezado Last-Event-ID, lo que permite al servidor reanudar el stream desde donde se interrumpió.
Cada navegador tiene un límite en el número de conexiones HTTP simultáneas a un dominio. Para HTTP/1.1 — 6–8 conexiones por dominio, para HTTP/2 — hasta 100. SSE usa una conexión, por lo que no hay competencia con otras solicitudes.
SSE es adecuado solo para recibir mensajes (entrantes). Para enviar mensajes (salientes), se requiere una solicitud HTTP separada (POST). Para un chat completo, es más conveniente usar WebSocket o Socket.IO con comunicación bidireccional en una única conexión.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también