---
term: 'SSE vs. WebSockets vs. Polling'
seoTitle: 'SSE vs. WebSockets vs. Polling: Como Escolher o Transporte de Tempo Real'
headline: 'Server-Sent Events vs. WebSockets vs. Polling: qual você deveria usar?'
slug: sse-vs-websockets-vs-polling
category: api-realtime
shortDefinition: 'Polling é um modelo pull em que clientes perguntam repetidamente; SSE e WebSockets mantêm uma conexão aberta para o servidor fazer push em tempo real.'
relatedTerms:
  - websockets-real-time-sync
  - real-time-live-queries
  - pub-sub-pattern
  - api-payload-optimization
contrastsWith:
  - websockets-real-time-sync
aboutTerms:
  - 'Server-Sent Events (SSE)'
  - 'WebSockets'
  - 'Long Polling'
  - 'Short Polling'
faq:
  - question: 'O que é melhor, SSE ou WebSockets?'
    answer: 'Nenhum dos dois universalmente — a pergunta é a direção. SSE é a ferramenta mais simples quando os dados fluem num sentido só, do servidor para o cliente: HTTP puro, reconexão automática, funciona através de proxies comuns. WebSockets justificam sua complexidade extra quando o cliente também precisa enviar em tempo real — chat, jogos, edição colaborativa.'
  - question: 'SSE é mais rápido que polling?'
    answer: 'Em latência de entrega, decisivamente: os eventos chegam quando acontecem, enquanto o polling tem em média metade do intervalo de poll mais um round trip. Também é mais barato — uma conexão mantida em vez de um fluxo de ciclos request/response quase sempre vazios, cada um pagando o overhead completo de headers HTTP.'
  - question: 'Quando devo usar long polling?'
    answer: 'Como fallback, não como primeira escolha: ele existe para ambientes em que conexões persistentes falham — intermediários legados, proxies que removem o upgrade de WebSocket ou bufferizam streams. O servidor segura cada request aberta até chegar dado, o que aproxima o push ao custo de churn de reconexão e overhead de headers por request.'
  - question: 'Quantas conexões SSE um navegador pode abrir?'
    answer: 'Sobre HTTP/1.1, seis por origem — e o limite é compartilhado entre abas, um footgun documentado em que um dashboard aberto em sete abas trava silenciosamente. Sobre HTTP/2, a restrição passa a ser o número de streams concorrentes multiplexados numa única conexão (por padrão em torno de cem), o que na prática aposenta o problema.'
  - question: 'SSE reconecta automaticamente?'
    answer: 'Sim — e é o recurso que mais o distingue de WebSockets crus. O EventSource refaz sozinho conexões caídas, respeita um intervalo de retry definido pelo servidor e envia o ID do último evento recebido num header Last-Event-ID, para o servidor retomar o stream sem lacunas. Reconexão de WebSocket é código que você escreve.'
  - question: 'SSE pode enviar dados binários?'
    answer: 'Não — o stream é texto UTF-8 por especificação; payloads binários precisam ser codificados, com cerca de um terço de overhead de tamanho. WebSockets carregam frames binários nativamente, o que importa para áudio, protocol buffers e qualquer coisa que já seja compacta.'
  - question: 'O que os apps de chat de IA usam para fazer streaming das respostas?'
    answer: 'Server-Sent Events, quase universalmente: geração token a token é streaming de texto numa direção só, que é exatamente o formato do SSE — HTTP puro na saída, sem negociação de upgrade, retomada automática. WebSockets aparecem em produtos de IA só quando o cliente precisa interromper ou falar no meio do stream, como em interfaces de voz.'
  - question: 'Qual é a ordem de fallback para recursos de tempo real?'
    answer: 'Detecte o suporte e degrade: WebSocket onde o caminho permite, SSE onde só o push do servidor é necessário ou os upgrades falham, long polling como denominador comum mais baixo. Bibliotecas maduras de tempo real negociam essa escada automaticamente — uma das razões pelas quais sockets crus raramente são usados sem camada em produção.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'Server-sent events — WHATWG HTML Living Standard'
    url: 'https://html.spec.whatwg.org/multipage/server-sent-events.html'
  - name: 'RFC 6455 — The WebSocket Protocol'
    url: 'https://datatracker.ietf.org/doc/html/rfc6455'
  - name: 'Using server-sent events — MDN Web Docs'
    url: 'https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events'
  - name: 'RFC 6202 — Known Issues with Long Polling and HTTP Streaming'
    url: 'https://datatracker.ietf.org/doc/html/rfc6202'
cta:
  title: 'Pule a decisão de transporte'
  text: 'As Live Queries do Back4app entregam atualizações em tempo real sobre uma frota gerenciada de WebSockets — inscreva-se na consulta que você já tem e deixe a plataforma ser dona das conexões, das reconexões e do fan-out.'
  linkText: 'Comece grátis'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-08-21'
translationKey: sse-vs-websockets-vs-polling
---

**Polling é um modelo pull em que clientes perguntam repetidamente; SSE e WebSockets mantêm uma conexão aberta para o servidor fazer push em tempo real.** Escolher entre eles são, na verdade, três perguntas — em que direção os dados fluem, com que frequência mudam e que infraestrutura fica no meio do caminho — e a resposta honesta varia por feature, não por app.

## Principais pontos

| Pergunta | Resposta |
| --- | --- |
| Short polling | Perguntar num timer — simples, amigável a cache, requests quase todas desperdiçadas |
| Long polling | O servidor segura a request até chegar dado — push simulado sobre HTTP puro |
| SSE | Um stream HTTP, eventos de texto servidor → cliente, reconexão automática embutida |
| WebSockets | Um socket, full-duplex, com suporte a binário — o protocolo é seu |
| A regra prática | Uma direção → SSE · duas direções → WebSockets · mudanças raras → polling está ótimo |

## O código, lado a lado

```js
// 1 · Short polling — pergunta num timer
setInterval(async () => {
  const res = await fetch('/api/messages?since=' + lastId);
  render(await res.json());              // quase sempre vazio — headers pagos mesmo assim
}, 2000);

// 2 · Server-Sent Events — um stream HTTP, o servidor envia eventos de texto
const events = new EventSource('/api/stream');
events.onmessage = (e) => render(JSON.parse(e.data));   // reconecta sozinho

// 3 · WebSocket — um socket, as duas direções
const ws = new WebSocket('wss://api.example.com/live');
ws.onmessage = (e) => render(JSON.parse(e.data));
ws.send(JSON.stringify({ type: 'typing' }));            // o cliente também faz push
```

O que a maioria dos apps realmente entrega — uma camada de subscription que é dona do transporte por você:

**JavaScript:**

```javascript
// JavaScript / Node.js — Back4app JS SDK
// The polling replacement: subscribe once, receive pushes
const query = new Parse.Query('Message');
query.equalTo('room', 'general');
const subscription = await query.subscribe();    // WebSocket under the hood
subscription.on('create', (msg) => render(msg)); // pushed, not polled
// subscription.unsubscribe() when the screen closes
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// The polling replacement: subscribe once, receive pushes
final liveQuery = LiveQuery();
final query = QueryBuilder<ParseObject>(ParseObject('Message'))
  ..whereEqualTo('room', 'general');
final subscription = await liveQuery.client.subscribe(query); // WebSocket under the hood
subscription.on(LiveQueryEvent.create, (msg) => render(msg)); // pushed, not polled
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// The polling replacement: subscribe once, receive pushes
let query = Message.query("room" == "general")
let subscription = try await query.subscribe() // WebSocket under the hood
subscription.handleEvent { _, event in
    if case .created(let msg) = event { render(msg) } // pushed, not polled
}
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// The polling replacement: subscribe once, receive pushes
val client = ParseLiveQueryClient.Factory.getClient()
val query = ParseQuery.getQuery<ParseObject>("Message")
query.whereEqualTo("room", "general")
val subscription = client.subscribe(query) // WebSocket under the hood
subscription.handleEvent(SubscriptionHandling.Event.CREATE) { _, msg ->
    render(msg) // pushed, not polled
}
```

## Como cada técnica funciona

**Short polling** é um `setInterval` em volta de um fetch: perguntar a cada *n* segundos se algo mudou. Cada ciclo paga uma request/response HTTP completa — headers, auth, roteamento — geralmente para ouvir "nada ainda", e o atraso médio de entrega é metade do intervalo mais um round trip.

**Long polling** move a espera para o lado do servidor: o cliente pergunta, o servidor *segura a request aberta* até chegar dado ou estourar um timeout, e o cliente pergunta de novo imediatamente. Aproxima o push sobre HTTP puro — a gambiarra da era Comet, com seus custos conhecidos (churn de reconexão, headers por request, cuidado com ordenação) catalogados na [RFC 6202](https://datatracker.ietf.org/doc/html/rfc6202).

**Server-Sent Events** tornam permanente a resposta segurada: uma resposta HTTP com `Content-Type: text/event-stream` que nunca termina, pela qual o servidor escreve eventos UTF-8 (campos `data:`, `event:`, `id:`, `retry:`, conforme o [padrão WHATWG](https://html.spec.whatwg.org/multipage/server-sent-events.html)). O `EventSource` do navegador a consome — e reconecta automaticamente, retomando via `Last-Event-ID`.

**WebSockets** saem do HTTP por completo: um handshake faz o upgrade da conexão (`101 Switching Protocols`, [RFC 6455](https://datatracker.ietf.org/doc/html/rfc6455)), e a partir daí os dois lados trocam frames de texto ou binários com ~2–14 bytes de overhead, full-duplex, até alguém fechar o socket. Capacidade máxima — e tudo acima do frame (formato das mensagens, acks, reconexão, retomada) é seu para projetar.

```mermaid
flowchart LR
  accTitle: Pull do polling versus push de SSE e WebSocket
  accDescr: Com polling o cliente pede atualizações repetidamente ao servidor e a maioria das respostas volta vazia. Com Server-Sent Events o servidor faz push de eventos ao cliente por um stream HTTP mantido. Com WebSockets cliente e servidor trocam frames nas duas direções por um socket persistente.
  subgraph P["Polling — pull"]
    C1["Cliente"] -->|"pergunta a cada n s (quase sempre vazio)"| S1["Servidor"]
  end
  subgraph E["SSE — push"]
    S2["Servidor"] -->|"um stream HTTP de eventos"| C2["Cliente<br/>(EventSource)"]
  end
  subgraph W["WebSocket — duplex"]
    C3["Cliente"] -->|"frames"| S3["Servidor"]
    S3 -->|"frames"| C3
  end
```

## SSE vs. WebSockets vs. long polling vs. short polling

| | Short polling | Long polling | SSE | WebSockets |
| --- | --- | --- | --- | --- |
| Direção | Pull | Push simulado | Servidor → cliente | Full-duplex |
| Protocolo | HTTP puro | HTTP puro | Stream HTTP puro | Protocolo próprio após o upgrade |
| Latência de entrega | intervalo/2 + RTT | ~RTT | ~RTT | ~RTT |
| Payloads | Qualquer | Qualquer | Só texto UTF-8 | Texto + binário |
| Reconexão automática | Trivial (próximo poll) | Loop de re-request | **Embutida + Last-Event-ID** | Você escreve |
| Atrito com proxy/firewall | Nenhum | Baixo | Baixo (ressalvas de buffering) | O upgrade pode ser removido |
| Estado no servidor | Nenhum | Requests seguradas | Streams abertos | Sockets presos a nós |
| Complexidade | Trivial | Moderada | Baixa | A mais alta |
| Ponto ideal | Mudanças raras | Fallback legado | Feeds, notificações, streams de IA | Chat, jogos, colaboração |

## Quanto custa o polling? A matemática do overhead

A comparação que nenhuma página de ranking faz — 1.000 clientes num poll de 2 segundos versus os mesmos 1.000 em push:

```text
1.000 clientes, polling de 2 s            1.000 clientes, push
→ 500 requests/segundo sustentadas        → 0 requests em repouso
→ ~800 B de headers por ciclo             → framing de evento SSE ~5 B
→ ~0,4 MB/s de puro imposto de headers    → overhead de frame WebSocket 2–14 B
→ quase toda resposta vazia               → bytes só fluem quando existe dado
→ atraso médio de entrega: 1 s + RTT      → atraso de entrega: ~RTT
```

A lição corta dos dois lados. Push ganha de lavada quando as atualizações são frequentes e a latência importa. Mas se os dados mudam de hora em hora, aquelas 500 req/s nunca se materializam — um poll gentil (ou refetch ao focar) é amigável a cache, debugável com curl, compatível com serverless e livre de estado de conexão. Descartar o polling por completo é moda, não engenharia.

## Reconexão: o diferencial silencioso

Conexões caem — trocas de célula, tampas de laptop, timeouts de inatividade de proxy (muitas vezes 30–120 s, e é por isso que streams SSE enviam keep-alives de comentário e WebSockets trocam frames de ping/pong). O que acontece em seguida é o que separa os transportes. O contrato do SSE resolve: o navegador tenta de novo com o atraso `retry` definido pelo servidor e apresenta `Last-Event-ID`, de modo que um servidor que mantém um buffer curto de eventos retoma o stream sem lacunas. Um WebSocket cru simplesmente fecha: reconexão com backoff exponencial, recuperação de mensagens perdidas e protocolo de retomada são todos código de aplicação — o item mais subestimado de "a gente só usa WebSockets". De qualquer forma, um cliente offline por minutos precisa de *catch-up* (reexecutar a consulta base), não só de reconexão — transportes de push entregam deltas, e deltas pressupõem uma linha de base.

## Por que o chat de IA faz streaming por SSE

Saída de modelo token a token é a carga perfeita para SSE: estritamente unidirecional, texto, em rajadas, sobre HTTP puro que todo proxy e CDN entende, com semântica de retomada para gerações interrompidas. É por isso que as APIs de LLM esmagadoramente transmitem completions como `text/event-stream` — e por isso o padrão vale conhecer além dos chatbots: feeds de progresso, logs de build e dashboards têm o mesmo formato. WebSockets entram nos produtos de IA na camada de voz, em que o usuário interrompe no meio do stream — no momento em que o cliente precisa responder, o imposto do duplex compra alguma coisa.

## Escalando push: por que statefulness importa

Polling e SSE são HTTP comum para um load balancer; qualquer servidor responde qualquer request (o SSE segura um stream, mas mantém a semântica HTTP, exigindo apenas proxies sem buffering). WebSockets são *estado*: cada socket prende um cliente a um processo, então escalar horizontalmente significa balanceamento consciente de conexões, drenagem nos deploys e um backplane de [pub/sub](/glossary/pub-sub-pattern/) (comumente Redis) para que uma mensagem publicada no servidor A alcance sockets mantidos pelo servidor B. No HTTP/1.1, o SSE tem seu próprio footgun famoso — seis conexões por origem *compartilhadas entre abas* ([o alerta do MDN](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)) — aposentado pelo HTTP/2, em que os streams se multiplexam numa única conexão. Nada disso é exótico; tudo isso é o motivo de existirem camadas gerenciadas de tempo real.

## Casos de uso comuns

- **Feeds de notificações e tickers** — uma direção, texto, frequente: o quintal do SSE.
- **Streaming de respostas de IA** — o caso matador atual do SSE; uma direção, texto em tokens, retomada em caso de queda.
- **Chat e colaboração** — mensagens fluem nas duas direções com baixa latência: [WebSockets](/glossary/pt/websockets/), normalmente via uma camada gerenciada.
- **Dashboards ao vivo** — push de resultados de consulta; na prática, uma subscription de [live query](/glossary/pt/live-queries-tempo-real/), não um transporte feito à mão.
- **Dados que mudam devagar** — estoque que atualiza de hora em hora, telas de configurações: polling ou refetch ao focar, honestamente.

## Qual transporte você deveria usar? Matriz de decisão

| Sua situação | Escolha |
| --- | --- |
| Só servidor → cliente (feeds, streams, progresso) | SSE |
| Cliente e servidor enviam em tempo real | WebSockets |
| Atualizações mais raras que a cada poucos minutos | Short polling / refetch ao focar |
| Proxies hostis, infraestrutura legada | Long polling como fallback |
| Payloads binários ou de alta frequência | WebSockets |
| Plataforma serverless, timeouts de função | Polling, ou SSE via hosts com suporte a streaming |
| "Eu só quero dados ao vivo na tela" | Uma camada de live query que seja dona do transporte |

## Limitações e trade-offs

- **SSE é só texto e só de ida.** Binário precisa de codificação; qualquer conversa cliente-para-servidor viaja em requests HTTP separadas — ótimo para acks, errado para chat.
- **WebSockets colocam você no negócio de protocolos.** Framing, acks, reconexão, retomada, backpressure: o transporte é fácil, o contrato em cima é o trabalho.
- **A simplicidade do polling esconde um piso de latência.** Nenhum ajuste escapa do atraso médio de intervalo/2; encurtar o intervalo só recompra o imposto de headers.
- **Long polling é o pior dos dois em escala.** Requests seguradas consomem capacidade de servidor como push, enquanto pagam overhead de reconexão por mensagem como pull — por isso ele sobrevive apenas como degrau de fallback.
- **Todo transporte de push precisa da cooperação dos proxies.** Buffering de stream quebra o SSE em silêncio; headers de upgrade removidos quebram WebSockets — teste através da infraestrutura real, não do localhost.

## Transportes de tempo real no Back4app

O Back4app é uma plataforma open-source de Backend as a Service (BaaS) que combina banco de dados gerenciado, APIs REST e GraphQL geradas automaticamente, autenticação, armazenamento de arquivos e funções serverless com Cloud Code. A decisão de transporte é em grande parte absorvida pelas [Live Queries](/glossary/pt/live-queries-tempo-real/): as abas de código acima se inscrevem numa consulta e recebem eventos por push sobre uma frota de WebSockets que a plataforma opera — conexões, reconexões, checagens de permissão e fan-out entre servidores incluídos — de modo que "SSE ou WebSockets?" vira um detalhe de implementação que você herda, não uma infraestrutura que você constrói. Onde uma cadência mais suave genuinamente cabe, a mesma consulta roda como um fetch comum no seu cronograma; fazer polling de uma consulta Parse e inscrever-se nela estão a uma linha de distância, o que torna o transporte certo por feature um refactor, não uma reescrita.
