Both technologies transfer real-time data to your browser; both work great. However, when it comes to developing dashboards for tracking assets in real time, which is constantly receiving data from thousands of devices and where there is only one direction of data flow, the decision should be made wisely. Here is an overview of both.
Functionality of each technology
WebSockets
Full-duplex persistent connection
One TCP connection which is opened both ways. Data exchange between client and server is possible anytime. Protocol upgrade over HTTP at the very beginning of connection; then works independently.
- Bidirectional
- Binary or text
- Custom protocol
SSE
One-directional HTTP event stream
HTTP connection is kept open, but there is only the server pushing the events to the client. Client can not send data to the server over this connection, but sends HTTP requests instead.
- Server -> client only
- Text only
- HTTP-native
Comparing Asset Dashboards
| Feature | WebSockets | SSE |
|---|---|---|
| Message direction | Bidirectional — greater flexibility | Single-direction (Server to Client) |
| Overhead | Larger overhead due to framing (2–14 bytes per message) | Small HTTP overhead (~100 bytes) one-time |
| Auto-reconnect | Manual configuration needed | Built-in browser functionality — automatic |
| Firewalls/proxies | May not work through proxies | Equivalent to standard HTTP — guaranteed |
| Load balancing | Needs sticky session support | Browser does the job well |
| Support for binary data | Native support | Basic support — no binary messages |
| Browser compatibility | All browsers | All browsers except IE |
| Server implementation | difficult — stateful sessions | easy — standard HTTP handlers gains |
Implementing SSE – asset location stream
SSE is vastly easier to implement compared to WebSockets for read-only dashboards. Here's how to create an SSE stream on Node.js, where we emit events as assets are updated by our Redis service:
// Node.js SSE endpoint — streams live asset state
app.get('/stream/assets', async (req, res) => {
// SSE headers — keep connection open
res.setHeader('Content-Type', 'text/event-stream')
res.setHeader('Cache-Control', 'no-cache')
res.setHeader('Connection', 'keep-alive')
res.flushHeaders()
// Subscribe to Redis pub/sub channel
const sub = redis.duplicate()
await sub.subscribe('asset-updates', (msg) => {
res.write(`data: ${msg}\n\n`) // SSE format: data: {json}\n\n
})
// Cleanup on client disconnect
req.on('close', () => sub.unsubscribe())
})
And here's the same stream in action on the client side in React:
// React — consuming SSE asset stream
const [assets, setAssets] = useState({})
useEffect(() => {
const source = new EventSource('/stream/assets')
source.onmessage = (e) => {
const asset = JSON.parse(e.data)
setAssets(prev => ({ ...prev, [asset.id]: asset }))
}
// Browser auto-reconnects on disconnect — no code needed
return () => source.close()
}, [])
WebSockets implementation
– when two-way communication is needed
When your read-only dashboard starts sending requests – panning, zooming a map, requesting asset groups, firing events – you start needing the full WebSockets setup. Here it is on the server and client sides:
// Node.js WebSocket server with selective subscriptions
const { WebSocketServer } = require('ws')
const wss = new WebSocketServer({ port: 8080 })
wss.on('connection', (ws) => {
let subscribedFleets = []
// Client tells server which fleets to subscribe to
ws.on('message', (msg) => {
const { action, fleets } = JSON.parse(msg)
if (action === 'subscribe') subscribedFleets = fleets
})
// Push updates only for subscribed fleets
const interval = setInterval(async () => {
const updates = await getFleetUpdates(subscribedFleets)
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify(updates))
}
}, 1000)
ws.on('close', () => clearInterval(interval))
})
SSE reconnection tip: When reconnecting after a network outage, the browser will attempt reconnect using the same EventSource instance – and pass the Last-Event-ID request header containing the most recent event ID number. Use it on your backend to fetch missed events from your cache and close potential gaps in data streams between reconnects. Just add id: {eventId}\n to each SSE event.
The asset dashboard-specific answer
With a normal asset tracking dashboard that consists of a live mapping display, location pins for each tracked asset, statuses, alert feed – almost all data transfer is from server to client. The server receives the updates to asset locations via IoT events, and these get consumed by the dashboard that displays them to the user.
A classic scenario for Server-Sent Events. Built-in reconnect functionality. Regular HTTP load balancer support. No need for sticky sessions. No custom protocol required. Way simpler server-side logic compared to keeping thousands of stateful WebSocket connections.
WebSockets become a necessity once you introduce interactivity into the picture - filtering data on behalf of the users, issuing commands for selected assets, displaying alerts based on the user's roles. For data display purposes, SSE beats WebSockets hands down, but for user interaction, the latter is better suited.
Fast guide to decision making
- Map, board, alerts with read-only interface → SSE
- Easier deployment with no proxies involved → SSE
- Auto-reconnect without developing anything yourself → SSE
- User sending commands and subscribing to feeds → WebSockets
- Binary data transfer required or chat-like interactions → WebSockets
- Dashboard doing read/write operations → SSE for stream, REST for control
Preferred Stack
- Node.js / Express
- EventSource API
- ws (WebSockets)
- Redis pub/sub
- React + useState
The most practical approach for most asset dashboards is SSE for the live data stream plus REST POST for all user-driven actions. You have the easy approach of SSE for 95% of the use cases, while REST allows for sending any data to the server in the 5% of actions that require such actions.
AssetTrackPro’s live dashboard follows a SSE-first approach to handle asset location streaming with WebSockets acting as the secondary approach for fleet management.
Check out the live asset dashboard of AssetTrackPro →
Building your own live asset dashboard? With AssetTrackPro’s solution, you just focus on building the user interface, not setting up the infrastructure.













