TypeScript SDK Reference
wrc-ts. All methods return a Promise; the return types below show the resolved value (the Promise<…> wrapping is implicit).addHeader
functionaddHeader(name: string, value: string): HeaderModificationBuilderBuilds a HeaderModification that adds a new request header.
Chain .beforeHeader(name) / .afterHeader(name) on the returned builder to control where the header is inserted; otherwise it is appended at the end.
| name | string | header name |
| value | string | header value |
const mod = addHeader("X-Trace", "abc123");
await browser.modifyRequest("*\/api/me", { modifications: [mod] });HeaderModificationBuilderchainable HeaderModificationBuilder ready to pass to CloudBrowser.modifyRequestafterHeader
method on HeaderModificationBuilderafterHeader(name: string): HeaderModificationBuilderPositions an "add" modification immediately after the named existing header.
Mirror of beforeHeader; only affects "add" modifications.
| name | string | anchor header name to insert after |
const mod = addHeader("X-Trace", "abc").afterHeader("User-Agent");HeaderModificationBuilderthis builder for chainingat
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 targetbeforeHeader
method on HeaderModificationBuilderbeforeHeader(name: string): HeaderModificationBuilderPositions an "add" modification immediately before the named existing header.
Only affects "add" modifications; ignored for edit/remove.
| name | string | anchor header name to insert before |
const mod = addHeader("X-Trace", "abc").beforeHeader("Cookie");HeaderModificationBuilderthis builder for chainingclearCookies
method on CloudBrowserclearCookies(): voidDeletes every cookie in the browser context.
await browser.clearCookies();void| UNKNOWN_ERROR | the cookies 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 |
await browser.click(css("button.submit"));// 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| CLICK_FAILED | the click could not be dispatched |
| ELEMENT_NOT_FOUND | no element matched the locator |
| FRAME_NOT_FOUND | the requested frame does not exist |
| INVALID_LOCATOR | target is empty or has multiple targets set |
| PAGE_NOT_ALIVE | the page has been closed |
| TIMEOUT | the operation exceeded the server-side timeout |
createBrowserClient
functioncreateBrowserClient(grpcWebUrl: string, sessionId: string, apiKey: string, fingerprint: string): CloudBrowserAttaches a CloudBrowser to an existing session over gRPC-Web.
Use this from a browser context that has a gRPC-Web proxy in front of the WRC 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.
| grpcWebUrl | string | base URL of the gRPC-Web proxy |
| 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 = createBrowserClient(
"https://wrc.example.com/grpc-web",
sessionId,
apiKey,
);
await browser.navigate("https://example.com");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.
Preferred over createBrowserClient in environments where a gRPC-Web proxy is not available; the WebSocket transport framing is defined by WebSocketTransport and is served directly by the WRC session host. Same rental semantics as createBrowserClient.
| 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.wrc.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 targetdragBy
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| UNKNOWN_ERROR | the drag could not be performed |
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| UNKNOWN_ERROR | the drag could not be performed |
editHeader
functioneditHeader(name: string, value: string): HeaderModificationBuilds a HeaderModification that replaces an existing header's value.
Only useful when the request already carries the header — use addHeader to introduce a new header.
| name | string | header name to overwrite |
| value | string | new value |
await browser.modifyRequest("*\/api", {
modifications: [editHeader("User-Agent", "MyAgent/1.0")],
});HeaderModificationHeaderModification ready to pass to CloudBrowser.modifyRequestevaluate
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, clears its content, then types text into it.
The browser scrolls the element into view, moves the cursor along a human-like path, clicks to focus, optionally clears existing content (Ctrl+A, Delete), then types the text character-by-character with QWERTZ keyboard simulation and human-like timing.
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");// Append to existing content instead of clearing first.
await browser.fill(css("textarea"), " — appended", { noClear: true });ElementResultElementResult with success, resolved frameId, backendNodeId and the root-viewport (rootX, rootY) where the element was clicked| ELEMENT_NOT_FOUND | no element matched the locator |
| FILL_FAILED | the input could not be filled |
| FRAME_NOT_FOUND | the requested frame does not exist |
| INVALID_LOCATOR | target is empty or has multiple targets set |
| PAGE_NOT_ALIVE | the page has been closed |
| TIMEOUT | the operation exceeded the server-side timeout |
getApiKey
method on CloudBrowsergetApiKey(): stringReturns the API key used to rent this session.
stringgetCookies
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): ObservationResultReturns a compact, agent-friendly description of every interactable element currently visible on the page, together with a truncated view of the surrounding text.
Intended as input for LLM/agent loops where a full DOM dump would be too large; the server filters down to elements that are actually visible and interactable.
| opts | GetObservationOpts | undefined | optional caps: maxElementsPerFrame, maxTextLength; omit either to use the server default |
const obs = await browser.getObservation({ maxElementsPerFrame: 200 });
console.log(obs.text);ObservationResultObservationResult with both a human-readable text rendering and a json payload of the structured observation| 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.
stringhighlightNode
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 |
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 frameinsertText
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 |
js
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 targetloadHTML
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. Use addHeader / editHeader / removeHeader to build the modifications inline.
| 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: [addHeader("X-Trace", "abc123")],
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| UNKNOWN_ERROR | the move could not be completed |
node
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 targetpressKey
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 |
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 |
removeHeader
functionremoveHeader(name: string): HeaderModificationBuilds a HeaderModification that drops a header from the request.
| name | string | header name to remove |
await browser.modifyRequest("*\/api", {
modifications: [removeHeader("Cookie")],
});HeaderModificationHeaderModification ready to pass to CloudBrowser.modifyRequestrentBrowser
functionrentBrowser(config: BrowserConfig): CloudBrowserRents a new browser session and returns a connected handle.
Calls the WRC 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 |
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| UNKNOWN_ERROR | the element could not be scrolled into view |
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| ELEMENT_NOT_FOUND | no element matched the locator |
| FRAME_NOT_FOUND | the requested frame does not exist |
| INVALID_LOCATOR | target is empty or has multiple targets set |
| PAGE_NOT_ALIVE | the page has been closed |
| SELECT_FAILED | the option could not be selected (out of range, or element is not a `<select>`) |
| TIMEOUT | the operation exceeded the server-side timeout |
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| ELEMENT_NOT_FOUND | no element matched the locator |
| FRAME_NOT_FOUND | the requested frame does not exist |
| INVALID_LOCATOR | target is empty or has multiple targets set |
| PAGE_NOT_ALIVE | the page has been closed |
| SELECT_FAILED | the option could not be selected (out of range, or element is not a `<select>`) |
| TIMEOUT | the operation exceeded the server-side timeout |
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| ELEMENT_NOT_FOUND | no element matched the locator |
| FRAME_NOT_FOUND | the requested frame does not exist |
| INVALID_LOCATOR | target is empty or has multiple targets set |
| PAGE_NOT_ALIVE | the page has been closed |
| SELECT_FAILED | the option could not be selected (out of range, or element is not a `<select>`) |
| TIMEOUT | the operation exceeded the server-side timeout |
setApiEndpoint
functionsetApiEndpoint(endpoint: string): voidOverrides the HTTP rent/stop endpoint.
Defaults to http://wrc-beta.xyz:8004. Call this before any rentBrowser / stopBrowser call if you need to point at a private WRC deployment.
| endpoint | string | base URL of the rent/stop service, with no trailing slash |
setApiEndpoint("https://wrc.internal.example.com");voidsetBlockList
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 |
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 |
steady
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 appliedstopBrowser
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 |
visible
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 appliedwait
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| UNKNOWN_ERROR | the wait timed out or a condition was invalid |
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| UNKNOWN_ERROR | the wait timed out or a condition was invalid |
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 |
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 chainingwithRenderer
method on BrowserConfigwithRenderer(enabled: boolean): BrowserConfigToggles the WebRTC live-render stream for the session.
Disabled by default. Enable when you need a live-UI experience (the user_frontend stream, screenshots, etc.); disable in pure-automation scenarios to save backend resources.
| enabled | boolean | true to enable the WebRTC renderer, false to disable |
new BrowserConfig(apiKey, 600, "", 0, "", "").withRenderer(true);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 chaining