Repository navigation
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
- In Settings → Browser, set Browser recording frame rate to 60 fps.
- Serve a page that repaints every frame, for example:
<div id="n">0</div> <script>let n=0;(function f(){document.getElementById('n').textContent=++n;requestAnimationFrame(f)})()</script>
- From an agent:
preview_openthat page,preview_recording_start, wait 4 seconds,preview_recording_stop. - Count the frames in the returned MP4, for example with
ffprobe -count_frames, and the gaps between their timestamps.
Expected behavior
Up to 60 fps, as the setting says ("Maximum recording rate. 30 fps saves CPU and storage; 60 fps is smoother."). Before #15328, agent recordings went through the same recorder as the record button and followed this setting.
Actual behavior
The page ran at 60 fps inside the tab (counted with requestAnimationFrame), but the recording has about 29 fps:
| Viewport | MP4 size | Frames / duration | Mean gap | Longest gap |
|---|---|---|---|---|
| 1600×900 | 3200×1800 | 159 / 5.45 s | 34.3 ms | 232 ms |
| 800×450 | 1600×900 | 141 / 4.91 s | 34.8 ms | 266 ms |
A quarter of the pixels gives the same rate, so the limit is not frame size. A 140 ms CSS fade, which is what I was recording, gets three or four frames.
From the source at 26c48bb:
- The agent's recording is encoded on the server, with a fixed rate:
canvas.captureStream(30), and the bitrate formula also assumes 30. The screencast it reads from isRECORDING_SCREENCAST. browserRecordingFrameRateis read only by the record button's path (startBrowserRecording, which passes it togetDisplayMedia). Nothing on the server reads it.- Both lines came with feat(preview): run the browser on the environment server #15328. Before it, the
recordingStartautomation command was handled inPreviewAutomationHosts.tsxbystartBrowserRecording, so the setting applied to agent recordings too.
The setting is client-local by design (comment in settings.ts), so the server cannot read it as it is. One way to fix it: have the client that starts or owns the tab pass its frame rate with recordingStart, or move the setting into server settings, and use that value in captureStream() and the bitrate.
Impact
Minor bug or occasional failure
Version or commit
0.0.46-nightly.20261014.3093 (107f602); main at 26c48bb has the same code
Environment
Desktop app on Linux (NixOS, Wayland, niri), 2× display scale
Logs or stack traces
No response
Screenshots, recordings, or supporting files
No response
Workaround
No response
Activity
juliusmarminge commentedon Oct 14, 2026
Note
Grok responding on behalf of Julius.
Confirmed on main: agent recordings are encoded on the server with a fixed
canvas.captureStream(30)and a bitrate that assumes 30 fps (apps/server/src/preview/ServerBrowserPage.tsL587–588). Nothing on the server readsbrowserRecordingFrameRate, which is a client-local setting used only by the record button.This is a regression from #15328, not intended behavior. That PR moved agent recording to the server browser but left the setting behind. The setting doesn't say it applies only to manual recordings, and before #15328 it covered agent recordings too. The
settings.tscomment explaining why the setting is client-local still describes the old desktop-owned guest, so it's out of date.Not a duplicate. #10494 is about resizing during a recording corrupting the MP4.
Likely fix: send the requesting client's frame rate with
recordingStart, or move the setting into server settings, and use it in bothcaptureStream()and the bitrate.Until then, agent recordings are limited to 30 fps. For 60 fps, use the record button.
paul-vd commentedon Oct 25, 2026
A separate problem remains after #23895: agent recordings still drop frames (58–65% captured at 1600×900, 91–97% at 1280×800) and come out blurry, regardless of the frame-rate setting. Frame-numbered repro and recordings in #24979.
juliusmarminge commentedon Oct 30, 2026
Closing: current main already covers this as of 70bd96282c. If you still see it on a build that includes that commit, reply and we'll reopen.