Real-Time UX with the htmx SSE Extension
Most web apps need live updates at some point — a notification badge, a progress bar, a dashboard that refreshes without polling. The usual answer is WebSockets or a full SPA framework. But if you’re already using htmx, there’s a simpler path: the htmx SSE extension, which wires server-sent events directly into your HTML with almost no JavaScript.
Key Takeaways
- Server-Sent Events (SSE) provide one-way, server-to-client streaming over standard HTTP — ideal for notifications, dashboards, and live feeds.
- The htmx SSE extension is a separate package (
htmx-ext-sse) that connects SSE streams to your HTML using declarative attributes, with no custom JavaScript required. - Three core attributes —
sse-connect,sse-swap, andhx-trigger="sse:<event>"— cover most real-time UX patterns. - SSE is simpler to deploy than WebSockets and eliminates the wasted requests of polling, though it only supports server-to-client communication.
What Server-Sent Events Actually Are
Server-Sent Events (SSE) is a browser-native protocol for one-way, server-to-client streaming over a standard HTTP connection. The server holds the connection open and pushes text events whenever it has something to say. The browser receives them through the EventSource API.
The wire format is plain text:
event: priceUpdate
data: <li>BTC — $62,400</li>
Each event has an optional name and a data payload. Multiple data: lines are concatenated. Events are separated by a blank line.
Because SSE runs over HTTP, it works through proxies and firewalls without special configuration. It supports automatic reconnection natively. The trade-off is directionality: once the connection is open, the client can’t send messages back. For notifications, dashboards, job progress, and live feeds, that’s perfectly fine. For chat or collaborative editing, you’d want WebSockets instead.
Installing the htmx SSE Extension
SSE support is not built into htmx core. It lives in the separate htmx-ext-sse package. Load both scripts and activate the extension on a container element:
<head>
<script src="https://cdn.jsdelivr.net/npm/htmx.org@latest/dist/htmx.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/htmx-ext-sse@latest"></script>
</head>
<body hx-ext="sse">
For npm-based builds, install with npm install htmx-ext-sse and import both htmx.org and htmx-ext-sse in your entry file.
Note: The old
hx-sseattribute from earlier htmx versions is deprecated. Usehx-ext="sse"with the dedicated extension instead.
Core Attributes for htmx Streaming Updates
Three attributes cover most real-time UX patterns:
| Attribute | Purpose |
|---|---|
sse-connect="<url>" | Opens the EventSource connection |
sse-swap="<event-name>" | Swaps incoming HTML into the element |
hx-trigger="sse:<event-name>" | Fires an htmx request when the event arrives |
A live feed that replaces its own content on every push:
<div hx-ext="sse" sse-connect="/feed" sse-swap="message">
Loading…
</div>
The server sends an event with data: <p>New item</p> followed by a blank line, and htmx replaces the div contents — no JavaScript required.
Discover how at OpenReplay.com.
Handling Multiple Events and Triggering Requests
One sse-connect can feed several child elements, each listening for a different event name:
<div hx-ext="sse" sse-connect="/stream">
<div sse-swap="statsUpdate"></div>
<div sse-swap="alertBanner"></div>
</div>
You can also use SSE events to trigger follow-up HTTP requests rather than swap content directly. This is useful when the event signals that fresh data is available but you want htmx to fetch the full rendered fragment:
<div hx-ext="sse" sse-connect="/events">
<div hx-get="/notifications" hx-trigger="sse:newNotification">
<!-- refreshed on each SSE event -->
</div>
</div>
To close a stream gracefully when the server signals completion, add sse-close="done" — the connection closes when an event named done arrives.
When SSE Beats Polling or WebSockets
- vs. polling: SSE eliminates wasted requests. The server pushes only when something changes.
- vs. WebSockets: SSE is simpler to deploy, works over HTTP/1.1 and HTTP/2, and needs no special server infrastructure. Use WebSockets only when you need bidirectional communication.
One practical note: HTTP/1.1 browsers cap connections per domain at six. If users open multiple tabs, SSE connections compete for that limit. Serving over HTTP/2 largely avoids this limitation by multiplexing multiple streams over a single connection.
Conclusion
The htmx SSE extension lets you add genuine HTML-over-the-wire real-time UI — live dashboards, progress indicators, notification streams — with a few HTML attributes and a server endpoint that knows how to keep a connection open. No state management library, no client-side routing, no build pipeline required. If your server can stream text, your UI can be live.
FAQs
No. Server-Sent Events are strictly one-way, from server to client. If you need to send data back, pair your SSE stream with standard htmx requests using hx-post or hx-put. For fully bidirectional communication, such as real-time chat, WebSockets are the better choice.
The browser's built-in EventSource API automatically attempts to reconnect after a brief delay. The server can control the retry interval by including a retry field in the event stream. The htmx SSE extension inherits this reconnection behavior without any extra configuration on your part.
Yes, and HTTP/2 is actually recommended. Under HTTP/1.1, browsers limit concurrent connections per domain to about six, so multiple tabs with open SSE streams can exhaust that limit. HTTP/2 multiplexes streams over a single connection, effectively removing the cap.
Send a named event that matches the sse-close attribute value on your container element. For example, if you set sse-close equal to done, sending an event with the name done will cause the extension to close the EventSource connection cleanly on the client side.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.