Skip to content

Reference

WebSocket reference

  • v0 · latest
  • 10 min read
  • Updated Sep 16, 2026
  • Generated from source

Realtime protocol v1 used by the dashboard for live feeds, the screencast and takeover input. Generated from @browserhive/contracts/ws. Available when --admin is on.

  • URL: ws://<host>:<port>/api/v1/ws (same port as everything else).
  • Subprotocol: Sec-WebSocket-Protocol: browserhive.v1.
  • Authentication: the dashboard session cookie or Authorization: Bearer <token>, checked at upgrade. A failed check completes the upgrade and closes immediately with 4401, so browsers see the code.
  • The first server frame is a reply with payload type: "hello", carrying epoch and the current cursor. epoch changes on every server start; a cursor from another epoch cannot be replayed.

Every server text frame is JSON:

{ v: 1, kind: "event" | "reply" | "error" | "stream", seq: number, ts: number, topic?: string, corr?: string, payload: unknown }
kind Meaning
event ordered, replayable feed event on a topic (has topic and seq)
reply answer to a client command (echoes corr); also the first hello frame
error command failure or protocol violation; the socket stays open
stream screencast control message on screencast:<id>; latest-wins, never replayed

Client frames are JSON objects discriminated on type (see client commands); any command may carry corr (1–64 characters), which is echoed on its reply or error.

Limit Value
maxInboundFrameBytes 16KiB
maxProtocolViolations 5
feedBufferCount 10000
feedBufferBytes 8MiB
feedBufferMs 5m
heartbeatMs 20s
staleMs 1m
tickMs 30s
overloadBytes 4MiB
overloadGraceMs 10s
screencastDropBytes 1MiB
Code Name Meaning
4401 UNAUTHORIZED not authenticated or the session expired; log in again
4403 PASSWORD_CHANGE_REQUIRED the operator must change the password first
4400 PROTOCOL_ERROR too many malformed frames
4406 BAD_SUBPROTOCOL missing or unknown Sec-WebSocket-Protocol (expected browserhive.v1)
1013 OVERLOADED the client did not read fast enough (backpressure limit exceeded)
1001 GOING_AWAY server shutting down, or the socket was silent too long
type Fields Scope
ping any authenticated caller
subscribe topic: string, cursor?: integer any authenticated caller
unsubscribe topic: string any authenticated caller
screencast.start session_id: string, max_width?: integer, max_height?: integer, quality?: integer sessions:read
screencast.stop session_id: string sessions:read
screencast.set_size session_id: string, max_width: integer, max_height: integer sessions:read
input session_id: string, input: object sessions:takeover
session.set_viewport session_id: string, width: integer, height: integer sessions:write
logs.tail level?: one of error, warn, info, debug, trace, module?: string logs:read

input is accepted only while an attention request is open for the session and is re-checked on every message (INPUT_NOT_PERMITTED otherwise). session.set_viewport is an observability control and is not attention-gated.

Field names follow the Chrome DevTools Protocol (camelCase). modifiers is a bitmask: Alt=1, Ctrl=2, Meta=4, Shift=8.

Field Type Required Constraints
type "mouse" yes
action one of mouseMoved, mousePressed, mouseReleased, mouseWheel yes
x number yes ≥ 0; ≤ 100000
y number yes ≥ 0; ≤ 100000
button one of none, left, middle, right no
clickCount integer no ≥ 0; ≤ 8
deltaX number no ≥ -10000; ≤ 10000
deltaY number no ≥ -10000; ≤ 10000
modifiers integer no ≥ 0; ≤ 15
Field Type Required Constraints
type "key" yes
action one of keyDown, keyUp, char, rawKeyDown yes
key string no max length 32
code string no max length 64
text string no max length 16
windowsVirtualKeyCode integer no ≥ 0; ≤ 255
modifiers integer no ≥ 0; ≤ 15
Field Type Required Constraints
type "touch" yes
action one of touchStart, touchEnd, touchMove, touchCancel yes
points object[] yes at most 10 items; each item: keys x, y, radiusX, radiusY, force, id
modifiers integer no ≥ 0; ≤ 15
payload type Fields
hello protocol: "browserhive.v1", protocol_version: 1, epoch: string, cursor: integer, server_version: string, now: integer
subscribed topic: string, from: integer, to: integer, complete: boolean
unsubscribed topic: string, ok: boolean
pong ts: integer
screencast.started topic: string, ordinal: integer
ok result?: any
resync_required topic?: string, reason: one of cursor_expired, epoch_changed, buffer_overflow

Subscribe with { "type": "subscribe", "topic": "<topic>", "cursor"?: <last seq> }. The reply subscribed { from, to, complete } says whether the replay was complete; complete: false (or resync_required) means reload from REST.

Topic Scope Events
sessions sessions:read session.opened, session.updated, session.closed, session.removed
attention attention:read attention.created, attention.resolved
vault.confirm vault:read vault.confirm.created, vault.confirm.resolved
vault.config vault:read vault.binding.changed, vault.policy.changed, vault.lock_state
vault.access vault:read vault.access
pages sessions:read page.visited
blocklist blocklist:read blocklist.hit, blocklist.reloaded
system system:read system.degraded, system.recovered, system.tick, system.capacity, retention.completed
logs logs:read log.record
notifications notifications:read notification.created, notification.updated
session:<id> sessions:read session.opened, session.updated, session.closed, session.removed, session.warning, tool.called, page.visited, screenshot.captured, vault.access, blocklist.hit, attention.created, attention.resolved, vault.confirm.created, vault.confirm.resolved
screencast:<id> sessions:read stream messages meta, started, stopped, failed and binary frames

Payloads of kind: "event" frames, discriminated on type. DTO fields (session, row, request, …) are the same shapes the REST API returns.

Field Type Required Constraints
session object yes keys session_id, slug, owner, tenant_id, channel, engine, headless, incognito, persistence_mode, current_url, created_at, last_activity_at, closed_at, closed_reason, archived_at, lease_expires_at, lease_paused_at, lease_remaining_ms, state, live, disable_evaluate, vault_enabled, stealth, fingerprint, humanize, stealth_recorded, identity, proxy_label, counts, has_live_viewers, client

Field Type Required Constraints
session object yes keys session_id, slug, owner, tenant_id, channel, engine, headless, incognito, persistence_mode, current_url, created_at, last_activity_at, closed_at, closed_reason, archived_at, lease_expires_at, lease_paused_at, lease_remaining_ms, state, live, disable_evaluate, vault_enabled, stealth, fingerprint, humanize, stealth_recorded, identity, proxy_label, counts, has_live_viewers, client

Field Type Required Constraints
session_id string yes pattern ^([a-z][a-z0-9-]{1,31})-([0-9a-z]{8})$
closed_at integer yes ≥ 0
reason one of user, operator, lease_expired, crash, shutdown, interrupted, launch_failed yes

Field Type Required Constraints
session_id string yes pattern ^([a-z][a-z0-9-]{1,31})-([0-9a-z]{8})$
action one of archived, unarchived, deleted yes
at integer yes ≥ 0

Field Type Required Constraints
session_id string yes pattern ^([a-z][a-z0-9-]{1,31})-([0-9a-z]{8})$
code string yes
message string yes
details any no

Field Type Required Constraints
row object yes keys event_id, session_id, tool, tab_id, ok, error_code, error_message, duration_ms, result_size_bytes, ts, trace_id, has_screenshot, args_json, result_text
has_detail boolean yes

Field Type Required Constraints
row object yes keys event_id, session_id, tab_id, url, title, domain, category, ts

Field Type Required Constraints
row object yes keys event_id, session_id, tool, kind, content_type, width, height, size_bytes, ts, url

Field Type Required Constraints
row object yes keys event_id, session_id, session_slug, tool_event_id, entry_name, handle, result, reason, evaluate_enabled, page_url, origin_check, principal_id, details, ts

Field Type Required Constraints
row object yes keys event_id, session_id, session_slug, tool_event_id, url, domain, pattern, source, tool, ts

Field Type Required Constraints
request object yes keys request_id, kind, session_id, session_slug, owner, reason, mode, options, status, message, resolved_by, resolution_reason, created_at, resolved_at, deadline_at, waited_ms, page_url, tool, event_id, entry_name

Field Type Required Constraints
request object yes keys request_id, kind, session_id, session_slug, owner, reason, mode, options, status, message, resolved_by, resolution_reason, created_at, resolved_at, deadline_at, waited_ms, page_url, tool, event_id, entry_name

Field Type Required Constraints
request object yes keys request_id, kind, session_id, session_slug, owner, reason, mode, options, status, message, resolved_by, resolution_reason, created_at, resolved_at, deadline_at, waited_ms, page_url, tool, event_id, entry_name

Field Type Required Constraints
request object yes keys request_id, kind, session_id, session_slug, owner, reason, mode, options, status, message, resolved_by, resolution_reason, created_at, resolved_at, deadline_at, waited_ms, page_url, tool, event_id, entry_name

Field Type Required Constraints
handle string yes pattern ^[a-z0-9][a-z0-9._-]{0,127}$
action one of created, updated, removed yes

Field Type Required Constraints
group_id string or null yes

Field Type Required Constraints
unlocked boolean yes

Field Type Required Constraints
patterns integer yes ≥ 0
skipped integer yes ≥ 0
loaded_at integer yes ≥ 0

Field Type Required Constraints
event object yes keys event_id, code, severity, message, details, first_seen_at, last_seen_at, count, resolved_at

Field Type Required Constraints
event object yes keys event_id, code, severity, message, details, first_seen_at, last_seen_at, count, resolved_at

Field Type Required Constraints
now integer yes ≥ 0

Field Type Required Constraints
live integer yes ≥ 0
max integer or null yes

Field Type Required Constraints
at integer yes ≥ 0
pruned_rows integer yes ≥ 0
result one of ok, partial, failed yes
severity one of info, warn, error no

Field Type Required Constraints
notification object yes keys notification_id, principal_id, type, title, body, session_id, session_slug, target, source_event_id, created_at, updated_at, count, read_at, dismissed_at

Field Type Required Constraints
notification object yes keys notification_id, principal_id, type, title, body, session_id, session_slug, target, source_event_id, created_at, updated_at, count, read_at, dismissed_at

Field Type Required Constraints
record object yes keys seq, ts, level, msg, module, trace_id, span_id, request_id, session_id, principal, transport, err; additional keys allowed

Start with screencast.start { session_id, max_width?, max_height?, quality? }; the reply screencast.started carries the ordinal that tags this screencast’s binary frames. Frames are latest-wins and dropped under backpressure; each viewer may request its own size with screencast.set_size.

type Fields
meta session_id: string, ordinal: integer, device_width: integer, device_height: integer, page_scale: number, offset_top: number
started session_id: string, ordinal: integer
stopped session_id: string, reason: one of stopped, session_closed, session_crashed, connection_closed
failed session_id: string, code: string, message?: string

Each binary frame is a 16-byte big-endian header followed by the JPEG bytes.

Offset Field Encoding
0 magic 4 ASCII bytes BHSC
4 ordinal u32
8 seq u32 (monotonic per screencast; a lower seq after a higher one is dropped)
12 width u16 (JPEG width)
14 height u16 (JPEG height)