WebSocket vs webhook vs SSE

WebSocket abre un canal en ambos sentidos. SSE envía eventos del servidor al navegador por HTTP. Un webhook es una petición HTTP que un servicio hace a tu URL cuando algo ocurre. Se elige según quién habla y con quién.

Actualizado el 5 min de lectura

Objetivos de aprendizaje

Después de leer este artículo podrás:

  • Distinguir quién inicia la comunicación y en qué dirección fluyen los datos en cada opción
  • Elegir entre WebSocket, SSE y webhook según el caso de uso
  • Ver un ejemplo mínimo en Node.js de las tres técnicas
En esta página

Una petición HTTP normal es una pregunta con respuesta: el cliente pregunta, el servidor contesta y la conversación termina. Cuando necesitas que algo llegue sin preguntar cada pocos segundos (un mensaje de chat, un pago aprobado, un precio que cambia), aparecen tres opciones: WebSocket, Server-Sent Events (SSE) y webhooks.

Se parecen en el resultado, pero resuelven problemas distintos. La pregunta que ordena todo es: ¿quién habla con quién, y en qué dirección?

WebSocketClienteServidorabremensajesen ambos sentidosSSENavegadorServidorabreeventossolo del servidorWebhookServicioexternoTu servidorPOST1 POST por evento
WebSocket y SSE empiezan en el cliente y quedan abiertos; el webhook empieza en el servicio externo, con un POST por evento.

¿Qué es cada una?#

WebSocket es un canal bidireccional sobre una sola conexión TCP. Empieza como una petición HTTP con Upgrade, el servidor responde 101 Switching Protocols y desde ahí cliente y servidor se envían mensajes cuando quieran. Usa los esquemas ws:// y wss:// (este último, con TLS). Está definido en la RFC 6455. Más detalle en Qué es WebSocket.

SSE es una respuesta HTTP que no termina. El navegador abre la conexión con EventSource, el servidor responde con Content-Type: text/event-stream y va escribiendo eventos de texto. Solo viaja información del servidor al cliente.

Webhook no es un protocolo, es un patrón: un servicio externo (por ejemplo Stripe o GitHub) hace una petición HTTP POST a una URL tuya cuando ocurre un evento. Es comunicación entre servidores, sin navegador de por medio.

¿Cuáles son las diferencias?#

WebSocket SSE Webhook
Dirección Ambos sentidos Servidor al cliente Servicio externo a tu servidor
Quién inicia El cliente abre el canal El cliente abre la conexión El servicio llama a tu URL
Conexión Persistente Persistente Una petición por evento
Formato Texto o binario Texto UTF-8 Normalmente JSON
Reconexión La programas tú Automática en el navegador Depende del servicio emisor
Cliente típico Navegador, app, otro servidor Navegador Otro servidor

Dos detalles prácticos de SSE: sobre HTTP/1.1 el navegador limita a 6 conexiones abiertas por dominio (por navegador, no por pestaña), mientras que con HTTP/2 el límite negociado por defecto es de 100 streams. Y como EventSource reconecta solo, el servidor puede ajustar la espera con el campo retry.

¿Cuándo elegir WebSocket?#

Cuando el cliente también envía datos con frecuencia y necesitas baja latencia en los dos sentidos: chats, juegos multijugador, edición colaborativa, cursores compartidos. Si solo el servidor habla, WebSocket es más de lo que necesitas.

A cambio, pierdes parte de lo que HTTP ya resuelve: tú gestionas la reconexión, los latidos (ping/pong para detectar conexiones muertas) y la autenticación del mensaje.

js
// npm install ws
import { WebSocketServer } from "ws";

const wss = new WebSocketServer({ port: Number(process.env.PORT) || 8080 });

wss.on("connection", (socket) => {
  socket.on("message", (data) => {
    // reenvía a todos los clientes conectados
    for (const client of wss.clients) {
      if (client.readyState === client.OPEN) client.send(data.toString());
    }
  });
});

Desde el navegador: const ws = new WebSocket("wss://tu-dominio.com"); ws.onmessage = (e) => console.log(e.data);. Para poner este servidor en línea, mira cómo hospedar un servidor WebSocket.

¿Cuándo elegir SSE?#

Cuando solo necesitas empujar datos al navegador: notificaciones, progreso de una tarea, un marcador en vivo, la respuesta de un modelo de IA que llega por trozos. Es HTTP puro, no necesita bibliotecas en el cliente y el navegador reconecta solo.

js
// npm install express@5
import express from "express";

const app = express();

app.get("/eventos", (req, res) => {
  res.set({
    "Content-Type": "text/event-stream",
    "Cache-Control": "no-cache",
    Connection: "keep-alive",
  });
  res.flushHeaders();

  const timer = setInterval(() => {
    res.write(`event: tick\ndata: ${JSON.stringify({ hora: new Date() })}\n\n`);
  }, 1000);

  req.on("close", () => clearInterval(timer));
});

app.listen(Number(process.env.PORT) || 3000);
js
const fuente = new EventSource("/eventos");
fuente.addEventListener("tick", (e) => console.log(JSON.parse(e.data)));

Cada mensaje termina con una línea en blanco. Los campos reconocidos son event, data, id y retry. Si el cliente necesita enviar algo, usa una petición fetch aparte: la combinación SSE más REST cubre muchas apps que parecen pedir WebSocket.

¿Cuándo elegir un webhook?#

Cuando otro servicio debe avisar a tu backend: un pago confirmado, un push a un repositorio, un mensaje entrante. Evitas consultar su API cada minuto (polling) y recibes el evento al momento. Para el caso de Discord, mira webhook vs bot.

Tu endpoint debe ser público, responder rápido con un 2xx y verificar la firma, porque cualquiera puede hacer un POST a tu URL. GitHub, por ejemplo, firma el cuerpo con HMAC-SHA256 en la cabecera X-Hub-Signature-256 y recomienda una comparación de tiempo constante.

js
import crypto from "node:crypto";
import express from "express";

const app = express();

// el HMAC se calcula sobre el cuerpo crudo, no sobre el JSON ya parseado
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  if (!Buffer.isBuffer(req.body)) return res.sendStatus(415); // sin cuerpo JSON
  const esperado =
    "sha256=" +
    crypto.createHmac("sha256", process.env.WEBHOOK_SECRET).update(req.body).digest("hex");
  const recibido = req.get("X-Hub-Signature-256") ?? "";

  const a = Buffer.from(esperado);
  const b = Buffer.from(recibido);
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    return res.sendStatus(401);
  }

  const evento = JSON.parse(req.body.toString());
  console.debug("evento recibido", evento.action);
  res.sendStatus(204);
});

app.listen(Number(process.env.PORT) || 3000);

El nombre de la cabecera y el algoritmo cambian según el servicio: revisa su documentación.

¿Se pueden combinar?#

Sí, y es lo habitual. Un caso típico: un proveedor de pagos avisa a tu servidor con un webhook de pago completado, y tu servidor lo reenvía al navegador del usuario con SSE o WebSocket para que la pantalla cambie sin recargar. El webhook trae el dato hasta tu backend; SSE o WebSocket lo llevan hasta el cliente.

Regla corta: si el destino es un navegador y solo escucha, SSE. Si el navegador también habla mucho, WebSocket. Si el destino es tu servidor y el emisor es un servicio externo, webhook. No hay un ganador universal. Si lo que buscas es consultar o modificar datos, una API REST sigue siendo la base.

Cómo hacerlo en Square Cloud#

Los tres patrones necesitan un proceso siempre encendido con una URL pública, y es lo que da una aplicación web en Square Cloud: contenedores sin modo de suspensión y un subdominio *.squareweb.app con HTTPS en todos los planes. La red admite WebSockets, así que el wss:// del ejemplo funciona sobre ese subdominio, y el proxy deja pasar WebSocket y SSE sin buffer y sin cortar conexiones largas.

Para el webhook, la URL de tu aplicación es la que registras en el servicio emisor. Guarda el secreto de firma como variable de entorno en el panel, no en el código. Puedes usar Node.js, Python, Go y otros de los runtimes disponibles.

El plan Hobby arranca en R$12,49 al mes con 1 GB de RAM, y la RAM se comparte entre todas tus aplicaciones. Para publicar una API completa, empieza por Cómo hospedar una API y revisa el checklist de producción. La página de hospedaje de APIs resume lo que necesitas.

Hosting de APIs

APIs en contenedores siempre encendidos, sin cold start

Más información

Preguntas frecuentes

¿SSE es más rápido que WebSocket?

No hay una diferencia de velocidad que decida la elección. Una vez abiertos, ambos envían eventos al instante. La diferencia real es la dirección: SSE solo va del servidor al cliente, WebSocket va en los dos sentidos.

¿Puedo usar un webhook para actualizar una página en tiempo real?

No directamente. Un webhook llega a tu servidor, no al navegador. Tu servidor tiene que reenviar el dato al navegador con SSE o WebSocket.

¿WebSocket reemplaza a las peticiones HTTP normales?

No. Para consultar o modificar recursos, una API REST sigue siendo lo más simple. WebSocket es para cuando necesitas mensajes frecuentes en ambos sentidos.

¿SSE se reconecta solo si se corta la conexión?

Sí. EventSource reintenta automáticamente y el servidor puede indicar el tiempo de espera con el campo retry. Con WebSocket tienes que programar la reconexión tú.

¿Cómo sé que un webhook viene del servicio real?

Verificando la firma. Muchos servicios envían un HMAC del cuerpo en una cabecera, por ejemplo X-Hub-Signature-256 en GitHub, y debes compararlo con tu secreto usando una comparación de tiempo constante.

Siguiente artículoQué es un webhookUn webhook es una petición HTTP que un servicio envía a tu URL cuando ocurre un evento. Aprende cómo funciona, cómo verificar la firma y un ejemplo en Node.js.