WebSocket API
Real-time event streaming for live dashboards.
WebSocket API
The Dashcam daemon serves a WebSocket endpoint on the same port as the HTTP API. This is how the dashboard receives real-time events, captures, window updates, and agent status changes without polling. If you are building a custom dashboard, an integration, or a monitoring script, this is the API to use.
Connecting
Open a WebSocket connection to:
ws://localhost:57580/wsThe connection upgrades from the same HTTP server that hosts the REST API and the dashboard. No additional configuration is required.
const ws = new WebSocket('ws://localhost:57580/ws');
ws.onopen = () => {
console.log('Connected to Dashcam');
};
ws.onmessage = (message) => {
const data = JSON.parse(message.data);
console.log(data.type, data);
};Channel System
Messages are organized into channels. When you connect, you receive nothing until you subscribe. Send a subscribe message to start receiving events on specific channels:
{
"type": "subscribe",
"channels": ["events", "captures", "window", "agents", "live"]
}| Channel | Description |
|---|---|
events | New events as they are captured (tool use, messages, decisions) |
captures | New screenshots and videos |
window | Window state changes and timer updates |
agents | Agent start/stop notifications |
live | Heartbeat messages for connection health |
Subscribe to all channels for the full live dashboard experience, or pick only the channels you need.
Server-to-Client Messages
After subscribing, the server pushes messages as events occur. Every message is a JSON object with a type field.
event
A new event was captured. Sent on the events channel.
{
"type": "event",
"data": {
"id": "evt_01JQDEF",
"session_id": "sess_01JQXYZ",
"timestamp": "2026-03-20T10:15:23.456Z",
"event_type": "tool_use",
"agent_id": null,
"summary": "Write src/auth/jwt.ts",
"tool_name": "Write",
"file_path": "src/auth/jwt.ts",
"tokens_in": 1200,
"tokens_out": 450,
"duration_ms": 234
}
}capture
A new screenshot or video was saved. Sent on the captures channel.
{
"type": "capture",
"data": {
"id": "cap_01JQGHI",
"event_id": "evt_01JQDEF",
"session_id": "sess_01JQXYZ",
"timestamp": "2026-03-20T10:15:24.000Z",
"capture_type": "screenshot",
"file_path": "/captures/sess_01JQXYZ/1711234567890-full.png",
"thumbnail_path": "/captures/sess_01JQXYZ/1711234567890-thumb.png",
"width": 1920,
"height": 1080
}
}window_update
The window state changed or the timer ticked. Sent on the window channel. These arrive approximately once per minute during an active window.
{
"type": "window_update",
"data": {
"id": "win_01JQABC",
"state": "ACTIVE",
"started_at": "2026-03-20T09:00:00Z",
"remaining_seconds": 11520,
"elapsed_seconds": 6480,
"session_count": 2,
"event_count": 89
}
}session_update
A session's metadata changed (new summary, status transition, updated event count). Sent on the events channel.
{
"type": "session_update",
"data": {
"id": "sess_01JQXYZ",
"status": "completed",
"total_events": 142,
"summary": "Built auth system with JWT tokens and user dashboard",
"estimated_cost_usd": 0.47
}
}agent_status
An agent started or stopped. Sent on the agents channel.
{
"type": "agent_status",
"data": {
"session_id": "sess_01JQXYZ",
"agent_id": "agent_frontend_01",
"agent_type": "frontend",
"status": "active",
"started_at": "2026-03-20T10:00:00Z"
}
}live_heartbeat
Keep-alive message sent every 30 seconds on the live channel. Use this to detect stale connections.
{
"type": "live_heartbeat",
"timestamp": "2026-03-20T10:15:30.000Z"
}Client-to-Server Messages
Clients can send messages to subscribe to channels or query historical data over the WebSocket connection.
subscribe
Subscribe to one or more channels. Can be sent multiple times to add channels.
{
"type": "subscribe",
"channels": ["events", "captures"]
}query_events
Request historical events for a session within a time range. The server responds with a batch of event messages.
{
"type": "query_events",
"sessionId": "sess_01JQXYZ",
"from": "2026-03-20T10:00:00Z",
"to": "2026-03-20T11:00:00Z"
}query_sessions
Request sessions for a given date. The server responds with a batch of session_update messages.
{
"type": "query_sessions",
"date": "2026-03-20"
}Example: Live Event Listener
A minimal script that connects, subscribes, and logs events as they arrive:
const ws = new WebSocket('ws://localhost:57580/ws');
ws.onopen = () => {
ws.send(JSON.stringify({
type: 'subscribe',
channels: ['events', 'captures', 'window']
}));
};
ws.onmessage = (msg) => {
const { type, data } = JSON.parse(msg.data);
switch (type) {
case 'event':
console.log(`[${data.timestamp}] ${data.event_type}: ${data.summary}`);
break;
case 'capture':
console.log(`[${data.timestamp}] Screenshot: ${data.file_path}`);
break;
case 'window_update':
const mins = Math.floor(data.remaining_seconds / 60);
console.log(`Window: ${data.state} (${mins}m remaining)`);
break;
}
};
ws.onclose = () => console.log('Disconnected');node monitor.js
# [2026-03-20T10:15:23.456Z] tool_use: Write src/auth/jwt.ts
# [2026-03-20T10:15:24.000Z] Screenshot: /captures/sess_01JQXYZ/1711234567890-full.png
# Window: ACTIVE (192m remaining)The WebSocket connection does not require authentication in v1. Anyone who can reach the daemon port can subscribe. Bind to 127.0.0.1 (the default) or use SSH tunnels to restrict access.