WebSocket vs webhook vs SSE

WebSocket abre um canal nos dois sentidos. SSE envia eventos do servidor para o navegador por HTTP. Um webhook é uma requisição HTTP que um serviço faz para a sua URL quando algo acontece. A escolha depende de quem fala com quem.

Atualizado em 5 min de leitura

Objetivos de aprendizado

Depois de ler este artigo, você vai conseguir:

  • Distinguir quem inicia a comunicação e em que direção os dados fluem em cada opção
  • Escolher entre WebSocket, SSE e webhook conforme o caso de uso
  • Ver um exemplo mínimo em Node.js das três técnicas
Nesta página

Uma requisição HTTP normal é uma pergunta com resposta: o cliente pergunta, o servidor responde e a conversa termina. Quando você precisa que algo chegue sem perguntar a cada poucos segundos (uma mensagem de chat, um pagamento aprovado, um preço que mudou), aparecem três opções: WebSocket, Server-Sent Events (SSE) e webhooks.

Elas se parecem no resultado, mas resolvem problemas diferentes. A pergunta que organiza tudo é: quem fala com quem, e em que direção?

WebSocketClienteServidorabremensagensnos dois sentidosSSENavegadorServidorabreeventossó do servidorWebhookServiçoexternoSeu servidorPOST1 POST por evento
WebSocket e SSE começam no cliente e ficam abertos; o webhook começa no serviço externo, com um POST por evento.

O que é cada uma?#

WebSocket é um canal bidirecional sobre uma única conexão TCP. Ele começa como uma requisição HTTP com Upgrade, o servidor responde 101 Switching Protocols e, daí em diante, cliente e servidor trocam mensagens quando quiserem. Usa os esquemas ws:// e wss:// (este último, com TLS). É definido na RFC 6455. Mais detalhes em O que é WebSocket.

SSE é uma resposta HTTP que não termina. O navegador abre a conexão com EventSource, o servidor responde com Content-Type: text/event-stream e vai escrevendo eventos de texto. A informação só viaja do servidor para o cliente.

Webhook não é um protocolo, é um padrão: um serviço externo (como Stripe ou GitHub) faz uma requisição HTTP POST para uma URL sua quando um evento acontece. É comunicação entre servidores, sem navegador no meio.

Quais são as diferenças?#

WebSocket SSE Webhook
Direção Nos dois sentidos Servidor para o cliente Serviço externo para o seu servidor
Quem inicia O cliente abre o canal O cliente abre a conexão O serviço chama a sua URL
Conexão Persistente Persistente Uma requisição por evento
Formato Texto ou binário Texto UTF-8 Normalmente JSON
Reconexão Você programa Automática no navegador Depende do serviço emissor
Cliente típico Navegador, app, outro servidor Navegador Outro servidor

Dois detalhes práticos do SSE: sobre HTTP/1.1, o navegador limita a 6 conexões abertas por domínio (por navegador, não por aba), enquanto com HTTP/2 o limite negociado por padrão é de 100 streams. E, como o EventSource reconecta sozinho, o servidor pode ajustar a espera com o campo retry.

Quando escolher WebSocket?#

Quando o cliente também envia dados com frequência e você precisa de baixa latência nos dois sentidos: chats, jogos multiplayer, edição colaborativa, cursores compartilhados. Se só o servidor fala, WebSocket é mais do que você precisa.

Em troca, você perde parte do que o HTTP já resolve: você mesmo cuida da reconexão, dos batimentos (ping/pong para detectar conexões mortas) e da autenticação das mensagens.

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) => {
    // repassa para todos os clientes conectados
    for (const client of wss.clients) {
      if (client.readyState === client.OPEN) client.send(data.toString());
    }
  });
});

No navegador: const ws = new WebSocket("wss://seu-dominio.com"); ws.onmessage = (e) => console.log(e.data);. Para colocar esse servidor no ar, veja como hospedar um servidor WebSocket.

Quando escolher SSE?#

Quando você só precisa empurrar dados para o navegador: notificações, progresso de uma tarefa, um placar ao vivo, a resposta de um modelo de IA que chega em pedaços. É HTTP puro, não precisa de biblioteca no cliente e o navegador reconecta sozinho.

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 fonte = new EventSource("/eventos");
fonte.addEventListener("tick", (e) => console.log(JSON.parse(e.data)));

Cada mensagem termina com uma linha em branco. Os campos reconhecidos são event, data, id e retry. Se o cliente precisar enviar algo, use uma requisição fetch separada: a combinação de SSE com REST resolve muitos apps que parecem pedir WebSocket.

Quando escolher um webhook?#

Quando outro serviço precisa avisar o seu backend: um pagamento confirmado, um push num repositório, uma mensagem recebida. Você evita consultar a API dele a cada minuto (polling) e recebe o evento na hora. Para o caso do Discord, veja webhook vs bot.

O seu endpoint precisa ser público, responder rápido com um 2xx e verificar a assinatura, porque qualquer pessoa pode fazer um POST para a sua URL. O GitHub, por exemplo, assina o corpo com HMAC-SHA256 no cabeçalho X-Hub-Signature-256 e recomenda uma comparação de tempo constante.

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

const app = express();

// o HMAC é calculado sobre o corpo cru, não sobre o JSON já interpretado
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  if (!Buffer.isBuffer(req.body)) return res.sendStatus(415); // sem corpo JSON
  const esperado =
    "sha256=" +
    crypto.createHmac("sha256", process.env.WEBHOOK_SECRET).update(req.body).digest("hex");
  const recebido = req.get("X-Hub-Signature-256") ?? "";

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

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

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

O nome do cabeçalho e o algoritmo mudam de serviço para serviço: confira a documentação dele.

Dá para combinar?#

Dá, e é o comum. Um caso típico: um provedor de pagamentos avisa o seu servidor com um webhook de pagamento concluído, e o seu servidor repassa ao navegador do usuário com SSE ou WebSocket para a tela mudar sem recarregar. O webhook leva o dado até o seu backend; SSE ou WebSocket o levam até o cliente.

Regra curta: se o destino é um navegador que só escuta, SSE. Se o navegador também fala muito, WebSocket. Se o destino é o seu servidor e o emissor é um serviço externo, webhook. Não existe vencedor universal. Se o que você quer é consultar ou alterar dados, uma API REST continua sendo a base.

Como fazer isso na Square Cloud#

Os três padrões precisam de um processo sempre ligado com uma URL pública, e é isso que uma aplicação web na Square Cloud oferece: containers sem modo de suspensão e um subdomínio *.squareweb.app com HTTPS em todos os planos. A rede suporta WebSockets, então o wss:// do exemplo funciona nesse subdomínio, e o proxy deixa WebSocket e SSE passarem sem buffer e sem cortar conexões longas.

Para o webhook, a URL da sua aplicação é a que você cadastra no serviço emissor. Guarde o segredo da assinatura como variável de ambiente no painel, não no código. Você pode usar Node.js, Python, Go e outros dos runtimes disponíveis.

O plano Hobby começa em R$ 12,49 por mês com 1 GB de RAM, e a RAM é compartilhada entre todas as suas aplicações. Para publicar uma API completa, comece por Como hospedar uma API e confira o checklist de produção. A página de hospedagem de APIs resume o que você precisa.

Hospedagem de APIs

APIs em containers sempre ligados, sem cold start

Saiba mais

Perguntas frequentes

SSE é mais rápido que WebSocket?

Não existe uma diferença de velocidade que decida a escolha. Depois de abertos, os dois enviam eventos na hora. A diferença real é a direção: SSE só vai do servidor para o cliente, WebSocket vai nos dois sentidos.

Posso usar um webhook para atualizar uma página em tempo real?

Não diretamente. Um webhook chega ao seu servidor, não ao navegador. O seu servidor precisa repassar o dado ao navegador com SSE ou WebSocket.

WebSocket substitui as requisições HTTP normais?

Não. Para consultar ou alterar recursos, uma API REST continua sendo o mais simples. WebSocket é para quando você precisa de mensagens frequentes nos dois sentidos.

SSE reconecta sozinho se a conexão cair?

Sim. O EventSource tenta de novo automaticamente, e o servidor pode indicar o tempo de espera com o campo retry. Com WebSocket, você mesmo programa a reconexão.

Como sei que um webhook vem do serviço real?

Verificando a assinatura. Muitos serviços enviam um HMAC do corpo num cabeçalho, como o X-Hub-Signature-256 do GitHub, e você deve compará-lo com o seu segredo usando uma comparação de tempo constante.

Próximo artigoO que é um webhookWebhook é uma requisição HTTP que um serviço envia para a sua URL quando um evento acontece. Veja como funciona, como verificar a assinatura e um exemplo em Node.js.