New Features
- Added input priority and per-client delivery settings to the stream server: each WebSocket connection now splits into a reader task and a writer loop, so clicks and keystrokes dispatch to the browser without queueing behind a frame write. Adds a per-client
{"type":"config","maxFps":N}cap (1 to 120,0uncapped) and opt-in ack pacing via{"type":"config","pacing":"ack"}with{"type":"ack","seq":N}, which keeps one frame in flight so a stalled client never drains a backlog. Both settings can also be declared on the connection URL (?pacing=ack&maxFps=10), the only way to cover the opening frame. Every frame now carries a monotonicseq(#1594) - Added configurable stream encoding: frames were hardcoded to jpeg quality 80 at the session viewport, so frame rate was the only bandwidth lever.
AGENT_BROWSER_STREAM_QUALITY,AGENT_BROWSER_STREAM_MAX_WIDTHandAGENT_BROWSER_STREAM_MAX_HEIGHTare read once per daemon and cut bytes without dropping frames: on a busy page at 1280x720, quality 20 takes a frame from 54 KB to 25 KB, and quality 20 at 640x360 takes it to 9 KB, frame rate unchanged in both. Width and height default to the session viewport, so a larger viewport is never downscaled unless both are set (#1626)
Behavior Changes
- Frame delivery is now latest-wins. The stream server holds only the newest frame and reads it at send time, so frames produced while an earlier one is still being written are skipped. A client that assumed it received every frame from the WebSocket now receives fewer. Nothing in this repo consumes the stream that way, since
recordcaptures through CDP and the dashboard is a viewer, so this affects external consumers only (#1594) metadata.timestampnow carries a real value. It was always 0, because CDP sends the capture time as a float in seconds and the code read it as an integer. It is now epoch milliseconds, so a client can measure how stale the frame it is drawing is. A client that treated 0 as unknown is unaffected (#1594)
Bug Fixes
- Fixed keyboard input over the stream, which worked in none of the three shapes the docs publish: an absent
key,code, ortextreached CDP as an explicit null, which rejects the whole command, so every key release and every non-printable key was silently dropped, the dashboard's own payloads included (#1594) - Fixed click latency behind mouse movement: input dispatch awaited Chrome's reply before reading the next message, so a click sat one round trip behind every queued mouse move. After a 300-event sweep a click landed 2471ms late; it now lands in 6ms (#1627)
- Fixed
stream disablereturning while a slow client's input reader was still running (#1594)