How Live AI Progress Reaches the Browser
A practical comparison of polling, server-sent events, and WebSockets, including event contracts, reconnects, ordering, authorization, and honest progress percentages.
In this article

The Short Answer
A live progress bar is a distributed system in miniature. The GPU worker knows about nodes and sampling steps. The product knows about jobs and stages. The browser needs authorized, ordered, resumable updates.
Progress is a view, not the source of truth
The Event Path From GPU To Browser
- ComfyUI emits a node or sampler progress message with a provider prompt ID.
- The worker maps that message to the application job and a product stage.
- The worker persists meaningful state changes and publishes a safe event.
- An API process subscribes and finds authorized connections for that job.
- The browser reduces the event into local UI state.
- A slower refresh path reconciles the UI with durable state.
Movey uses this layered translation because internal node IDs should not become a permanent public contract. The UI can display “Encoding video” while the workflow changes from one encoding node to another.
Polling, Server-Sent Events, And WebSockets
| Transport | Direction | Strength | Cost |
|---|---|---|---|
| Polling | Request and response | Simple, cacheable, resilient | Repeated headers and stale intervals |
| SSE | Server to browser | Native event stream and reconnect | One-way, text framing, auth constraints |
| WebSocket | Two-way | Low-overhead frequent messages | Connection state and proxy complexity |
RFC 6455 defines WebSocket as an HTTP upgrade followed by framed, two-way communication over one TCP connection. The WHATWG HTML standard defines EventSource streams using text/event-stream and supports a last-event identifier for reconnection.
Design A Product-Level Message Contract
{
"type": "job.progress",
"job_id": "job_456",
"attempt_id": "attempt_2",
"sequence": 17,
"stage": "generating",
"progress": 67,
"message": "Generating motion",
"occurred_at": "2026-07-23T21:00:00Z"
}Include enough identity to reject stale messages. Sequence numbers help detect duplicates and reordering. Stage names should be stable product vocabulary. A human-readable message may change without breaking client logic.
ComfyUI’s server messages include execution_start, executing, progress, executed, cached-node notifications, and execution errors. A bridge should preserve diagnostic detail in structured logs while publishing only safe user-facing fields.
Ordering, Duplicates, And Reconnect
A reconnecting browser may receive an old event after it has already fetched a newer durable state. The reducer should compare sequence or version values rather than blindly applying arrival order.
- Ignore events for another authenticated owner or job.
- Ignore an earlier attempt after a retry starts.
- Ignore a lower state version than the current snapshot.
- Treat completed, failed, and cancelled as terminal for that attempt.
- Fetch a fresh snapshot after reconnect before resuming live events.
Make Progress Percentages Honest
A sampler with value 6 and max 9 is two-thirds through its sampling loop. It is not necessarily two-thirds through wall-clock time. Model loading may dominate the beginning, and VAE decoding or video encoding may dominate the end.
Use measured stage weights when historical timing is stable. Otherwise show named stages and an indeterminate indicator. Never let a progress bar reach 100 before the output is durable and readable.
Every Progress Channel Needs Authorization
Knowing a job ID must not grant access to its progress or output. Authenticate the connection, authorize each subscription, and recheck ownership when the server sends data. Do not place long-lived secrets in URLs.
Events should not include raw prompts, signed asset URLs, stack traces, provider credentials, or filesystem paths. The browser needs a stage, percentage, safe message, and stable identifiers.
A Resilient Browser Strategy
- Load the current job snapshot over authenticated HTTP.
- Open the live channel and subscribe to the job.
- Apply only newer authorized events.
- When disconnected, keep the last known state and start slower polling.
- Reconnect with bounded backoff.
- Fetch another snapshot before trusting the resumed stream.
- Stop all refresh work when the job reaches a durable terminal state.
Frequently Asked Questions
Why use WebSockets for AI generation progress?
WebSockets provide a persistent two-way channel with low per-message overhead. They suit frequent progress, status, preview, and cancellation messages, but they need authentication, reconnect logic, and a durable fallback.
Is polling a bad design?
No. Slow polling is a valuable recovery path and may be the simplest primary design for infrequent updates. The problem is aggressive polling that substitutes repeated full reads for a well-defined event model.
Should progress percentages be exact?
Only when the underlying stages have measurable totals. A sampler step ratio is real, but model loading, queue time, upload, and encoding often need stage-based or estimated progress.
Sources
Protocol standards and current ComfyUI server documentation used for the transport and message behavior.
- RFC 6455: The WebSocket Protocol defines the upgrade handshake and two-way framed transport.
- WHATWG server-sent events defines EventSource, event-stream framing, and last-event identifiers.
- ComfyUI server messages documents execution, progress, cached, and completion message types.
- ComfyUI server routes documents the WebSocket, queue, history, and interrupt routes.
Keep reading
Related articles

From Click to Clip: Inside an AI Generation Job
Follow an AI generation request through validation, durable job state, Redis-backed queues, ComfyUI execution, WebSocket progress, output storage, and failure recovery.

Queues, Retries, and Idempotency for Reliable AI Jobs
Design reliable GPU jobs with logical job identities, attempt records, idempotency keys, bounded retries, leases, reconciliation, durable outputs, and exactly-once effects.