Core Usage

Screenshots, Video & Viewport

This page is about turning what happens in the browser into files: grab a screenshot, record a workflow video, shrink the viewport to phone width to reproduce a responsive bug, and deal with iframes and dialogs that get in the way. These are all output tools — not for "finding elements and clicking them." For locating and interacting, always go through snapshot + @ref.

⚠️ Hard rule: screenshots are for archiving, not for locating
Never rely on "screenshot + coordinate click" to find or hit an element — that's a bug. For form fields, buttons, and links, use snapshot -i to get a @ref, which pierces even cross-origin iframes (embedded Stripe / Google Payments / checkout frames). Screenshots only exist to save the rendered result as a reusable image asset (maps, charts, og images, visual-regression baselines, report illustrations).

Screenshots

screenshot renders the current page to PNG. With no path, it saves to a temp file and prints the path to stdout; with a path, it writes to the location you give.

screenshot.sh
$ chrome-use screenshot                        # temp path, printed to stdout
$ chrome-use screenshot page.png               # specific path
$ chrome-use screenshot --full full.png        # entire scroll height
$ chrome-use screenshot --annotate map.png     # numbered labels + legend, mapped to snapshot refs

--full captures the full scroll height rather than just the visible area. --annotate is for multimodal models: each label [N] maps to @eN in the snapshot, making it easy to line up an image with the structured snapshot.

Scaling and clipping

Full-page screenshots from a real retina Chrome are often too large to fit into an image reader, so screenshots are automatically downsampled to a longest edge of ≤2000px — this keeps them readable while pixel coordinates stay aligned with click x y. Override with the flags below when needed, or capture just one selector / region:

bash
# capture just an element / region, saved as a reusable image asset
$ chrome-use screenshot "selector" --clip x,y,w,h region.png

# override the default downsample cap
$ chrome-use screenshot --max-width 1600 wide.png
$ chrome-use screenshot --scale 1 sharp.png
ℹ️ About scrollbars
Headless Chromium hides native scrollbars in screenshots to keep output consistent. Pass --hide-scrollbars false at launch to keep the visible native scrollbars.
✅ Want to click something a ref can't reach?
Don't use a screenshot to find coordinates. Use box @ref to get the element's CSS pixel box and centerX/centerY, then feed those straight into click <centerX> <centerY> — no screenshot needed at any point.

Recording workflow videos

Record a whole automation run as video, for debugging, documentation, or evidence. record start begins recording, you run your commands as usual in between, and record stop ends it and writes to disk.

record.sh
$ chrome-use record start demo.webm
$ chrome-use open https://example.com
$ chrome-use snapshot -i
$ chrome-use click @e3
$ chrome-use record stop

There's also a restart subcommand, equivalent to "stop the current recording + start a new one to a new file":

bash
$ chrome-use record start ./output.webm       # start recording to a file
$ chrome-use record stop                     # stop the current recording
$ chrome-use record restart ./take2.webm    # stop current + reopen to a new file

Practical recording tips

GoalHow
Make each step clear to watch Insert chrome-use wait 500 after key actions to give viewers time to react
Put context in the filename login-flow-2024-01-15.webm, checkout-test-run-42.webm
Keep the recording even on error Call chrome-use record stop inside trap cleanup EXIT
Keep video + key frames together While recording, grab a frame at each step with chrome-use screenshot ./stepN.png
ℹ️ Output format and limits
Recording pipes CDP frame captures through ffmpeg, so ffmpeg must be installed. The output format is chosen by the file extension: .webm encodes with VP8 (libvpx), any other extension (e.g. .mp4) uses H.264 (libx264) — there's no GIF export. Recording adds slight overhead to automation, long recordings take a lot of disk, and some headless environments may lack the codec. More recording recipes live in references/video-recording.md inside the skill package (a repo file — the doc site doesn't link to it).

Iframe scope

Iframe content is automatically inlined into the snapshot, and refs are transparently usable — usually you don't have to do anything:

bash
$ chrome-use snapshot -i
# @e3 [Iframe] "payment-frame"
#   @e4 [input] "Card number"
#   @e5 [button] "Pay"

$ chrome-use fill @e4 "4111111111111111"
$ chrome-use click @e5

When you want to focus the snapshot on a specific iframe (for concentration, or to handle deep nesting), use frame to switch context, then frame main to switch back to the main frame when done:

bash
$ chrome-use frame @e3      # switch context into this iframe
$ chrome-use snapshot -i
$ chrome-use frame main     # switch back to the main frame

Viewport / window size

To reproduce width-dependent bugs (responsive breakpoints, horizontal-overflow triage, mobile layouts), set the viewport first. This is a CDP virtual viewport (Emulation.setDeviceMetricsOverride) — it only changes this tab's layout viewport, and does not actually resize the OS window. So it works headless, and it works over the extension relay, without yanking around the user's real Chrome window.

viewport.sh
$ chrome-use viewport 1280 800        # set width x height (alias: resize)
$ chrome-use viewport 375x812         # WxH shorthand
$ chrome-use viewport 375 812 --dpr 3 --mobile   # retina + mobile emulation
$ chrome-use viewport reset           # clear the override, restore real size

A typical use — find out what's blowing out the layout at a narrow width:

bash
$ chrome-use viewport 375 812
$ chrome-use eval 'document.documentElement.scrollWidth + " vs " + innerWidth'
✅ Equivalent aliases
set viewport <w> <h> [scale] is equivalent to viewport, and resize is an alias too — write whichever feels natural.

Dialogs

alert and beforeunload are automatically accepted, so the agent never gets stuck on a popup. When you need to handle confirm and prompt manually:

dialog.sh
$ chrome-use dialog status          # is there a pending dialog?
$ chrome-use dialog accept           # accept
$ chrome-use dialog accept "text"    # accept and fill in the prompt text
$ chrome-use dialog dismiss          # cancel
ℹ️ When you need it
Most flows never touch dialog — native alert is already auto-accepted. Only when a page pops a confirm ("Are you sure you want to delete?") or a prompt (asking for text) and blocks what follows do you use dialog accept / dialog dismiss to respond explicitly.

Related pages