Skip to content

feat: add browser session recording via CDP screencast (start/stop API)#20

Open
Adarsh-Raj-Jaiswal wants to merge 6 commits intobrowser-use:mainfrom
Adarsh-Raj-Jaiswal:feat/cdp-screencast-recording
Open

feat: add browser session recording via CDP screencast (start/stop API)#20
Adarsh-Raj-Jaiswal wants to merge 6 commits intobrowser-use:mainfrom
Adarsh-Raj-Jaiswal:feat/cdp-screencast-recording

Conversation

@Adarsh-Raj-Jaiswal
Copy link
Copy Markdown

@Adarsh-Raj-Jaiswal Adarsh-Raj-Jaiswal commented Mar 28, 2026

#19

Summary

Adds initial support for recording browser sessions using Chrome DevTools Protocol (CDP) screencast.

This implements a minimal start/stop recording API that captures frames via Page.startScreencast and saves them as JPEG images.

Features

  • CDPClient.start_recording(output_dir) API
  • Frame capture using Page.startScreencast / Page.screencastFrame
  • Asynchronous frame processing using a queue-based worker
  • Saves frames as sequential JPEG images
  • Graceful shutdown with queue draining and task cancellation

Example

async with CDPClient(ws_url) as client:
    recorder = await client.start_recording("recording_output")

    try:
        await client.send.Page.navigate({"url": "https://youtube.com"})
        await asyncio.sleep(5)
    finally:
        await recorder.stop()

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Add browser session recording via CDP screencast with a simple start/stop API. Frames are saved as sequential JPEG images in the chosen directory.

- **Bug Fixes**
  - Made queue handling exception-safe with try/finally so stop() never hangs.
  - Prevent double-starts via `CDPClient._recorder`, raise a clear error, and clear the back-ref on stop to allow restart.
  - Stop an active recorder inside `CDPClient.stop()` before closing the WebSocket so `screencastFrameAck` can complete.

<sup>Written for commit adc16cc7faa5923ff10fc06cf543e99ab7d83c19. Summary will update on new commits.</sup>

<!-- End of auto-generated description by cubic. -->

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 3 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="examples/record.py">

<violation number="1" location="examples/record.py:21">
P2: Module executes `asyncio.run(main())` at import time; missing `__main__` guard causes import-time side effects.</violation>
</file>

<file name="cdp_use/recorder.py">

<violation number="1" location="cdp_use/recorder.py:50">
P1: Queue task completion is not exception-safe; an error in frame processing can prevent `task_done()` and cause `stop()` to hang on `queue.join()`.</violation>
</file>

<file name="cdp_use/client.py">

<violation number="1" location="cdp_use/client.py:412">
P2: `start_recording()` lacks an active-recording guard, allowing multiple recorder starts on one client and conflicting screencast/event-handler state.</violation>

<violation number="2" location="cdp_use/client.py:412">
P2: `start_recording()` launches a background `Recorder` task that is not tracked or stopped by `CDPClient.stop()`, causing lifecycle leaks when callers forget explicit `recorder.stop()`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
@crayment
Copy link
Copy Markdown

Hey @Adarsh-Raj-Jaiswal — following up on the feedback we left on the three threads. We went ahead and implemented the fixes on a branch on our fork if you'd like to cherry-pick them.

What's in the commits:

  • 1b19503 — three fixes: try/finally around task_done() in the worker; double-start guard on start_recording() (with _recorder sentinel on CDPClient); stop recorder in CDPClient.stop() before closing the WebSocket; clear _recorder back-reference in Recorder.stop() so the client can start a new recording after manual stop
  • b00e1b3 — 3 tests covering each fix, runnable via uvx --with websockets --with typing-extensions --with httpx --with-editable . pytest tests/

To cherry-pick:

git remote add crayment https://github.com/crayment/cdp-use.git
git fetch crayment
git cherry-pick 1b19503 b00e1b3

Happy to iterate if anything looks off.

crayment and others added 3 commits March 30, 2026 14:00
- Wrap worker frame processing in try/finally so task_done() is always
  called even if base64 decode, file write, or screencastFrameAck raises,
  preventing queue.join() from hanging indefinitely in stop()

- Add _recorder field to CDPClient to track active recording; guard
  start_recording() against double-start (EventRegistry uses a plain dict
  so a second call would silently overwrite the first on_frame handler,
  leaking the first recorder's worker task)

- Stop active recorder in CDPClient.stop() before closing the WebSocket,
  so screencastFrameAck calls in the recorder can still complete cleanly;
  without this, recorder.stop() called after CDPClient.stop() raises
  RuntimeError from send_raw() on a closed connection
@Adarsh-Raj-Jaiswal
Copy link
Copy Markdown
Author

Thanks a lot for the detailed review and for putting together the fixes + tests — really appreciate it.

I’ve cherry-picked the commits into my branch and pushed the updates. Let me know if anything else needs refinement.

@Adarsh-Raj-Jaiswal
Copy link
Copy Markdown
Author

Hi @crayment , Just checking if everything looks good now happy to make any further changes if needed.

@crayment
Copy link
Copy Markdown

Looks great @Adarsh-Raj-Jaiswal — the commits landed cleanly and the code matches exactly. From our side this is good to go! 🎉

@crayment
Copy link
Copy Markdown

Hey @reformedot — wanted to give this a gentle nudge! PR #20 from @Adarsh-Raj-Jaiswal adds the session recording feature via CDP screencast that was requested in issue #19. We reviewed it as third-party contributors, addressed the bot feedback, and added tests — everything looks good from our side. Would love to see this land! 🙏

@Adarsh-Raj-Jaiswal
Copy link
Copy Markdown
Author

Thanks again @crayment for the help getting this merged 🙏

Once this lands, I’m planning to proceed with the browser-use CLI integration on top of the current frame-based recording (start/stop commands), and then iterate toward video encoding support from there.

Let me know if that direction aligns with your expectations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants