How the Uptime Kuma API Router Handles WebSocket Real-Time Updates

The Uptime Kuma API router pushes real-time updates to connected browsers by emitting Socket.IO events to user-specific rooms after processing HTTP requests, decoupling state persistence from live UI synchronization.

Uptime Kuma leverages Socket.IO to bridge its HTTP API and live dashboard updates. The Uptime Kuma API router WebSocket real-time updates mechanism allows the server/routers/api-router.js file to notify frontend clients immediately when monitor states change, creating a seamless monitoring experience where the Vue dashboard refreshes instantly without page reloads.

Socket.IO Architecture and User Isolation

Server Initialization

In server/uptime-kuma-server.js, the Socket.IO server initializes by attaching to the HTTP server instance. Lines 42-56 create the Server instance and configure the connection manager that handles all real-time communications. This centralizes WebSocket management within the UptimeKumaServer class, making the io object available throughout the application for emitting events.

User-Scoped Rooms

The system implements strict user isolation through Socket.IO rooms. When a client authenticates, the server assigns socket.userID to the connection. This enables targeted emissions using io.to(userID), ensuring that monitor updates reach only the browser sessions belonging to the specific user who owns those monitors. This room-based architecture prevents cross-contamination of data between different user accounts.

End-to-End Update Flow

HTTP Endpoint Processing

When a monitoring service calls the push API, the request enters through POST /api/push/:pushToken defined in server/routers/api-router.js (lines 27-34). The router validates the push token, identifies the associated monitor, and creates a heartbeat bean containing the status, message, and ping time. This HTTP endpoint acts as the entry point for external state changes.

Real-Time Emission

After persisting the heartbeat data, lines 127-128 of server/routers/api-router.js trigger the WebSocket broadcast:

io.to(monitor.user_id).emit("heartbeat", bean.toJSON());

This single line bridges the HTTP request/response cycle with the persistent Socket.IO connection, pushing the new state to all connected browsers for that user instantly.

Frontend Subscription

The Vue mixin located in src/mixins/socket.js (lines 120-130) establishes the client-side Socket.IO connection and registers event listeners. When the server emits a heartbeat event, the frontend handler updates the dashboard table row immediately. The same pattern applies to monitorList, updateMonitorIntoList, and maintenanceList events, keeping all UI components synchronized with the server state.

Implementation Across the Stack

API Router Emissions

The server/routers/api-router.js file serves dual purposes: handling REST endpoints and triggering real-time notifications. After processing any state-modifying request—whether from the push API or internal status changes—it emits the appropriate Socket.IO events to refresh connected clients.

Monitor Model Integration

Scheduled health checks in server/model/monitor.js (lines 92-95) use identical emission logic:

io.to(this.user_id).emit("heartbeat", bean.toJSON());

This ensures consistency between updates triggered by external push APIs and those generated by the internal monitoring scheduler, providing a unified real-time experience regardless of the update source.

Practical Integration Examples

Pushing Heartbeats via HTTP

Simulate a monitored service calling the push API to trigger a real-time update:


# Replace <TOKEN> with your monitor's push token

curl -X POST "http://localhost:3001/api/push/<TOKEN>?msg=OK&status=up&ping=42"

After execution, the server validates the token, stores the heartbeat, and emits the update to your browser instantly.

Browser Client Implementation

Listen for real-time updates from a custom web application:

<script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
<script>
  const socket = io();
  
  // Receive heartbeat updates instantly
  socket.on('heartbeat', (hb) => {
    console.log('New heartbeat received:', hb);
    // Update DOM elements with hb.status, hb.ping, hb.time
  });
  
  // Receive full monitor list on connection
  socket.on('monitorList', (list) => {
    console.log('Current monitors:', list);
  });
</script>

Programmatic Server-Side Triggering

Trigger updates from a Node.js script:

await fetch('http://localhost:3001/api/push/abcd1234?msg=Manual&status=up&ping=10')
  .then(r => r.json())
  .then(console.log);

Any connected Uptime Kuma dashboard will immediately reflect the new status through the WebSocket connection.

Summary

  • Socket.IO Integration: The server/uptime-kuma-server.js file creates the Socket.IO server and manages user-specific room assignments via socket.userID.
  • Dual-Path Updates: Both the API router (server/routers/api-router.js) and the monitor model (server/model/monitor.js) emit heartbeat events using io.to(user_id) to ensure real-time synchronization.
  • User Isolation: Room-based emissions guarantee that monitor data reaches only authenticated sessions belonging to the correct user.
  • Frontend Reactivity: The src/mixins/socket.js Vue mixin handles connection management and event routing, enabling instantaneous UI updates without polling.

Frequently Asked Questions

How does Uptime Kuma ensure WebSocket updates reach only the correct user?

Uptime Kuma implements user-scoped rooms in Socket.IO. When a client authenticates, the server assigns socket.userID to the connection. Both the API router and monitor model emit events using io.to(monitor.user_id), which restricts delivery to sockets belonging to that specific user only, preventing data leakage between accounts.

What event names does the Uptime Kuma API router emit?

The primary events include heartbeat (for status changes), monitorList (full monitor synchronization), updateMonitorIntoList (partial updates), and maintenanceList (maintenance window changes). These stable event names allow the frontend mixin in src/mixins/socket.js to register predictable listeners that handle specific data types.

Can external scripts trigger real-time updates in Uptime Kuma?

Yes. Any HTTP request to POST /api/push/:pushToken processed by server/routers/api-router.js will trigger the same Socket.IO emission chain as internal monitors. After the router validates the token and stores the heartbeat, it immediately emits to the user's room, causing instant dashboard updates for connected browsers.

How does the frontend handle reconnection and missed events?

The Vue mixin in src/mixins/socket.js manages connection state and automatically re-registers event listeners upon reconnection. When the socket reconnects, the server typically emits a full monitorList event to resynchronize the client state, ensuring the dashboard remains consistent even after temporary disconnections.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →