Visual Browse
cua global is available in REPL.
Visual browsing is a coordinate fallback for visible browser UI that cannot be targeted reliably with snapshot(page), refs, or page locators. Use it only while the task genuinely depends on visible pixels.
When to use
- Canvas rendered apps: slide/document/image editors, maps, games, charts, whiteboards and simulations
- Custom visual controls: drag handles, sliders, drawing surfaces, crop boxes, map pins, timeline controls
- Unstable or missing refs: visible controls whose snapshot refs are stale, absent, obscured, or repeatedly hit the wrong target
- Visual verification: when DOM state is insufficient and the next action depends on what is visibly rendered
When not to use
Do not use visual browsing for:
- reading ordinary page text
- navigation-only work
- simple buttons, links, inputs, menus, or forms with usable refs
- repeated coordinate guesses without checking the visual result
Prefer snapshot(page), refs, and locators when they can target the UI reliably.
Operating rules
cua always acts on the current active page. Open or focus the right tab first.
- When coordinates are not already known, call
display(await cua.getVisibleScreenshot()) before acting.
- After any CUA action that changes the page, verify before the next action.
- Use
snapshot(page) when DOM/ref state matters.
- Use
display(await cua.getVisibleScreenshot()) when visual state matters.
- Return to
snapshot(page), refs, or locators as soon as the visual task is done (e.g. CAPTCHA solved, canvas interaction complete, dropdown finally submitted).
- Only keep using
visual-browse mode while the page genuinely requires pixel-level visual interaction.
- Use coordinates for pixel-only manipulation. Use refs or locators for UI controls whenever they exist.
Recovery
- If a popup, modal, or cookie banner blocks interaction, handle that first.
- If an action does not visibly work, take a fresh screenshot before retrying.
- If the same coordinate approach fails 2-3 times, switch strategy instead of repeating.
- For layered canvas/editor surfaces, prefer coarse sidebar/tool controls over precise clicks on stacked objects.
API
interface CUAAPI {
/** Click at a coordinate in the current viewport. */
click(options: {
x: number;
y: number;
button?: 'left' | 'middle' | 'right'; // Mouse button: left by default
keypress?: string[]; // Modifier keys held during the click.
}): Promise<void>;
/** Double click at a coordinate in the current viewport. */
doubleClick(options: {
x: number;
y: number;
keypress?: string[]; // Modifier keys held during the double click.
}): Promise<void>;
/** Drag from a point to a point by the provided path. */
drag(options: {
path: Array<{ x: number; y: number }>; // Drag path as viewport points.
keys?: string[]; // Optional modifier keys held during the drag.
}): Promise<void>;
/** Capture the visible portion of the page as a base64 PNG string. */
getVisibleScreenshot(): Promise<string>;
/** Press control characters at the current focused element. */
keypress(options: {
keys: string[]; // Key combination to press.
}): Promise<void>;
/** Move the mouse to a point by the provided x and y coordinates. */
move(options: {
keys?: string[]; // Optional modifier keys held while moving.
x: number;
y: number;
}): Promise<void>;
/** Scroll by a delta from a specific viewport coordinate. */
scroll(options: {
keypress?: string[]; // Modifier keys held during scroll.
scrollX: number;
scrollY: number;
x: number;
y: number;
}): Promise<void>;
/** Type text at the current focus. */
type(options: { text: string }): Promise<void>;
}
Modifier keys
Use these values in keypress / keys: Alt, Control, ControlOrMeta, Meta, Shift.
ControlOrMeta means Meta on macOS and Control elsewhere. Aliases also work: Cmd, Command, Ctrl, Option.
Examples
display(await cua.getVisibleScreenshot());
await cua.click({ x: 420, y: 315 });
console.log((await snapshot(page)).tree);
await cua.drag({
path: [
{ x: 240, y: 540 },
{ x: 320, y: 540 },
{ x: 410, y: 540 },
],
});
1---2name: aside-visual-browse3description: Read this when you need a coordinate fallback for visible browser UI that snapshots, refs, or locators cannot target reliably.4---56# Visual Browse78`cua` global is available in REPL.910Visual browsing is a coordinate fallback for visible browser UI that cannot be targeted reliably with `snapshot(page)`, refs, or page locators. Use it only while the task genuinely depends on visible pixels.1112## When to use1314- **Canvas rendered apps**: slide/document/image editors, maps, games, charts, whiteboards and simulations15- **Custom visual controls**: drag handles, sliders, drawing surfaces, crop boxes, map pins, timeline controls16- **Unstable or missing refs**: visible controls whose snapshot refs are stale, absent, obscured, or repeatedly hit the wrong target17- **Visual verification**: when DOM state is insufficient and the next action depends on what is visibly rendered1819## When not to use2021Do not use visual browsing for:2223- reading ordinary page text24- navigation-only work25- simple buttons, links, inputs, menus, or forms with usable refs26- repeated coordinate guesses without checking the visual result2728Prefer `snapshot(page)`, refs, and locators when they can target the UI reliably.2930## Operating rules3132- `cua` always acts on the current active `page`. Open or focus the right tab first.33- When coordinates are not already known, call `display(await cua.getVisibleScreenshot())` before acting.34- After any CUA action that changes the page, verify before the next action.35- Use `snapshot(page)` when DOM/ref state matters.36- Use `display(await cua.getVisibleScreenshot())` when visual state matters.37- Return to `snapshot(page)`, refs, or locators as soon as the visual task is done (e.g. CAPTCHA solved, canvas interaction complete, dropdown finally submitted).38- Only keep using `visual-browse` mode while the page genuinely requires pixel-level visual interaction.39- Use coordinates for pixel-only manipulation. Use refs or locators for UI controls whenever they exist.404142## Recovery4344- If a popup, modal, or cookie banner blocks interaction, handle that first.45- If an action does not visibly work, take a fresh screenshot before retrying.46- If the same coordinate approach fails 2-3 times, switch strategy instead of repeating.47- For layered canvas/editor surfaces, prefer coarse sidebar/tool controls over precise clicks on stacked objects.4849## API5051```ts52interface CUAAPI {53 /** Click at a coordinate in the current viewport. */54 click(options: {55 x: number;56 y: number;57 button?: 'left' | 'middle' | 'right'; // Mouse button: left by default58 keypress?: string[]; // Modifier keys held during the click.59 }): Promise<void>;6061 /** Double click at a coordinate in the current viewport. */62 doubleClick(options: {63 x: number;64 y: number;65 keypress?: string[]; // Modifier keys held during the double click.66 }): Promise<void>;6768 /** Drag from a point to a point by the provided path. */69 drag(options: {70 path: Array<{ x: number; y: number }>; // Drag path as viewport points.71 keys?: string[]; // Optional modifier keys held during the drag.72 }): Promise<void>;7374 /** Capture the visible portion of the page as a base64 PNG string. */75 getVisibleScreenshot(): Promise<string>;7677 /** Press control characters at the current focused element. */78 keypress(options: {79 keys: string[]; // Key combination to press.80 }): Promise<void>;8182 /** Move the mouse to a point by the provided x and y coordinates. */83 move(options: {84 keys?: string[]; // Optional modifier keys held while moving.85 x: number;86 y: number;87 }): Promise<void>;8889 /** Scroll by a delta from a specific viewport coordinate. */90 scroll(options: {91 keypress?: string[]; // Modifier keys held during scroll.92 scrollX: number;93 scrollY: number;94 x: number;95 y: number;96 }): Promise<void>;9798 /** Type text at the current focus. */99 type(options: { text: string }): Promise<void>;100}101```102### Modifier keys103104Use these values in `keypress` / `keys`: `Alt`, `Control`, `ControlOrMeta`, `Meta`, `Shift`.105`ControlOrMeta` means `Meta` on macOS and `Control` elsewhere. Aliases also work: `Cmd`, `Command`, `Ctrl`, `Option`.106107## Examples108109```js110display(await cua.getVisibleScreenshot());111```112113```js114await cua.click({ x: 420, y: 315 });115console.log((await snapshot(page)).tree);116```117118```js119await cua.drag({120 path: [121 { x: 240, y: 540 },122 { x: 320, y: 540 },123 { x: 410, y: 540 },124 ],125});126```