htmx Tutorial · Going Further · Lesson 28 of 30

Real-Time Updates: Polling, SSE and WebSockets

Keep a page up to date with polling, Server-Sent Events or WebSockets, and know which one to pick.

Create a free account to save this page, take notes and track your progress. Sign in

Polling: the simplest option

hx-trigger="every 5s" asks the server again and again. It works with any backend, through any proxy, and is easy to scale. The cost is a request every few seconds even when nothing changed. To stop, have the server respond with status 286, which tells htmx to stop polling that element.

Poll until a job finishesTry it yourself
<div hx-get="/job/42" hx-trigger="every 1s" hx-swap="innerHTML">Starting the export...</div>

<!-- The pretend server: on a real site this part is your backend (Python, PHP, Node, Go...) -->
<script>
  let progress = 0;
  server.get("/job/42", () => {
    progress = Math.min(progress + 20, 100);
    if (progress === 100) return { status: 286, body: "<strong>Export finished.</strong> (286: polling stopped)" };
    return `Exporting... ${progress}%`;
  });
</script>

Server-Sent Events (SSE)

For updates pushed by the server (notifications, live scores, progress), use the official SSE extension. The server keeps one HTTP response open and sends named events; each one is swapped in:

<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>

<div hx-ext="sse" sse-connect="/events">
  <div sse-swap="notification">Waiting for notifications...</div>
</div>

The server sends lines like event: notification followed by data: <p>New message from Ada</p> and a blank line.

WebSockets

For two-way communication (chat, collaborative editing), the ws extension opens a WebSocket. Forms with ws-send send their values as JSON over the socket, and HTML messages from the server are swapped by id (like out-of-band swaps):

<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>

<div hx-ext="ws" ws-connect="/chat">
  <div id="messages"></div>
  <form ws-send><input name="message"></form>
</div>

Which one?

Need Use
Updates every few seconds or minutes are fine Polling
The server pushes updates as they happen SSE (one-way, plain HTTP, reconnects automatically)
Both sides send messages constantly WebSockets

Test yourself

How does a server tell htmx to stop polling an element?

  1. Respond with status code 286
  2. Respond with 204
  3. Send HX-Stop: true
  4. Return an empty body
Show answer

Answer: Respond with status code 286

286 is htmx's special 'stop polling' status.

Was this page helpful?