TypeScript SDK Reference
browserscale-ts. All methods return a Promise; the return types below show the resolved value (the Promise<…> wrapping is implicit).CloudBrowser
CloudBrowser is the SDK-side handle for an active browserscale browser session.
One CloudBrowser corresponds to exactly one browser context, which always has at least one page. The session is implicitly bound to its primary page server-side — the proto's page_id field is currently ignored server-side, so the SDK never sets it.
Construct via rentBrowser() / createWebSocketBrowser() — never directly.
addReaction
method on CloudBrowseraddReaction(match: Locator, opts: ReactionOpts | undefined): stringRegisters a one-shot "reaction": a background poller (one shared loop per page) watches for the match locator and, as soon as it matches, clicks it with the full smart-click machinery (scroll, human path, occlusion gate, evade) — then removes itself. The poller yields to any in-flight input action and only fires while the pointer is idle, so a reaction naturally slots into the gaps of a retrying foreground action (e.g. it dismisses a newsletter modal blocking a CloudBrowser.click, after which the click's own retry succeeds). Reactions are scoped to the page and torn down automatically when the page/session ends.
match must be a css() or js() Locator — node()/at() are rejected. Use .inAllFrames() to watch every frame and .visible(false) to opt out of the default visibility gate. Pass a ReactionOpts to click a different target (on), change the button/click count, or the poll cadence.
| match | Locator | the css()/js() locator to watch for |
| opts | ReactionOpts | undefined | optional reaction customization; see ReactionOpts |
// Auto-dismiss a consent button whenever it appears, in any frame.
const id = await browser.addReaction(css("button#accept").inAllFrames());// Watch for a newsletter modal, but click its close "X" instead.
const id = await browser.addReaction(css("#newsletter-modal"), {
on: css(".modal-close"),
});stringthe reactionId (pass to CloudBrowser.removeReaction)| BrowserScaleError | `match` (or `opts.on`) is not a css()/js() locator, or a server/transport error |
clearCookies
method on CloudBrowserclearCookies(): voidDeletes every cookie in the browser context.
await browser.clearCookies();void| UNKNOWN_ERROR | the cookies could not be cleared |
clearStorage
method on CloudBrowserclearStorage(origin: string | undefined): voidDeletes localStorage in the browser context.
| origin | string | undefined | if set, only this origin's storage is deleted (e.g. "https://example.com"); omit to delete all origins |
// Wipe one origin.
await browser.clearStorage("https://example.com");
// Wipe everything.
await browser.clearStorage();void| UNKNOWN_ERROR | the storage could not be cleared |
click
method on CloudBrowserclick(target: Locator, opts: ClickOpts | undefined): ElementResultTriggers a single left mouse click on the given target.
The browser scrolls the element into view if needed, moves the cursor along a human-like path, then dispatches a full mouseDown+mouseUp at a randomized point inside the element's bounding rect.
For right-click, double-click, press/release-only, or to override the target frame, pass a ClickOpts object as the second argument.
| target | Locator | locator describing what to click; at is also valid |
| opts | ClickOpts | undefined | optional click customization; see ClickOpts |
try {
await browser.click(css("button.submit"));
} catch (e) {
if (e instanceof ClickError) console.log(e.code, e.occluder?.tagName);
}// Right double-click on a context menu trigger.
await browser.click(css("li.menu"), { button: "right", clickCount: 2 });ElementResultElementResult with success, resolved frameId, backendNodeId, post-scroll isVisible, element bounds, and the root-viewport (rootX, rootY) where the click landed| BrowserScaleError | invalid locator, or a server/transport error (element not found, frame not found, timeout, page closed) |
| ClickError | the target was found but the click could not land because another element covered it; `.code`, `.occluder` and `.result` describe the blocker and the resolved coordinates |
dragBy
method on CloudBrowserdragBy(target: Locator, offsetX: number, offsetY: number): DragResultPicks up the target and drops it at an offset relative to the pickup point.
The browser presses the left mouse button at a pickup point inside the element, drags along a human-like path to (pickupX+offsetX, pickupY+offsetY), then releases. at is not a valid target — drag needs a real element.
| target | Locator | locator describing the element to pick up |
| offsetX | number | horizontal distance to drag, in CSS pixels |
| offsetY | number | vertical distance to drag, in CSS pixels |
await browser.dragBy(css(".slider .handle"), 120, 0);DragResultDragResult with the resolved frameId, backendNodeId and the final cursor position (rootX, rootY) where the drop happened| BrowserScaleError | invalid locator or a server/transport error |
| DragError | the source could not be acquired/pressed; `.code` and `.clickError` describe the underlying click-core failure |
dragTo
method on CloudBrowserdragTo(target: Locator, absoluteX: number, absoluteY: number): DragResultPicks up the target and drops it at absolute root-viewport coordinates.
Same gesture as dragBy, but the drop destination is in page coordinates rather than relative to the pickup point.
| target | Locator | locator describing the element to pick up |
| absoluteX | number | horizontal drop coordinate in the root viewport |
| absoluteY | number | vertical drop coordinate in the root viewport |
await browser.dragTo(css(".card"), 800, 400);DragResultDragResult with the resolved frameId, backendNodeId and the final cursor position (rootX, rootY) where the drop happened| BrowserScaleError | invalid locator or a server/transport error |
| DragError | the source could not be acquired/pressed; `.code` and `.clickError` describe the underlying click-core failure |
evaluate
method on CloudBrowserevaluate(expression: string): EvaluateResult<T>Runs a JavaScript expression in the page's main frame.
The expression's return value is JSON-serialized server-side and parsed eagerly into .value. When the expression returns a DOM element the .value is null and the element metadata (backendNodeId, isVisible, bounds) is populated instead — use node in subsequent calls to act on it.
The generic T is a TypeScript hint only — there is no runtime validation that the JS expression actually returned that type.
| expression | string | JavaScript expression evaluated in the main frame |
const res = await browser.evaluate<string>("document.title");
console.log(res.value);EvaluateResult<T>EvaluateResult with either value (non-Element) or element metadata (Element)| UNKNOWN_ERROR | the expression threw or could not be compiled |
evaluateInFrame
method on CloudBrowserinherits evaluateevaluateInFrame(frameId: string, expression: string): EvaluateResult<T>Runs a JavaScript expression in the given frame.
Same semantics as evaluate but targets a specific frame instead of the main frame. Useful for evaluating inside OOPIFs (out- of-process iframes) found via getPages. ALL_FRAMES is not supported here.
| frameId | string | id of the frame to evaluate in |
| expression | string | JavaScript expression evaluated in the main frame |
const pages = await browser.getPages();
const iframeId = pages[0].frameTree.children[0].frameId;
await browser.evaluateInFrame(iframeId, "location.href");EvaluateResult<T>EvaluateResult with either value (non-Element) or element metadata (Element)| UNKNOWN_ERROR | the expression threw or could not be compiled |
fill
method on CloudBrowserfill(target: Locator, text: string, opts: FillOpts | undefined): ElementResultClicks the target and types text into it, appending to any existing content.
The browser scrolls the element into view, moves the cursor along a human-like path, clicks to focus, then types the text character- by-character with QWERTZ keyboard simulation and human-like timing.
To overwrite the field instead of appending, pass { clearFirst: true }.
at is not a valid target — fill requires an actual element.
| target | Locator | locator describing the input element |
| text | string | text to type into the element |
| opts | FillOpts | undefined | optional fill customization; see FillOpts |
await browser.fill(css("input[name=email]"), "user@example.com");// Wipe the field first, then type fresh content.
await browser.fill(css("input[name=email]"), "user@example.com", { clearFirst: true });ElementResultElementResult with success, resolved frameId, backendNodeId and the root-viewport (rootX, rootY) where the element was clicked| BrowserScaleError | invalid locator, or a server/transport error (element not found, frame not found, timeout, page closed) |
| FillError | the field could not be focused/typed; `.code` and `.clickError` (the underlying click-core failure) describe why |
getApiKey
method on CloudBrowsergetApiKey(): stringReturns the API key used to rent this session.
stringgetAuthSession
method on CloudBrowsergetAuthSession(): AuthSession | undefinedExports the signed-in primary account and DBSC sessions of this browser context.
State is read in the browser process, so no page needs to be open. Returns undefined when the context has neither a signed-in account nor DBSC sessions.
const auth = await browser.getAuthSession();
if (auth) await fs.writeFile("auth.json", JSON.stringify(auth));AuthSession | undefinedAuthSession, or undefined when there is nothing to export| UNKNOWN_ERROR | the auth session could not be read |
getCookies
method on CloudBrowsergetCookies(): CookieParam[]Returns all cookies currently stored in this session's browser context.
const cookies = await browser.getCookies();
for (const c of cookies) console.log(c.name, "=", c.value);CookieParam[]CookieParam[], one per cookie in the context| UNKNOWN_ERROR | the cookies could not be read |
getDOM
method on CloudBrowsergetDOM(frameId: string, opts: GetDOMOpts | undefined): DOMResultReturns the DOM in CDP DOM.Node shape for the requested frame.
The shape matches Chrome DevTools' Protocol DOM.Node — useful for piping into agent loops or visualizers that already speak CDP. For a much smaller agent-oriented payload, prefer getObservation instead. The cheap polling endpoint is getDOMHash.
| frameId | string | id of the frame to dump; empty string targets the main frame |
| opts | GetDOMOpts | undefined | optional depth: -1 full tree (default), 0 root only, N root + N descendant levels |
const { dom } = await browser.getDOM();DOMResultDOMResult with the JSON string in .dom (the .hash field is populated by getDOMHash, not by this call)| UNKNOWN_ERROR | the DOM could not be retrieved |
getDOMHash
method on CloudBrowsergetDOMHash(frameId: string): stringReturns sha256:8 of the full-tree DOM JSON for cheap polling-based change detection.
Computing a hash is much cheaper than transferring the full tree — pair this with getDOM only when the hash differs from your last snapshot.
| frameId | string | id of the frame to hash; empty string targets the main frame |
const hash = await browser.getDOMHash();
if (hash !== lastHash) {
// DOM changed → re-fetch
}string16-char hex string (the first 8 bytes of sha256 of the DOM JSON)| UNKNOWN_ERROR | the hash could not be computed |
getFingerprint
method on CloudBrowsergetFingerprint(): stringReturns the browser fingerprint id in use for this session.
stringgetObservation
method on CloudBrowsergetObservation(opts: GetObservationOpts | undefined): stringReturns a compact, frame-aware view of the visible page — the first thing to reach for on an unfamiliar page, and the cheapest way to re-read the current state afterwards.
Each frame opens with header lines carrying the URL, the title and the scroll position, then one line per visible element:
`` input#email47 type="email" name="loginId" value="a@b.com" required click "E-Mail" ``
It spans every frame, pierces open and closed shadow roots, enumerates <select> options, and reports live form state: value= is what is typed in right now (passwords as a length), checked= for boxes. The trailing quoted string is always the label or text, never the value, so an empty and a prefilled field stay distinguishable. Because the headers already carry URL, title and scroll offset, this replaces the usual handful of evaluate probes after each step.
On what to do with the result: backendNodeId (the 47 above) is a handle for this session and can be passed straight to click/fill via node. It does not survive a new document, so for anything you write into a script, target with css or js instead — those calls return the backendNodeId they resolved to, which lets you confirm the durable anchor hits the element you saw.
| opts | GetObservationOpts | undefined | optional format and budget overrides; see GetObservationOpts |
const obs = await browser.getObservation();
console.log(obs);stringthe observation in the requested format, ready to hand to a model| UNKNOWN_ERROR | the observation could not be produced |
getPages
method on CloudBrowsergetPages(): PageInfo[]Returns all open pages (tabs and popups) for this session's browser context.
Each PageInfo carries the page's URL, title, viewport and a full nested frame tree (out-of-process iframes are children of the page's main frame).
const pages = await browser.getPages();
for (const p of pages) console.log(p.url, p.title);PageInfo[]PageInfo[] for every page currently open in the context| UNKNOWN_ERROR | the pages could not be enumerated |
getSelection
method on CloudBrowsergetSelection(): stringReturns the current text selection.
Walks every frame and returns the first non-empty selection found — useful for "copy what the user highlighted" flows. Returns an empty string when nothing is selected anywhere.
const sel = await browser.getSelection();
console.log("user selected:", sel);stringthe selected text, or "" when nothing is selected| UNKNOWN_ERROR | the selection could not be read |
getSessionId
method on CloudBrowsergetSessionId(): stringReturns the unique server-assigned id for this browser session.
stringgetStorage
method on CloudBrowsergetStorage(origin: string | undefined): StorageOriginEntry[]Returns the localStorage contents of this session's browser context, grouped by origin.
The storage database is read directly in the browser process, so no page needs to be open. Only first-party localStorage is included — sessionStorage is per-tab and not covered.
| origin | string | undefined | if set, only this origin is returned (e.g. "https://example.com"); omit to get all origins |
const storage = await browser.getStorage();
for (const e of storage) {
for (const { key, value } of e.items) console.log(e.origin, key, "=", value);
}StorageOriginEntry[]StorageOriginEntry[], one per origin with localStorage data| UNKNOWN_ERROR | the storage could not be read |
getStreamConfig
method on CloudBrowsergetStreamConfig(): IceServer[]Returns the ICE servers (TURN URL + short-lived credentials) to put in your RTCPeerConnection BEFORE creating the offer, so it can gather relay candidates.
Live streaming is a two-step, client-offerer handshake: call getStreamConfig, build your peer with the returned servers, create an offer, then pass its SDP to startStream and apply the answer.
const ice = await browser.getStreamConfig();
const pc = new RTCPeerConnection({ iceServers: ice });IceServer[]the ICE servers for the client RTCPeerConnection| UNKNOWN_ERROR | TURN is not configured on the server |
highlightNode
method on CloudBrowserhighlightNode(backendNodeId: number, frameId: string): voidPaints a debug overlay over the node identified by backendNodeId.
Useful for visual debugging of agent flows — the overlay stays until the next call. Pass backendNodeId <= 0 to clear any current highlights.
| backendNodeId | number | id of the node to highlight, or <= 0 to clear |
| frameId | string | id of the frame the node lives in; empty string targets the main frame |
await browser.highlightNode(res.backendNodeId, res.frameId);void| UNKNOWN_ERROR | the highlight could not be applied |
insertText
method on CloudBrowserinsertText(text: string): voidPastes text at the current caret using IME-style input.
No individual key events are dispatched; the entire string is committed at once via Input.insertText. Whatever element currently has focus receives the text. Use click or fill first if you need a specific element to be focused.
| text | string | the text to insert at the caret |
await browser.insertText("hello world");void| UNKNOWN_ERROR | the text could not be inserted |
inspectAtPosition
method on CloudBrowserinspectAtPosition(x: number, y: number): InspectResultHit-tests at the viewport-relative (x, y) and returns the topmost element under that point.
Mirrors what the live-UI overlay does on hover. Elements with pointer-events:none are skipped — the result is the actual click target, not the visually-topmost node. A backendNodeId === 0 in the result means nothing was found.
| x | number | viewport-relative x in CSS pixels |
| y | number | viewport-relative y in CSS pixels |
const r = await browser.inspectAtPosition(200, 300);
console.log(r.tagName, r.textContent);InspectResultInspectResult with the resolved backendNodeId, frameId, tag name, trimmed textContent, visibility and bounds| UNKNOWN_ERROR | the hit-test failed |
listReactions
method on CloudBrowserlistReactions(): ReactionInfo[]Returns the still-pending reactions registered for the current page. Reactions that have already fired (one-shot) are not included.
const pending = await browser.listReactions();
for (const r of pending) console.log(r.reactionId, r.matchSelector);ReactionInfo[]the pending reactions for the pageloadHTML
method on CloudBrowserloadHTML(url: string, html: string, opts: LoadHTMLOpts | undefined): voidServes a synthetic response for the next navigation to url.
Registers a one-shot interceptor that intercepts the next request to url and replies with the supplied html and headers instead of going to the network. Useful for snapshotted pages, test fixtures, and offline replays. Pair with navigate to trigger the load.
| url | string | URL pattern that, when navigated to, returns the html |
| html | string | response body to serve |
| opts | LoadHTMLOpts | undefined | optional headers and statusCode (default 200) |
await browser.loadHTML("https://example.com", "<h1>hi</h1>");
await browser.navigate("https://example.com");void| UNKNOWN_ERROR | the interceptor could not be installed |
modifyRequest
method on CloudBrowsermodifyRequest(urlPattern: string, opts: {
body?: string;
modifications?: HeaderModification[];
timeoutMs?: number;
} | undefined): InterceptedRequest | nullWaits for the next request whose URL matches urlPattern, applies the supplied header modifications (and optional body replacement), then forwards the modified request.
One-shot: consumes the first matching request. Each modification is a plain HeaderModification object literal.
| urlPattern | string | URL wildcard to wait for |
| opts | { body?: string; modifications?: HeaderModification[]; timeoutMs?: number; } | undefined | optional body (replacement request body), modifications (header changes), and timeoutMs (per-call timeout) |
const req = await browser.modifyRequest("*\/api/me", {
modifications: [
{ action: "add", name: "X-Trace", value: "abc123" },
{ action: "remove", name: "Cookie" },
],
timeoutMs: 5000,
});
console.log("forwarded headers:", req?.headers);InterceptedRequest | nullInterceptedRequest carrying the method/URL/headers/body that were actually sent on the wire after modifications were applied; null when no request payload was reported| UNKNOWN_ERROR | no matching request appeared within the timeout |
moveTo
method on CloudBrowsermoveTo(target: Locator): ElementResultMoves the mouse cursor over the given target.
The browser scrolls the target into view first if necessary, then animates the cursor along a human-like path to the element's center (or to the viewport coordinate when target is at).
| target | Locator | locator describing where to move; at is also valid |
await browser.moveTo(css("nav .menu"));ElementResultElementResult with the resolved frameId, backendNodeId, post-scroll isVisible, element bounds and the root-viewport (rootX, rootY) where the cursor ended up| BrowserScaleError | invalid locator or a server/transport error |
| MoveError | the target could not be located (`.code` is `"not_found"`); `.result` carries the resolved payload |
pressKey
method on CloudBrowserpressKey(key: string, opts: { code?: string; modifiers?: number; location?: number } | undefined): voidFires a single key-down event.
Only the keydown half is dispatched — pair with releaseKey for a full press cycle. The event targets whichever element currently has focus.
| key | string | DOM KeyboardEvent.key value (e.g. "Enter", "a", "ArrowLeft") |
| opts | { code?: string; modifiers?: number; location?: number } | undefined | optional key customization: code (DOM KeyboardEvent.code, e.g. "KeyA"), modifiers (bit-flag: Alt=1, Ctrl=2, Meta=4, Shift=8), location (0=standard, 1=left, 2=right, 3=numpad) |
// Ctrl+A
await browser.pressKey("a", { code: "KeyA", modifiers: 2 });
await browser.releaseKey("a", { code: "KeyA", modifiers: 2 });void| UNKNOWN_ERROR | the event could not be dispatched |
readCanvas
method on CloudBrowserreadCanvas(target: Locator, opts: ReadCanvasOpts | undefined): ReadCanvasResultReads the pixels of a <canvas> element directly in the renderer, bypassing the origin-clean (tainted) security check and without executing any page JavaScript — so cross-origin/tainted canvases (common in captchas) read fine where a normal toDataURL / getImageData would throw a SecurityError.
at is not a valid target — a real <canvas> element is required.
| target | Locator | locator for the <canvas>; css, js or node |
| opts | ReadCanvasOpts | undefined | optional format, quality, sub-rectangle and frame override; see ReadCanvasOpts |
const res = await browser.readCanvas(css("#game canvas"));
await fs.writeFile("canvas.png", Buffer.from(res.dataBase64, "base64"));// Read the left half as JPEG at quality 80.
const res = await browser.readCanvas(css("canvas"), {
format: "jpeg", quality: 80, sw: 150, sh: 300,
});ReadCanvasResultReadCanvasResult with the base64 image in dataBase64, the canvas width/height, resolved frameId/backendNodeId and the originClean flag| ELEMENT_NOT_FOUND | no element matched the locator |
| FRAME_NOT_FOUND | the requested frame does not exist |
| INVALID_LOCATOR | target is empty, uses at(x,y), or has multiple targets |
| PAGE_NOT_ALIVE | the page has been closed |
| TIMEOUT | the operation exceeded the server-side timeout |
releaseKey
method on CloudBrowserinherits pressKeyreleaseKey(key: string, opts: { code?: string; modifiers?: number; location?: number } | undefined): voidFires a single key-up event.
Mirror of pressKey. Same parameter semantics; use this to close a press cycle that was started with pressKey.
| key | string | DOM KeyboardEvent.key value (e.g. "Enter", "a", "ArrowLeft") |
| opts | { code?: string; modifiers?: number; location?: number } | undefined | optional key customization: code (DOM KeyboardEvent.code, e.g. "KeyA"), modifiers (bit-flag: Alt=1, Ctrl=2, Meta=4, Shift=8), location (0=standard, 1=left, 2=right, 3=numpad) |
await browser.pressKey("Shift", { code: "ShiftLeft", location: 1 });
await browser.releaseKey("Shift", { code: "ShiftLeft", location: 1 });void| UNKNOWN_ERROR | the event could not be dispatched |
removeReaction
method on CloudBrowserremoveReaction(reactionId: string): booleanRemoves a pending reaction by id. Returns false if the reaction had already fired (one-shot) or was never registered.
| reactionId | string | id returned by CloudBrowser.addReaction |
const removed = await browser.removeReaction(id);booleantrue if a pending reaction with this id existed and was removedscreenshot
method on CloudBrowserscreenshot(opts: ScreenshotOpts | undefined): ScreenshotResultCaptures a single image of the page's current frame and returns it as base64-encoded image bytes.
The capture uses a one-shot surface copy (the same mechanism as CDP Page.captureScreenshot), so it is independent of any active live stream and works with both GPU (hardware) and software compositing.
| opts | ScreenshotOpts | undefined | optional format ("png" default, "jpeg", "webp") and quality (0-100, for jpeg/webp only); omit to use the server defaults |
const shot = await browser.screenshot({ format: "png" });
await fs.writeFile("page.png", Buffer.from(shot.dataBase64, "base64"));ScreenshotResultScreenshotResult with the base64 image in dataBase64 and the physical pixel width/height| UNKNOWN_ERROR | the screenshot could not be captured |
scrollTo
method on CloudBrowserscrollTo(target: Locator): ElementResultScrolls the given element into view.
Whatever scroll container is closest to the element does the scrolling — nested scroll containers and out-of-process iframe chains are walked automatically. at is not a valid target here; scrolling needs a real element.
| target | Locator | locator describing the element to bring into view; at is rejected |
await browser.scrollTo(css("#footer"));ElementResultElementResult with the resolved frameId, backendNodeId, post-scroll isVisible and the element's bounds after the scroll| BrowserScaleError | invalid locator or a server/transport error |
| ScrollError | the target could not be located/scrolled (`.code` is `"not_found"`); `.result` carries the resolved payload |
selectByIndex
method on CloudBrowserselectByIndex(target: Locator, index: number, opts: SelectOpts | undefined): SelectOptionResultPicks the <option> at the zero-based index inside the targeted <select> element.
Sets the option as selected on the targeted <select>, then fires the standard input + change events (unless suppressed via opts.fireEvents = false).
at is not a valid target — select requires an actual <select> element.
| target | Locator | locator describing the <select> element |
| index | number | zero-based option index |
| opts | SelectOpts | undefined | optional select customization; see SelectOpts |
await browser.selectByIndex(css("select#country"), 2);// Pick the option silently, no input/change events.
await browser.selectByIndex(css("select#hidden"), 0, { fireEvents: false });SelectOptionResultSelectOptionResult with the resolved selectedIndex, selectedValue and selectedText after the change| BrowserScaleError | invalid locator, or a server/transport error (frame not found, timeout, page closed) |
| SelectOptionError | the option could not be selected; `.code` is `"not_found"` (no `<select>`) or `"option_not_found"` |
selectByText
method on CloudBrowserinherits selectByIndexselectByText(target: Locator, text: string, opts: SelectOpts | undefined): SelectOptionResultPicks the <option> whose visible (trimmed) text matches the given string exactly.
Sets the option as selected on the targeted <select>, then fires the standard input + change events (unless suppressed via opts.fireEvents = false).
at is not a valid target — select requires an actual <select> element.
| target | Locator | locator describing the <select> element |
| text | string | the visible option text to match |
| opts | SelectOpts | undefined | optional select customization; see SelectOpts |
await browser.selectByText(css("select#country"), "Germany");SelectOptionResultSelectOptionResult with the resolved selectedIndex, selectedValue and selectedText after the change| BrowserScaleError | invalid locator, or a server/transport error (frame not found, timeout, page closed) |
| SelectOptionError | the option could not be selected; `.code` is `"not_found"` (no `<select>`) or `"option_not_found"` |
selectByValue
method on CloudBrowserinherits selectByIndexselectByValue(target: Locator, value: string, opts: SelectOpts | undefined): SelectOptionResultPicks the <option> whose value attribute matches the given string exactly.
Sets the option as selected on the targeted <select>, then fires the standard input + change events (unless suppressed via opts.fireEvents = false).
at is not a valid target — select requires an actual <select> element.
| target | Locator | locator describing the <select> element |
| value | string | the value attribute to match |
| opts | SelectOpts | undefined | optional select customization; see SelectOpts |
await browser.selectByValue(css("select#country"), "DE");SelectOptionResultSelectOptionResult with the resolved selectedIndex, selectedValue and selectedText after the change| BrowserScaleError | invalid locator, or a server/transport error (frame not found, timeout, page closed) |
| SelectOptionError | the option could not be selected; `.code` is `"not_found"` (no `<select>`) or `"option_not_found"` |
setAuthSession
method on CloudBrowsersetAuthSession(session: AuthSession): voidImports an auth session so the context comes up signed in (and syncing if syncConsent) with its DBSC sessions restored.
Call it before navigating. Pair with setCookies() / setStorage() to restore a full persona.
| session | AuthSession | session as returned by getAuthSession() |
await browser.setAuthSession(saved);
await browser.navigate("https://mail.google.com");void| UNKNOWN_ERROR | the auth session could not be written |
setBlockList
method on CloudBrowsersetBlockList(patterns: string[]): voidReplaces the session's URL blocklist.
Any request whose URL matches one of the supplied patterns is blocked before it leaves the browser. Patterns are simple URL wildcards (* matches any character span). Pass an empty array to clear the blocklist and let everything through.
| patterns | string[] | URL wildcards to block; empty array clears the list |
await browser.setBlockList([
"*.doubleclick.net/*",
"*googletagmanager.com*",
]);void| UNKNOWN_ERROR | the blocklist could not be applied |
setCookies
method on CloudBrowsersetCookies(cookies: CookieParam[]): voidWrites the supplied cookies into the browser context.
Existing cookies with the same (name, domain, path) tuple are overwritten. Pass an empty array for a no-op.
| cookies | CookieParam[] | cookies to write; empty array is a no-op |
await browser.setCookies([
{ name: "auth", value: "tok", domain: "example.com", path: "/" },
]);void| UNKNOWN_ERROR | the cookies could not be written |
setProxy
method on CloudBrowsersetProxy(proxyHost: string, proxyPort: number, proxyUsername: string, proxyPassword: string): voidChanges the runtime proxy for this session.
Takes effect for new requests immediately; in-flight requests keep their original routing. Pass an empty proxyHost to clear the proxy and route directly.
| proxyHost | string | upstream proxy host; empty disables the proxy |
| proxyPort | number | upstream proxy port; ignored when proxyHost is empty |
| proxyUsername | string | proxy auth user; empty for unauthenticated proxies |
| proxyPassword | string | proxy auth password; empty for unauthenticated proxies |
await browser.setProxy("proxy.example.com", 8080, "user", "pass");void| UNKNOWN_ERROR | the proxy could not be applied |
setStaticPaths
method on CloudBrowsersetStaticPaths(blobName: string, patterns: string[]): voidConfigures the session to serve cached static responses for requests matching the given patterns from blobName.
Useful for replaying frozen page assets (HTML/JS/CSS/images) without hitting the origin every time. The cache backend itself is configured server-side. Pass an empty patterns array to disable caching for this session.
| blobName | string | server-side identifier of the snapshot to serve from |
| patterns | string[] | URL wildcards to redirect to the cache; empty disables |
await browser.setStaticPaths("snap-2026-05", ["*.example.com/*"]);void| UNKNOWN_ERROR | the static paths could not be configured |
setStorage
method on CloudBrowsersetStorage(storage: StorageOriginEntry[]): voidWrites localStorage entries into the browser context, grouped by origin.
Accepts the same structure getStorage() returns, so a dump can be fed back verbatim. Existing keys are overwritten. Works without any open page; pages that are already open will not observe the writes until they reload.
| storage | StorageOriginEntry[] | entries to write, grouped by origin |
await browser.setStorage([
{
origin: "https://example.com",
items: [
{ key: "token", value: "abc123" },
{ key: "theme", value: "dark" },
],
},
]);void| UNKNOWN_ERROR | the storage could not be written |
solveCaptcha
method on CloudBrowsersolveCaptcha(opts: { timeoutMs?: number; retryAmount?: number } | undefined): stringDetects and solves the first supported bot-challenge it finds anywhere on the page.
Detection covers the common challenge types you run into in the wild. The challenge is completed in-page server-side (the resulting token / bypass cookies are wired into the page automatically), so callers can ignore the returned string.
| opts | { timeoutMs?: number; retryAmount?: number } | undefined | optional timeoutMs (how long to wait for a captcha to appear; omit for server default 60s) and retryAmount (failures tolerated before giving up) |
await browser.solveCaptcha({ retryAmount: 2 });stringempty string on success — the solution is applied server-side| UNKNOWN_ERROR | no captcha appeared within timeoutMs, or the detected captcha could not be solved within retryAmount attempts |
startStream
method on CloudBrowserstartStream(offerSdp: string): stringAnswers your WebRTC SDP offer and starts streaming the page as a video track, returning the SDP answer to set as your peer's remote description. The browser is the answerer; you are the offerer (see getStreamConfig for the credentials to build the offer).
| offerSdp | string | your RTCPeerConnection's SDP offer |
const answer = await browser.startStream(offer.sdp);
await pc.setRemoteDescription({ type: "answer", sdp: answer });stringthe SDP answer to apply as the remote description| UNKNOWN_ERROR | the offer was empty, TURN is unconfigured, or the browser could not negotiate the stream |
stopStream
method on CloudBrowserstopStream(): voidTears down the live video stream for the session's page. Safe to call even if no stream is running.
await browser.stopStream();void| UNKNOWN_ERROR | the stream could not be stopped |
type
method on CloudBrowsertype(text: string, opts: { clearFirst?: boolean } | undefined): voidTypes text into the currently focused element as a per-key stream of real keyboard events (keyDown/char/keyUp with the context's QWERTZ/QWERTY layout and human cadence) — unlike insertText, a single IME-style commit with no key events.
type is intentionally UNtargeted and loose: it does not locate or focus any element and does NOT pin focus, so the page is free to route keys and move focus between fields mid-stream — ideal for one-time-code / OTP inputs that auto-advance to the next box on each digit. To type one specific field that must stay focused for the whole value, use fill instead (strict, target-bound, per-key focus-verified).
Nothing is focused for you: click (or fill) the field first, or otherwise ensure focus, before calling type.
| text | string | the text to type as real key events |
| opts | { clearFirst?: boolean } | undefined | optional: clearFirst clears the focused field (Ctrl+A, Delete) before typing |
// OTP field that auto-advances across boxes.
await browser.click(css("input.otp-0"));
await browser.type("123456");void| UNKNOWN_ERROR | the page/context was torn down mid-stream |
wait
method on CloudBrowserinherits waitAnywait(condition: Locator, opts: WaitOpts | undefined): WaitResultBlocks until the given locator matches.
Shortcut for waitAny(condition, opts). See waitAny for timeout handling, per-locator visible/steady defaults and the list of locators that are not valid wait conditions.
| condition | Locator | the single locator to wait for |
| opts | WaitOpts | undefined | optional wait customization (timeoutMs) |
await browser.wait(css(".success"));WaitResultWaitResult for the first matching condition| BrowserScaleError | a condition was invalid, or a server/transport error occurred |
| WaitError | no condition matched before the deadline; `.conditions` holds the per-condition breakdown of why each never matched |
waitAny
method on CloudBrowserwaitAny(conditions: Locator[], opts: WaitOpts | undefined): WaitResultBlocks until any of the supplied locators matches.
When several conditions are supplied, the first one to match wins; the others are abandoned. The returned WaitResult's .index points to the entry in conditions that matched.
Defaults applied automatically: - timeout: 30000 ms — override via opts.timeoutMs - per-locator visible/steady: true / 500 for css() and js() locators. For js() expressions returning a non-Element value both flags are no-ops. Override with .visible(false) / .steady(ms) on individual locators.
node and at are not valid wait conditions — they only make sense as action targets — and throw at send time.
| conditions | Locator[] | one or more Locators to wait for; must be non-empty |
| opts | WaitOpts | undefined | optional wait customization (timeoutMs) |
const r = await browser.waitAny(
[css(".success"), js("window.__ready === true")],
{ timeoutMs: 5000 },
);
console.log("matched index:", r.index);WaitResultWaitResult for the first matching condition| BrowserScaleError | a condition was invalid, or a server/transport error occurred |
| WaitError | no condition matched before the deadline; `.conditions` holds the per-condition breakdown of why each never matched |
waitForAnyRequest
method on CloudBrowserwaitForAnyRequest(patterns: RequestPattern[], opts: { timeoutMs?: number } | undefined): { index: number; request: InterceptedRequest | null }Blocks until the next request whose URL matches one of the supplied patterns is observed.
Returns the matched pattern's index and the captured request. When patternsi.abort is true the request is dropped with an empty 200 response instead of being sent to the network.
| patterns | RequestPattern[] | one or more URL patterns (with optional abort flags) |
| opts | { timeoutMs?: number } | undefined | optional timeoutMs; omit to use the server default |
const { index, request } = await browser.waitForAnyRequest(
[{ url: "*\/api/login" }],
{ timeoutMs: 5000 },
);
console.log(index, request?.method, request?.url);{ index: number; request: InterceptedRequest | null }object with index (matched pattern index) and request (the captured method/URL/headers/body; null if intercepted with no body)| UNKNOWN_ERROR | the wait timed out or no patterns were supplied |
waitForAnyResponse
method on CloudBrowserinherits waitForAnyRequestwaitForAnyResponse(patterns: RequestPattern[], opts: { timeoutMs?: number } | undefined): { index: number; response: InterceptedResponse | null }Blocks until the next response whose URL matches one of the supplied patterns is observed.
Same shape as waitForAnyRequest but on the response phase. When patternsi.abort is true the page receives an empty 200 instead of the real response.
| patterns | RequestPattern[] | one or more URL patterns (with optional abort flags) |
| opts | { timeoutMs?: number } | undefined | optional timeoutMs; omit to use the server default |
const { index, response } = await browser.waitForAnyResponse(
[{ url: "*\/api/login" }],
{ timeoutMs: 5000 },
);
console.log(index, response?.statusCode);{ index: number; response: InterceptedResponse | null }object with index (matched pattern index) and response (the captured status/headers/body; null if no body was returned)| UNKNOWN_ERROR | the wait timed out or no patterns were supplied |
Locator
Locator is the universal "what element / what condition" type. It is used both as a wait condition (passed to wait()/waitAny()) and as a target for element actions (passed to click(), fill(), …).
Not every field is meaningful in every context: - selector / jsExpression → both wait and actions - backendNodeId → actions only (wait rejects it) - visible / steadyMs → wait only (silently ignored by actions) - x / y → actions only (wait rejects it) - frameId → both, may be overridden by call-level opts.inFrame
Use the css() / js() / node() / at() constructors instead of building this class by hand.
Modifiers (visible, steady, inFrame, inAllFrames) are immutable — they return a new Locator and leave the original untouched, so it's safe to share a base locator across calls.
| selector | string = "" | |
| jsExpression | string = "" | |
| backendNodeId | number = 0 | |
| frameId | string = "" | |
| visibleFlag? | boolean | |
| steadyMs? | number | |
| x? | number | |
| y? | number |
inAllFrames
method on LocatorinAllFrames(): LocatorScopes this Locator to every frame.
Equivalent to .inFrame(AllFrames). Use this when an element might appear inside any of several frames and you do not want to enumerate them.
await browser.wait(css("button.consent").inAllFrames());Locatora new Locator scoped to all framesinFrame
method on LocatorinFrame(frameId: string): LocatorScopes this Locator to a specific frameId.
Use the frameId from a previous result or CloudBrowser.getPages to target elements inside a known iframe.
| frameId | string | id of the frame to scope to |
const pages = await browser.getPages();
const iframeId = pages[0].frameTree.children[0].frameId;
await browser.click(css("button").inFrame(iframeId));Locatora new Locator scoped to that framesteady
method on Locatorsteady(ms: number): LocatorRequires the element to keep a stable position and size for at least ms milliseconds before the wait matches.
Pass 0 to disable the default DefaultSteadyMs (500). Has no effect for js() expressions that return a non-Element value, nor when used as an action target.
| ms | number | steady-state duration in milliseconds; 0 disables |
await browser.wait(css(".banner").steady(0));Locatora new Locator with the override appliedvisible
method on Locatorvisible(v: boolean): LocatorEnforces or disables the visibility check for this Locator's wait condition.
Pass false to opt out of the default DefaultVisible (true). Has no effect when used as an action target — actions never check visibility before dispatching.
| v | boolean | true to require visibility, false to skip the check |
await browser.wait(css("#hidden").visible(false));Locatora new Locator with the override appliedBrowserConfig
Configuration for renting a browser session. Create with the required parameters, then chain optional setters.
| apiKey | string | |
| rentDuration | number | |
| proxyHost | string | |
| proxyPort | number | |
| proxyUsername | string | |
| proxyPassword | string |
withCountryCode
method on BrowserConfigwithCountryCode(countryCode: string): BrowserConfigSets the geo-IP country code for the rented session.
Drives both the assigned exit-IP region and the locale defaults (Accept-Language, timezone fallback) when those are not overridden separately.
| countryCode | string | ISO-3166 country code (e.g. "DE", "US") |
new BrowserConfig(apiKey, 600, "", 0, "", "").withCountryCode("DE");BrowserConfigthis BrowserConfig for chainingwithFingerprint
method on BrowserConfigwithFingerprint(fingerprint: string): BrowserConfigPins a specific browser fingerprint id for the session.
When omitted the server picks a fingerprint based on the country code. Pass a known id (e.g. one returned by a previous rental) to keep fingerprints stable across sessions.
| fingerprint | string | server-side fingerprint id |
new BrowserConfig(apiKey, 600, "", 0, "", "").withFingerprint("fp_abc123");BrowserConfigthis BrowserConfig for chainingwithTimezone
method on BrowserConfigwithTimezone(timezone: string): BrowserConfigSets the IANA timezone for the rented session.
| timezone | string | IANA timezone (e.g. "Europe/Berlin") |
new BrowserConfig(apiKey, 600, "", 0, "", "").withTimezone("Europe/Berlin");BrowserConfigthis BrowserConfig for chainingFunctions
at
functionat(x: number, y: number): Locatorat targets viewport coordinates instead of an element.
Useful for clicking inside a canvas, hovering decorative regions, or dispatching events at synthetic positions. Action-only — using it in wait() throws at send time. Note that only click and moveTo accept at; scrollTo, drag, fill and select all require a real element.
| x | number | viewport-relative x in CSS pixels |
| y | number | viewport-relative y in CSS pixels |
// Click at canvas-relative coordinates.
await browser.click(at(120, 240));LocatorLocator usable only as an action targetconnectSession
functionconnectSession(grpcUrl: string, apiKey: string, sessionId: string): CloudBrowserAttaches to an already-rented session over a fresh gRPC connection.
Useful when a session id (and its gRPC URL) was persisted across processes and you want to drive it again without renting a new one. Mirrors browserscale-go's ConnectSession. Closing the returned handle via CloudBrowser.stopBrowser releases the rental (calls the stop endpoint) and closes the transport.
| grpcUrl | string | session host gRPC URL from the original rent (grpc:// or grpcs://) |
| apiKey | string | API key the session was rented with |
| sessionId | string | id of the existing session |
const browser = connectSession(grpcUrl, apiKey, sessionId);
try {
await browser.navigate("https://example.com");
} finally {
await browser.stopBrowser();
}CloudBrowserCloudBrowser attached to the existing sessioncreateWebSocketBrowser
functioncreateWebSocketBrowser(wsUrl: string, sessionId: string, apiKey: string, fingerprint: string): CloudBrowserAttaches a CloudBrowser to an existing session over a raw WebSocket transport.
Use this from a browser context: the WebSocket transport framing is defined by WebSocketTransport and is served directly by the browserscale session host. The session must already exist server-side; unlike rentBrowser this does not call the rent API. Closing the returned handle (via CloudBrowser.stopBrowser) only closes the transport — the rental stays alive.
| wsUrl | string | WebSocket URL (ws:// or wss://) of the session host |
| sessionId | string | id of the existing session |
| apiKey | string | API key authorizing access to the session |
| fingerprint | string | browser fingerprint id; empty if unknown |
const browser = createWebSocketBrowser(
"wss://session-abc.browserscale.example.com/ws",
sessionId,
apiKey,
);
await browser.navigate("https://example.com");CloudBrowserCloudBrowser attached to the existing sessioncss
functioncss(selector: string): Locatorcss waits for / targets an element matching the given CSS selector.
When used in CloudBrowser.wait/CloudBrowser.waitAny, the returned Locator carries the SDK defaults DefaultVisible (true) and DefaultSteadyMs (500). Override per call with .visible(false) / .steady(ms) (use .steady(0) to disable the steady check).
When used as an action target (click, fill, …) the visible/steady fields are ignored — there are no corresponding fields on the action requests.
| selector | string | CSS selector matching the element |
// As a wait condition.
await browser.wait(css("button.submit"));
// As an action target.
await browser.click(css("button.submit"));LocatorLocator usable as a wait condition or as an action targetjs
functionjs(expression: string): Locatorjs waits for / targets the result of a JavaScript expression.
Same wait defaults as css (DefaultVisible=true, DefaultSteadyMs=500); these only apply when the expression returns a DOM Element. For non-Element truthy values (boolean, string, number, plain object) both fields are no-ops and the condition matches as soon as the value is truthy. Use .visible(false) / .steady(0) to opt out.
| expression | string | JavaScript expression evaluated in the target frame |
await browser.wait(js("window.__ready === true"));LocatorLocator usable as a wait condition or as an action targetnode
functionnode(backendNodeId: number): Locatornode targets an element by its DevTools backendNodeId.
Use this when you already have a backendNodeId from a previous result (e.g. a wait or evaluate result) and want to act on the exact same element without re-resolving by selector. Action-only — using it in wait() throws at send time.
| backendNodeId | number | DevTools backendNodeId of the target element |
const r = await browser.click(css("button.open"));
await browser.click(node(r.backendNodeId));LocatorLocator usable only as an action targetrentBrowser
functionrentBrowser(config: BrowserConfig): CloudBrowserRents a new browser session and returns a connected handle.
Calls the browserscale rent endpoint with the supplied BrowserConfig, opens a gRPC connection to the assigned session host, and returns a ready-to-use CloudBrowser. Closing the returned handle (via CloudBrowser.stopBrowser) also releases the rental.
| config | BrowserConfig | rental parameters |
const cfg = new BrowserConfig("sk_…", 600, "", 0, "", "");
const browser = await rentBrowser(cfg);
try {
await browser.navigate("https://example.com");
} finally {
await browser.stopBrowser();
}CloudBrowserCloudBrowser ready to drive the rented session| UNKNOWN_ERROR | the rent API rejected the request or the gRPC connection could not be established |
setApiEndpoint
functionsetApiEndpoint(endpoint: string): voidOverrides the HTTP rent/stop endpoint.
Defaults to https://api.browserscale.cloud. Call this before any rentBrowser / stopBrowser call if you need to point at a private browserscale deployment.
| endpoint | string | base URL of the rent/stop service, with no trailing slash |
setApiEndpoint("https://browserscale.internal.example.com");voidstopBrowser
functionstopBrowser(apiKey: string, sessionId: string): voidReleases a session without needing a CloudBrowser handle.
Useful when a session id was persisted across processes and the rental outlived the original handle. Only calls the rent stop endpoint; there is no gRPC connection to close in this form.
| apiKey | string | API key the session was rented with |
| sessionId | string | id of the session to release |
await stopBrowser(apiKey, sessionId);void| UNKNOWN_ERROR | the stop API rejected the request |
Types
AuthSession
interfaceAuthSession is a portable snapshot of a context's signed-in Google account and/or DBSC sessions. Every field is optional, so a context that only has DBSC sessions (no primary account) or only a sign-in (no DBSC) round-trips.
Pair it with getCookies()/setCookies() and getStorage()/setStorage() to move a whole persona between fresh contexts.
| gaiaId? | string | Gaia obfuscated account id. |
| email? | string | Account email. |
| refreshToken? | string | OAuth refresh token (persistent). |
| wrappedBindingKey? | string | Base64 of the wrapped device-binding key for the refresh token. Absent means the token is unbound. |
| signinScopedDeviceId? | string | Signin-scoped device id; must travel with the token. |
| syncConsent? | boolean | True if the account should be restored at Sync consent. |
| dbscSessions? | DbscSession[] | Device Bound Session Credentials for this context (all bound sites). |
BrowserScaleError
classBrowserScaleError is the base class for every error thrown by the SDK. It wraps either: - a client-side validation failure (bad locator, missing patterns, …) - a server-side gRPC error (Connect's ConnectError, available as cause)
Semantic action failures (an occluded click, a wait timeout, an option that did not exist, …) are thrown as the typed subclasses below, each carrying the same structured detail the Go SDK exposes via errors.As — plus the partial result of the attempted action on .result, so a single catch gives you both the diagnostics and the resolved coordinates.
Catch the base for anything, or narrow to a subclass for the detail:
try { await browser.click(css("#btn")); } catch (e) { if (e instanceof ClickError) console.log(e.code, e.occluder?.tagName); else if (e instanceof BrowserScaleError) { ... } }
Button
type aliastype Button = "left" | "right" | "middle"Mouse button used by CloudBrowser.click.
ClickAction
type aliastype ClickAction = "click" | "press" | "release"Mouse phase performed by CloudBrowser.click.
ClickError
classClickError is thrown by CloudBrowser.click when the click did not land — the target was found but another element covered the intended point. occluder describes the blocker; result carries the resolved element and coordinates (success is false).
It is also nested under FillError / DragError as the underlying click-core failure; in that nested form result is undefined (the partial result lives on the outer error).
| code | string | Machine-stable failure code, e.g. "occluded_no_reachable_point" (target fully covered, no exposed part reachable), "occluded_after_evade" (a reposition was tried but the target was still covered) or "not_found". |
| occluder? | OccluderInfo | The intercepting element (present for occlusion codes). |
| evadeAttempted | boolean | Whether a pointer reposition was tried before giving up. |
| result? | ElementResult | Resolved element + coordinates at the failed action. Present when this is the thrown top-level error; undefined when nested inside another error. |
ClickOpts
interfaceOptional customization for CloudBrowser.click. All fields are optional; missing or zero values mean "use the server default".
| inFrame? | string | Override the locator's frame. Omit to use the locator's own Locator.inFrame (or the main frame). Pass a specific frameId or AllFrames to search elsewhere. |
| button? | Button | Mouse button. Default "left". |
| clickCount? | number | 1 = single click (default), 2 = double-click. |
| action? | ClickAction | "click" (default) performs a full mouseDown+mouseUp. "press" only dispatches mouseDown, "release" only mouseUp at the current cursor position. |
CookieParam
interfaceCookieParam is one entry returned by getCookies() or passed to setCookies().
| name | string | |
| value | string | |
| url? | string | |
| domain | string | |
| path | string | |
| secure? | boolean | |
| httpOnly? | boolean | |
| sameSite? | string | |
| expires? | number | |
| priority? | string | |
| sourceScheme? | string | |
| sourcePort? | number | |
| partitionKey? | CookiePartitionKey |
CookiePartitionKey
interfacePartition metadata for partitioned cookies (CHIPS).
| topLevelSite | string | |
| hasCrossSiteAncestor | boolean |
DbscSession
interfaceDbscSession is one Device Bound Session Credentials entry.
| site | string | Serialized schemeful site key, e.g. "https://google.com". |
| session | string | Base64 of the serialized DBSC Session proto. It includes the wrapped binding key, which is portable under WRC's software key provider. |
DOMResult
interfaceDOMResult is the full-tree DOM snapshot returned by CloudBrowser.getDOM, plus its sha256:8 hash for cheap change detection.
| hash | string | |
| dom | string |
DragError
classDragError is thrown by CloudBrowser.dragBy / CloudBrowser.dragTo when the source element could not be acquired/pressed. Drag picks up the source with the same smart click as CloudBrowser.click, so a pre-drag failure is a click failure: code mirrors it and the full click diagnostics live under clickError.
| code | string | |
| clickError? | ClickError | |
| result | DragResult | Resolved source + coordinates at the failed drag (success is false). |
DragResult
interfaceDragResult is the outcome of a CloudBrowser.drag gesture: the resolved source element and the start/end coordinates of the performed drag.
| success | boolean | |
| frameId | string | |
| backendNodeId | number | |
| startX | number | |
| startY | number | |
| endX | number | |
| endY | number |
ElementRef
interfaceElementRef is a lightweight descriptor of an element — enough to identify it (and decide what to do) without another DOM round-trip. It names the element that stole focus in a FillError focus-loss failure.
| backendNodeId | number | |
| tagName | string | Upper-case tag name, e.g. "INPUT", "BUTTON", "DIV". |
| id? | string | id attribute, if present. |
| name? | string | name attribute, if present. |
| className? | string | class attribute, if present. |
| inputType? | string | <input> type, if the element is an <input>. |
| text? | string | Whitespace-collapsed textContent/value snippet (max 120 chars). |
| editable | boolean | Whether this element is itself an editable text sink (input / textarea / contenteditable). |
ElementResult
interfaceElementResult is the outcome of an element interaction such as CloudBrowser.click, CloudBrowser.fill or CloudBrowser.scrollTo: the resolved element plus the root-relative coordinates the action was performed at.
| success | boolean | |
| frameId | string | |
| backendNodeId | number | |
| isVisible | boolean | |
| bounds | Rect | |
| rootX | number | |
| rootY | number |
EvaluateResult
interfaceEvaluateResult carries the outcome of a JS evaluate call.
If the expression returned a DOM element, backendNodeId/isVisible/bounds are populated and value is null. Otherwise value holds the parsed JSON value (string/number/boolean/array/object/null). On parse failure value falls back to the raw server string so the caller is never empty-handed.
The optional generic T types the .value field for convenience — this is purely a TS hint, not a runtime guarantee.
| value | T | |
| backendNodeId | number | |
| isVisible | boolean | |
| bounds | Rect |
FillError
classFillError is thrown by CloudBrowser.fill when the field could not be focused/typed. The click-phase codes ("not_found", "occluded_no_reachable_point", "occluded_after_evade") mirror the underlying focus click, with diagnostics under clickError. The focus codes are "focus_stolen" (another element took focus — focusedElement names it; fill is strictly target-bound and will not type into the thief) and "focus_lost" (focus left the target and nothing is focused). For untargeted stream typing that lets focus move (e.g. OTP), use CloudBrowser.type.
| code | string | Machine-stable failure code (see the class doc for the full set). |
| clickError? | ClickError | The underlying click-core failure that prevented focusing/typing. Present for the click-phase codes; undefined for "focus_stolen"/"focus_lost". |
| focusedBackendNodeId? | number | Node that held focus when fill gave up (0 if nothing was focused), for the "focus_stolen"/"focus_lost" codes. |
| focusedElement? | ElementRef | The element that grabbed focus instead of the target ("focus_stolen"), so you can act on it (e.g. a consent button). |
| targetEditable? | boolean | The fill target's own state at the point of failure (the focus codes): whether it is still an editable text sink and its current text length. |
| targetValueLength? | number | |
| result | ElementResult | Resolved element + coordinates at the failed action (success is false). |
FillOpts
interfaceOptional customization for CloudBrowser.fill. All fields are optional; missing values mean "use the server default".
| inFrame? | string | Override the locator's frame. Omit to use the locator's own Locator.inFrame (or the main frame). Pass a specific frameId or AllFrames to search elsewhere. |
| clearFirst? | boolean | true wipes the field's existing content with Ctrl+A, Delete before typing. Default (false) appends to whatever is already in the field. |
| timeoutMs? | number | Budget in ms to make the field focusable+clickable (locate, scroll, settle, un-occlude), mirroring the click timeout. Omit for the server default (5000). 0 makes fill one-shot (no retry). |
| steadyMs? | number | Settle window in ms before the focus click, mirroring the click steady-time. Omit for the server default (750). 0 skips settling. |
FrameInfo
interfaceFrameInfo describes a single frame within a page's frame tree.
GetDOMOpts
interfaceDepth used by getDOM(). 0 = whole tree (default), >0 = limited depth.
| depth? | number |
GetObservationOpts
interfaceOptional customization for CloudBrowser.getObservation.
| format? | "text" | "json" | "text" (default) for the compact line format meant to be handed to a model as-is, or "json" for the structured form. Only the requested representation is built, so asking for one does not cost the other. |
| maxElementsPerFrame? | number | Cap on emitted elements per frame. Default 800 — a safety net against runaway documents; maxTotalTokens is the limit that normally binds. |
| maxTextLength? | number | Cap on human-readable strings (labels, text, values) in characters. Default 300. Identifier-like attributes (type, name, role) have their own fixed, shorter cap and are unaffected. |
| maxTotalTokens? | number | Budget across ALL frames, in estimated tokens rather than characters — the same character count is worth roughly four times as many tokens in CJK text as in ASCII. Default 8000. Frames are visited in tree order and each gets whatever is left. |
| includeBounds? | boolean | Include element bounds as bounds="x,y,w,h". Off by default; bounds cost about as much as the rest of a row and are rarely needed, since elements are addressed by backendNodeId. |
| viewportOnly? | boolean | Only emit elements intersecting the frame's current viewport. |
| backendNodeId? | number | Subtree scope — set exactly one of backendNodeId, selector or jsExpression to observe only that element's subtree (follow-up looks at a form then cost the form, not the ads around it). Omit all three for the whole page. Child iframes reached inside the scope are still visited. |
| selector? | string | Scope root by CSS selector. |
| jsExpression? | string | Scope root by JS expression that evaluates to a DOM Element (including __wrc.shadow(...) for closed shadow roots). |
| frameId? | string | Where to look up the scope root: a specific frameId, omit for the main frame, or AllFrames to search every frame until found. Ignored when observing the whole page. |
Header
interfaceHeader is a single HTTP header (name/value pair) on an intercepted request or response.
| name | string | |
| value | string |
HeaderModification
interfaceHeaderModification is one entry passed to CloudBrowser.modifyRequest. Write it as a plain object literal.
| action | HeaderModificationAction | "add" inserts a new header, "edit" replaces an existing header's value, "remove" drops the header. |
| name | string | Header name the action applies to. |
| value? | string | Header value for add/edit; ignored for remove. |
| before? | string | Positions an "add" immediately before the named existing header; otherwise the header is appended at the end. Ignored for edit/remove. |
| after? | string | Positions an "add" immediately after the named existing header. Mirror of before; ignored for edit/remove. |
HeaderModificationAction
type aliastype HeaderModificationAction = "add" | "edit" | "remove"Action verb for a HeaderModification.
IceServer
interfaceIceServer is one entry for a WebRTC RTCPeerConnection's iceServers config: a TURN (or STUN) URL plus the short-lived credentials to authenticate with it. Pass these to your peer before creating the offer.
| urls | string[] | ICE server URLs (e.g. turn:relay.example.com:3478?transport=udp). |
| username | string | Short-lived TURN REST username (empty for plain STUN). |
| credential | string | Short-lived TURN REST credential (empty for plain STUN). |
InspectResult
interfaceInspectResult describes the topmost element hit at viewport-relative (x, y). backendNodeId === 0 means nothing was found at that position.
| backendNodeId | number | |
| frameId | string | |
| tagName | string | |
| textContent | string | |
| isVisible | boolean | |
| bounds | Rect |
InterceptedRequest
interfaceInterceptedRequest describes an outgoing request captured by CloudBrowser.waitForAnyRequest.
| method | string | |
| url | string | |
| headers | Header[] | |
| body | string | |
| resourceType | string |
InterceptedResponse
interfaceInterceptedResponse describes a network response captured by CloudBrowser.waitForAnyResponse.
| url | string | |
| statusCode | number | |
| headers | Header[] | |
| body | string |
LoadHTMLOpts
interfaceOptional customization for CloudBrowser.loadHTML.
| headers? | { name: string; value: string }[] | Extra headers to attach to the synthetic response. |
| statusCode? | number | Default 200. |
MoveError
classMoveError is thrown by CloudBrowser.moveTo when the target could not be located. A move has no occlusion notion, so this is the only semantic failure.
| code | string | Currently always "not_found". |
| result | ElementResult |
OccluderInfo
interfaceOccluderInfo describes the element that intercepted a click — the element sitting on top of the target at the intended click point. Coordinates are in root-viewport CSS pixels. Populated on ClickError for occlusion failures so the caller can locate and clear the blocker (e.g. find its close button).
| backendNodeId | number | |
| frameId | string | |
| tagName | string | |
| id | string | |
| className | string | |
| text | string | |
| bounds | Rect | |
| pointerEvents | string | Computed pointer-events keyword (e.g. "auto", "none", "all"). Lets you tell an invisible pass-through layer from one that genuinely swallows the click. |
| visibility | string | Computed visibility keyword ("visible", "hidden", "collapse"). |
| opacity | number | Computed opacity (0..1). 0 means visually invisible but it may still intercept clicks depending on pointerEvents. |
| zIndex | string | Computed effective z-index as a string ("0" when auto / not stacked). |
| hittableWhileInvisible | boolean | True when the blocker intercepts clicks even while invisible (computed pointer-events in {all, painted, fill, stroke}): a real click is swallowed even at visibility:hidden / opacity:0. When false and the element is invisible, a real click would fall through. |
| position | string | Computed position keyword. "fixed"/"sticky" means the blocker is pinned (by itself or an ancestor) and stays put no matter where the pointer goes — clear it by scrolling the target out from under it; ordinary overlays often collapse once the pointer leaves. |
PageInfo
interfacePageInfo describes an open page (tab or popup) inside a browser context.
ReactionInfo
interfaceReactionInfo describes a still-pending reaction, as returned by CloudBrowser.listReactions. One-shot reactions that have already fired are gone and never appear here.
| reactionId | string | Stable id assigned by CloudBrowser.addReaction (pass to removeReaction). |
| matchSelector | string | Set if the reaction matches by CSS selector. |
| matchJsExpression | string | Set if the reaction matches by JS expression. |
| actionSelector | string | Set if the click target differs from the matched element. |
| actionJsExpression | string | Set if the click target differs from the matched element. |
| frameId | string | Frame scope: "" for the main frame, a specific frameId, or AllFrames. |
| visible | boolean | Whether the match additionally requires the element to be visible. |
ReactionOpts
interfaceOptional customization for CloudBrowser.addReaction. All fields are optional; missing or zero values mean "use the server default".
| on? | Locator | Override the click target. Omit to click the matched element itself. Provide a css()/js() Locator to click a different element, resolved in the matched element's frame (e.g. a modal's close "X"). node()/at() locators are rejected. |
| button? | Button | Mouse button for the click. Default "left". |
| clickCount? | number | 1 = single click (default), 2 = double-click. |
| intervalMs? | number | Poll cadence in milliseconds for the shared page loop. Default 300. |
ReadCanvasOpts
interfaceOptional customization for CloudBrowser.readCanvas.
| inFrame? | string | Override the locator's frame. Omit to use the locator's own Locator.inFrame (or the main frame). Pass a specific frameId or AllFrames to search elsewhere. |
| format? | "png" | "jpeg" | "webp" | "rgba" | Output encoding: "png" (default), "jpeg", "webp", or "rgba" for the raw unpremultiplied RGBA pixel buffer. |
| quality? | number | Encode quality 0-100 for "jpeg"/"webp" (ignored otherwise). Default 90. |
| sx? | number | Optional sub-rectangle in canvas pixels (mirrors getImageData(sx, sy, sw, sh)). The full canvas is read when sw/sh are omitted or <= 0. |
| sy? | number | |
| sw? | number | |
| sh? | number |
ReadCanvasResult
interfaceReadCanvasResult is the pixel readback of a <canvas>, returned by CloudBrowser.readCanvas. dataBase64 holds the encoded image bytes (PNG by default) or the raw RGBA buffer when format is "rgba". originClean reports whether the canvas was untainted (informational — the read succeeds either way).
| success | boolean | |
| frameId | string | |
| backendNodeId | number | |
| dataBase64 | string | |
| width | number | |
| height | number | |
| originClean | boolean |
Rect
interfaceRect describes a position and size in CSS pixels.
| x | number | |
| y | number | |
| width | number | |
| height | number |
RentResponse
interfaceRentResponse is the result of renting a browser via the REST API.
| sessionId | string | |
| grpcUrl | string | |
| countryCode | string | |
| timezone | string | |
| acceptLanguage | string | |
| fingerprint | string |
RequestPattern
interfaceRequestPattern matches a URL pattern in waitForAnyRequest/Response. Set abort to true to drop the request with an empty 200 response instead of letting it through to the network.
| url | string | |
| abort? | boolean | Default false. |
ScreenshotOpts
interfaceOptional customization for CloudBrowser.screenshot.
| format? | "png" | "jpeg" | "webp" | Image format: "png" (default), "jpeg", or "webp". |
| quality? | number | Encode quality 0-100 for "jpeg"/"webp" (ignored for "png"). Default 90. |
ScreenshotResult
interfaceScreenshotResult is a single captured image of the page, returned by CloudBrowser.screenshot. dataBase64 holds the encoded image bytes (PNG by default); width and height are in physical pixels.
| dataBase64 | string | |
| width | number | |
| height | number |
ScrollError
classScrollError is thrown by CloudBrowser.scrollTo when the target could not be located/scrolled.
| code | string | Currently always "not_found". |
| result | ElementResult |
SelectOptionError
classSelectOptionError is thrown by the CloudBrowser.selectByIndex / selectByValue / selectByText calls when the option could not be selected. selectOption is programmatic (no pointer gate), so it only reports semantic failures.
| code | string | "not_found" (the <select> was not located) or "option_not_found" (no option matched the requested index/value/text). |
| result | SelectOptionResult |
SelectOptionResult
interfaceSelectOptionResult reports which option a selectByXxx call ended up selecting.
| selectedIndex | number | |
| selectedValue | string | |
| selectedText | string |
SelectOpts
interfaceOptional customization for CloudBrowser.selectByIndex, CloudBrowser.selectByValue and CloudBrowser.selectByText.
| inFrame? | string | Override the locator's frame. Omit to use the locator's own Locator.inFrame (or the main frame). Pass a specific frameId or AllFrames to search elsewhere. |
| fireEvents? | boolean | false suppresses change/input events. Default (true) fires the standard events after the selection. |
StorageItem
interfaceStorageItem is a single localStorage key/value pair.
| key | string | |
| value | string |
StorageOriginEntry
interfaceStorageOriginEntry groups the localStorage entries of one origin (e.g. "https://example.com"). getStorage() returns these and setStorage() accepts the same shape, so a dump can be fed back verbatim.
| origin | string | |
| items | StorageItem[] |
WaitConditionStatus
interfaceWaitConditionStatus is the per-condition diagnostic carried by WaitError when a CloudBrowser.wait times out: one entry per condition (in the order they were passed) explaining why it never matched.
| index | number | Index into the condition list this entry describes. |
| state | string | Last observed state: "not_found", "found_hidden", "found_occluded" (only when the condition required visibility), or "pending_steady". |
| backendNodeId | number | backendNodeId last seen for this condition (0 if never found). |
| frameId | string | frameId where it was last seen (empty if never found). |
| isVisible | boolean | Whether it was CSS-visible at the last observation. |
| bounds? | Rect | Last known rect in root-viewport coordinates (undefined if never found). |
| occluder? | OccluderInfo | The intercepting element, present iff state === "found_occluded". |
WaitError
classWaitError is thrown by CloudBrowser.wait / CloudBrowser.waitAny when no condition matched before the deadline. conditions holds the per-condition breakdown (same order/length as the conditions passed in) explaining why each one never matched.
| code | string | Machine-stable failure code, currently always "timeout". |
| conditions | WaitConditionStatus[] | Per-condition status, same order/length as the conditions passed to wait. |
| result | WaitResult | The partial wait result (index is -1 on timeout). |
WaitOpts
interfaceOptional customization for CloudBrowser.wait / CloudBrowser.waitForAny.
| timeoutMs? | number | Default DefaultWaitTimeoutMs (30 000 ms). |
WaitResult
interfaceWaitResult is the outcome of a CloudBrowser.wait / CloudBrowser.waitForAny call: which condition matched (index, in argument order) and where the matched element lives.
| index | number | |
| frameId | string | |
| backendNodeId | number | |
| isVisible | boolean | |
| bounds | Rect |
WaitUntil
type aliastype WaitUntil = "load" | "domcontentloaded" | "networkidle"Lifecycle event CloudBrowser.navigate waits for before returning.