Go SDK Reference

Module github.com/browserscale/browserscale-go. Every method takes ctx context.Context as its first argument and returns an explicit error; both are omitted from the signatures below for brevity.
type

CloudBrowser

84 methods

CloudBrowser is the SDK-side handle for an active browserscale browser session.

One CloudBrowser corresponds to exactly one browser context, and its commands act on that context's primary page.

AcceptLanguage

method on CloudBrowser
AcceptLanguage() → string

AcceptLanguage returns the Accept-Language header value the session was provisioned with.

Returns
string

AddReaction

method on CloudBrowser
AddReaction(match *Locator) → string

AddReaction registers a one-shot "reaction": the browser watches for the match locator in the background and, as soon as it matches, clicks it the same way CloudBrowser.Click does (scroll, human path, occlusion check) — then removes itself. The reaction 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 and At are rejected. Use Locator.InAllFrames to watch every frame and Locator.Visible(false) to opt out of the default visibility gate.

Parameters
match*Locatorthe CSS/JS locator to watch for
// Auto-dismiss a consent button whenever it appears, in any frame.
id, err := browser.AddReaction(ctx, browserscale.CSS("button#accept").InAllFrames())
if err != nil {
    log.Fatal(err)
}
_ = id
Returns
stringthe reactionId (pass to CloudBrowser.RemoveReaction)
SeeCloudBrowser.AddReactionWith for a different click target, button,

AddReactionWith

method on CloudBrowserinherits AddReaction
AddReactionWith(match *Locator, opts ReactionOpts) → string

AddReactionWith is the customizable variant of CloudBrowser.AddReaction.

match must be a CSS or JS Locator — Node and At are rejected. Use Locator.InAllFrames to watch every frame and Locator.Visible(false) to opt out of the default visibility gate.

Parameters
match*Locatorthe CSS/JS locator to watch for
optsReactionOptsreaction customization; see ReactionOpts
// Watch for a newsletter modal, but click its close "X" instead.
id, err := browser.AddReactionWith(ctx,
    browserscale.CSS("#newsletter-modal"),
    browserscale.ReactionOpts{On: browserscale.CSS(".modal-close")},
)
Returns
stringthe reactionId (pass to CloudBrowser.RemoveReaction)
SeeCloudBrowser.AddReactionWith for a different click target, button,

ApiKey

method on CloudBrowser
ApiKey() → string

ApiKey returns the API key used to rent this session.

Returns
string

CaptureNetwork

method on CloudBrowser
CaptureNetwork(opts NetworkCaptureOptions, onExchange NetworkExchangeHandler) → *NetworkCapture

CaptureNetwork starts capturing the session's network traffic and returns a live view of it.

Every request matching opts.Patterns is reported once it completes, and "every request" is literal: capture sits in the browser process rather than in a page, so cross-process iframes, workers and service workers are included, the headers are the ones actually put on the wire (Cookie and Sec-* included), and each hop of a redirect chain arrives as its own exchange. Requests are never paused, so the page loads at full speed.

This call returns as soon as the capture is running; onExchange then fires in the background while you drive the browser. The capture is armed only after the subscription exists, so nothing that happens after this call returns is missed. Call NetworkCapture.Stop when done — it disarms the capture server-side, which a cancelled context alone does not.

Parameters
optsNetworkCaptureOptionswhich requests to capture and whether to keep bodies
onExchangeNetworkExchangeHandlercalled per exchange; see NetworkExchangeHandler for the
capture, err := browser.CaptureNetwork(ctx, browserscale.NetworkCaptureOptions{
    Patterns: []string{"*/api/*"},
    Bodies:   browserscale.NetworkBodiesText,
}, func(ex browserscale.NetworkExchange) {
    fmt.Println(ex.StatusCode, ex.Method, ex.Url)
})
if err != nil {
    log.Fatal(err)
}
defer capture.Stop(ctx)

_, _ = browser.Navigate(ctx, "https://example.com", 0)
Returns
*NetworkCapture*NetworkCapture handle for stopping the capture and inspecting how

ClearCookies

method on CloudBrowser
ClearCookies()

ClearCookies deletes every cookie in the browser context.

Reports only transport failures - a dead session, a page that is gone, a broken connection. This call has no semantic failure of its own, so there are no error codes to branch on.

_ = browser.ClearCookies(ctx)

ClearStorage

method on CloudBrowser
ClearStorage(origin string)

ClearStorage deletes localStorage in the browser context.

Parameters
originstringif non-empty, only this origin's storage is deleted (e.g. "https://example.com"); empty string deletes all origins
// Wipe one origin.
_ = browser.ClearStorage(ctx, "https://example.com")

// Wipe everything.
_ = browser.ClearStorage(ctx, "")

Click

method on CloudBrowser
Click(target *Locator) → *ElementResult

Click triggers a single left mouse click on the given target.

The element does not have to be ready when you call this. For up to 5s the browser keeps re-locating it, scrolls it into view, waits for its bounds to hold still for 750ms, and hit-tests the exact point it is about to press — so a plain Click also does the work of a preceding CloudBrowser.Wait, and needs no retry loop of your own. If the element never settles within that budget the click is attempted at the deadline rather than abandoned.

If something covers the target, the pointer is repositioned once to an exposed part of it, which also gives hover-triggered overlays a chance to collapse. Only if the target is still covered afterwards does the click refuse — it never presses whatever happens to lie on top.

The cursor then moves along a human-like path rather than jumping, and a full mouseDown+mouseUp is dispatched at a randomized point inside the element's bounding rect.

Parameters
target*Locatorlocator describing what to click; At is also valid
res, err := browser.Click(ctx, browserscale.CSS("button.submit"))
if err != nil {
    var ce *browserscale.ClickError
    if errors.As(err, &ce) {
        log.Printf("blocked by %s (%s)", ce.Occluder.TagName, ce.Code)
    }
    log.Fatal(err)
}
Returns
*ElementResult*ElementResult with success, resolved frameId, backendNodeId,
SeeClickError for the occlusion-failure detail · CloudBrowser.ClickWith for right-click, double-click,

ClickWith

method on CloudBrowserinherits Click
ClickWith(target *Locator, opts ClickOpts) → *ElementResult

ClickWith is the customizable variant of CloudBrowser.Click.

The element does not have to be ready when you call this. For up to 5s the browser keeps re-locating it, scrolls it into view, waits for its bounds to hold still for 750ms, and hit-tests the exact point it is about to press — so a plain Click also does the work of a preceding CloudBrowser.Wait, and needs no retry loop of your own. If the element never settles within that budget the click is attempted at the deadline rather than abandoned.

If something covers the target, the pointer is repositioned once to an exposed part of it, which also gives hover-triggered overlays a chance to collapse. Only if the target is still covered afterwards does the click refuse — it never presses whatever happens to lie on top.

The cursor then moves along a human-like path rather than jumping, and a full mouseDown+mouseUp is dispatched at a randomized point inside the element's bounding rect.

Parameters
target*Locatorlocator describing what to click; At is also valid
optsClickOptsclick customization; see ClickOpts
// Right double-click on a context menu trigger.
_, err := browser.ClickWith(ctx, browserscale.CSS("li.menu"), browserscale.ClickOpts{
    Button:     "right",
    ClickCount: 2,
})
Returns
*ElementResult*ElementResult with success, resolved frameId, backendNodeId,
SeeClickError for the occlusion-failure detail · CloudBrowser.ClickWith for right-click, double-click,

Close

method on CloudBrowser
Close()

Close is the defer-friendly form of CloudBrowser.StopBrowser: it uses a background context and drops the final usage. Call StopBrowser instead when you want the usage.

Reports a plain error when the stop API or the connection close fails. The session is released either way; retrying a stop is safe.

browser, err := browserscale.RentBrowser(ctx, cfg)
if err != nil { log.Fatal(err) }
defer browser.Close()

CloseConn

method on CloudBrowser
CloseConn()

CloseConn closes only the gRPC connection, leaving the server-side session running.

Use this to detach without releasing the rental — the common case when you attached with ConnectSession to act on a session owned elsewhere, or when a short-lived handle should not outlive its work but the session must. Contrast with CloudBrowser.Close / CloudBrowser.StopBrowser, which also release the rental via the stop endpoint.

Reports a plain error when the connection cannot be closed cleanly. The local handle is unusable afterwards regardless.

browser, err := browserscale.ConnectSession(ctx, grpcUrl, apiKey, sessionId)
if err != nil { log.Fatal(err) }
defer browser.CloseConn() // detach; the session keeps running

CountryCode

method on CloudBrowser
CountryCode() → string

CountryCode returns the ISO-3166 country code the server allocated for this session (drives geo-IP and locale defaults).

Returns
string

DragBy

method on CloudBrowser
DragBy(target *Locator, offsetX float64, offsetY float64) → *DragResult

DragBy picks up the target and drops it at an offset relative to the pickup point.

The source is acquired with the same smart click as CloudBrowser.Click — re-located, scrolled into view, settled and hit-tested — so the handle does not have to be ready when you call this. The browser then presses the left mouse button at a point inside the element, drags along a human-like path to (pickupX+offsetX, pickupY+offsetY), and releases. At is not a valid target — drag needs a real element.

Parameters
target*Locatorlocator describing the element to pick up
offsetXfloat64horizontal distance to drag, in CSS pixels
offsetYfloat64vertical distance to drag, in CSS pixels
_, err := browser.DragBy(ctx, browserscale.CSS(".slider .handle"), 120, 0)
if err != nil {
    log.Fatal(err)
}
Returns
*DragResult*DragResult with the resolved frameId, backendNodeId and the
SeeDragError for the occlusion-failure detail

DragTo

method on CloudBrowser
DragTo(target *Locator, absoluteX float64, absoluteY float64) → *DragResult

DragTo picks up the target and drops it at absolute root-viewport coordinates.

Same gesture and same source acquisition as CloudBrowser.DragBy, but the drop destination is in page coordinates rather than relative to the pickup point.

Parameters
target*Locatorlocator describing the element to pick up
absoluteXfloat64horizontal drop coordinate in the root viewport
absoluteYfloat64vertical drop coordinate in the root viewport
_, err := browser.DragTo(ctx, browserscale.CSS(".card"), 800, 400)
if err != nil {
    log.Fatal(err)
}
Returns
*DragResult*DragResult with the resolved frameId, backendNodeId and the
SeeDragError for the occlusion-failure detail

Evaluate

method on CloudBrowser
Evaluate(expression string) → *EvaluateResult

Evaluate runs a JavaScript expression in the page's main frame.

The expression's return value is JSON-serialized server-side and parsed eagerly into EvaluateResult.Value. When the expression returns a DOM element the EvaluateResult.Value is left empty and the element metadata (BackendNodeId, IsVisible, Bounds) is populated instead — use Node(id) in subsequent calls to act on it.

A falsy answer and a broken expression are different outcomes. Returning null, false or undefined is a successful evaluation and comes back as a result; an expression that throws or will not compile comes back as a *CommandError, so a typo can never read as "the page says null".

Parameters
expressionstringJavaScript expression evaluated in the main frame
res, err := browser.Evaluate(ctx, "document.title")
if err != nil {
    log.Fatal(err)
}
fmt.Println(res.Value)
// Telling a false answer from a broken expression.
res, err := browser.Evaluate(ctx, "window.__ready === true")
var ce *browserscale.CommandError
if errors.As(err, &ce) {
    log.Fatalf("expression is broken: %v", ce)
}
if res.Value != true {
    // legitimately not ready yet
}
Returns
*EvaluateResult*EvaluateResult with either Value (for non-Element returns) or
SeeCommandError for recovering the code with errors.As

EvaluateInFrame

method on CloudBrowserinherits Evaluate
EvaluateInFrame(frameId string, expression string) → *EvaluateResult

EvaluateInFrame runs a JavaScript expression in the given frame.

Same semantics as CloudBrowser.Evaluate but targets a specific frame instead of the main frame. Useful for evaluating inside OOPIFs (out-of- process iframes) found via CloudBrowser.GetPages.

Parameters
frameIdstringid of the frame to evaluate in; empty falls back to the main frame
expressionstringJavaScript expression evaluated in the main frame
pages, _ := browser.GetPages(ctx)
iframeId := pages[0].FrameTree.Children[0].FrameId
_, _ = browser.EvaluateInFrame(ctx, iframeId, "location.href")
Returns
*EvaluateResult*EvaluateResult with either Value (for non-Element returns) or
SeeCommandError for recovering the code with errors.As

Fill

method on CloudBrowser
Fill(target *Locator, text string) → *ElementResult

Fill clicks the target and types text into it, appending to any existing content.

The field is acquired with the same smart click as CloudBrowser.Click: re-located, scrolled into view, settled and hit-tested within the timeout budget, so it does not have to be present or ready yet. The cursor then moves along a human-like path and clicks to focus.

Typing is per-key rather than a value assignment: keyDown, char and keyUp for every character, with the keycodes of the layout that matches the session's region and human cadence between them. If the field already holds text the caret is moved to the end first, so appended input lands after the existing content instead of wherever the caret happened to sit.

Fill is strictly target-bound. If something else takes focus mid-typing, the remaining characters are never typed into the thief — the browser tries to re-focus the target and otherwise fails with "focus_stolen", naming the element that holds focus instead so you can deal with it (a consent button, a different field). For stream-style typing that is *supposed* to move between fields, such as an OTP input that auto-advances, use CloudBrowser.Type instead.

To overwrite the field instead of appending, use CloudBrowser.FillWith with ClearFirst: true.

At is not a valid target — Fill requires an actual element.

Parameters
target*Locatorlocator describing the input element
textstringtext to type into the element
res, err := browser.Fill(ctx, browserscale.CSS("input[name=email]"), "user@example.com")
if err != nil {
    var fe *browserscale.FillError
    if errors.As(err, &fe) && fe.ClickError != nil {
        log.Printf("blocked by %s", fe.ClickError.Occluder.TagName)
    }
    log.Fatal(err)
}
_ = res
Returns
*ElementResult*ElementResult with success, resolved frameId, backendNodeId
SeeCloudBrowser.FillWith for clearing existing content or · FillError for the focus-failure detail

FillWith

method on CloudBrowserinherits Fill
FillWith(target *Locator, text string, opts FillOpts) → *ElementResult

FillWith is the customizable variant of CloudBrowser.Fill.

The field is acquired with the same smart click as CloudBrowser.Click: re-located, scrolled into view, settled and hit-tested within the timeout budget, so it does not have to be present or ready yet. The cursor then moves along a human-like path and clicks to focus.

Typing is per-key rather than a value assignment: keyDown, char and keyUp for every character, with the keycodes of the layout that matches the session's region and human cadence between them. If the field already holds text the caret is moved to the end first, so appended input lands after the existing content instead of wherever the caret happened to sit.

Fill is strictly target-bound. If something else takes focus mid-typing, the remaining characters are never typed into the thief — the browser tries to re-focus the target and otherwise fails with "focus_stolen", naming the element that holds focus instead so you can deal with it (a consent button, a different field). For stream-style typing that is *supposed* to move between fields, such as an OTP input that auto-advances, use CloudBrowser.Type instead.

To overwrite the field instead of appending, use CloudBrowser.FillWith with ClearFirst: true.

At is not a valid target — Fill requires an actual element.

Parameters
target*Locatorlocator describing the input element
textstringtext to type into the element
optsFillOptsfill customization; see FillOpts
// Wipe the field first, then type fresh content.
_, err := browser.FillWith(ctx, browserscale.CSS("input[name=email]"), "user@example.com", browserscale.FillOpts{
    ClearFirst: true,
})
Returns
*ElementResult*ElementResult with success, resolved frameId, backendNodeId
SeeCloudBrowser.FillWith for clearing existing content or · FillError for the focus-failure detail

Fingerprint

method on CloudBrowser
Fingerprint() → string

Fingerprint returns the browser fingerprint id in use for this session.

Returns
string

FollowScript

method on CloudBrowser
FollowScript(runId string, onEvent ScriptEventHandler) → *ScriptFollow

FollowScript watches script output in a session without starting anything.

For the case CloudBrowser.StartScript cannot cover: a run somebody else launched, or one this process started before it restarted. Several readers can watch the same session, each with its own buffer.

Only output produced from now on arrives — lines printed before the subscription existed are not kept. A run that has already finished is therefore invisible here; CloudBrowser.ListScriptRuns is how you tell that apart from a run that is merely quiet.

Parameters
runIdstringrun to follow, or "" to follow every run in the session
onEventScriptEventHandlercalled per event; see ScriptEventHandler for the ordering
follow, err := browser.FollowScript(ctx, runId, func(ev browserscale.ScriptEvent) {
    if ev.Log != nil { fmt.Println(ev.Log.Message) }
})
if err != nil { log.Fatal(err) }
defer follow.Stop()
Returns
*ScriptFollow*ScriptFollow handle for stopping the subscription

GetAuthSession

method on CloudBrowser
GetAuthSession() → *AuthSession

GetAuthSession exports the signed-in primary account and DBSC sessions of this browser context. Reads state in the browser process — no page needed.

Returns nil, nil when the context has neither a signed-in account nor DBSC sessions.

auth, err := browser.GetAuthSession(ctx)
if err != nil {
    log.Fatal(err)
}
if auth == nil {
    log.Println("no auth/DBSC state")
    return
}
// persist auth, then later SetAuthSession on a fresh rent
Returns
*AuthSession*AuthSession, or nil when there is nothing to export

GetCookies

method on CloudBrowser
GetCookies() → []CookieParam

GetCookies returns all cookies currently stored in this session's browser context.

cookies, err := browser.GetCookies(ctx)
if err != nil {
    log.Fatal(err)
}
for _, c := range cookies {
    fmt.Println(c.Name, "=", c.Value)
}
Returns
[]CookieParam[]CookieParam, one per cookie in the context

GetDOM

method on CloudBrowser
GetDOM(frameId string, depth int32) → string

GetDOM returns a JSON string 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 CloudBrowser.GetObservation instead.

Parameters
frameIdstringid of the frame to dump; empty targets the main frame
depthint32tree depth: -1 for the full tree, 0 for root only, N for
tree, err := browser.GetDOM(ctx, "", -1)
if err != nil {
    log.Fatal(err)
}
fmt.Println(tree)
Returns
stringJSON string in CDP DOM.Node shape

GetDomChildren

method on CloudBrowser
GetDomChildren(backendNodeId int32, frameId string, depth int32) → *DomChildren

GetDomChildren fetches a node's children and starts reporting changes inside them. DomMirror.Expand calls this and folds the result into the tree.

On an <iframe>/<frame>/<object> the one child is the document it hosts, and this call is what starts mirroring that frame.

Parameters
backendNodeIdint32the node to open
frameIdstringthe frame its id belongs to; empty targets the main frame
depthint32levels below the node; 0 uses the server default of 1
Returns
*DomChildren*DomChildren with the child list as JSON and the sequence it is
SeeCommandError for recovering the code with errors.As

GetDOMHash

method on CloudBrowser
GetDOMHash(frameId string) → string

GetDOMHash returns 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 CloudBrowser.GetDOM only when the hash differs from your last snapshot.

Parameters
frameIdstringid of the frame to hash; empty targets the main frame
hash, err := browser.GetDOMHash(ctx, "")
if err != nil {
    log.Fatal(err)
}
if hash != lastHash {
    // DOM changed → re-fetch
}
Returns
string16-char hex string (the first 8 bytes of sha256 of the DOM JSON)

GetDomRevision

method on CloudBrowser
GetDomRevision(frameId string) → uint64

GetDomRevision returns a frame's mutation counter, incremented on every change the document sees. O(1) in the browser and the change detector to poll if you are not consuming mirror events.

Prefer it over CloudBrowser.GetDOMHash, which serializes the whole tree just to hash it. The two answer different questions: a hash compares content, a revision only says whether this document moved since you last asked. The counter is meaningful only within the current document.

Parameters
frameIdstringthe frame to ask; empty targets the main frame
Returns
uint64uint64 monotonic counter

GetObservation

method on CloudBrowser
GetObservation() → string

GetObservation returns 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 CloudBrowser.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.

obs, err := browser.GetObservation(ctx)
if err != nil {
    log.Fatal(err)
}
fmt.Println(obs)
Returns
stringthe observation in the requested format, ready to hand to a model
SeeCommandError for recovering the code with errors.As

GetObservationWith

method on CloudBrowserinherits GetObservation
GetObservationWith(opts ObservationOpts) → string

GetObservationWith is the customizable variant of CloudBrowser.GetObservation.

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 CloudBrowser.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.

Parameters
optsObservationOptsobservation customization; see ObservationOpts
// Only what is on screen right now, as structured JSON.
obs, err := browser.GetObservationWith(ctx, browserscale.ObservationOpts{
    Format:       "json",
    ViewportOnly: true,
})

// Re-read just one form after the first full look.
obs, err = browser.GetObservationWith(ctx, browserscale.ObservationOpts{
    Selector: "form#register",
})
Returns
stringthe observation in the requested format, ready to hand to a model
SeeCommandError for recovering the code with errors.As

GetPages

method on CloudBrowser
GetPages() → []*PageInfo

GetPages 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).

pages, err := browser.GetPages(ctx)
if err != nil {
    log.Fatal(err)
}
for _, p := range pages {
    fmt.Println(p.Url, p.Title)
}
Returns
[]*PageInfo[]*PageInfo for every page currently open in the context

GetSelection

method on CloudBrowser
GetSelection() → string

GetSelection returns 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.

sel, err := browser.GetSelection(ctx)
if err != nil {
    log.Fatal(err)
}
fmt.Println("user selected:", sel)
Returns
stringthe selected text, or "" when nothing is selected

GetStorage

method on CloudBrowser
GetStorage(origin string) → []StorageOriginEntry

GetStorage 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.

Parameters
originstringif non-empty, only this origin is returned (e.g. "https://example.com"); empty string returns all origins
storage, err := browser.GetStorage(ctx, "")
if err != nil {
    log.Fatal(err)
}
for _, e := range storage {
    for _, item := range e.Items {
        fmt.Println(e.Origin, item.Key, "=", item.Value)
    }
}
Returns
[]StorageOriginEntry[]StorageOriginEntry, one per origin with localStorage data

GetStreamConfig

method on CloudBrowser
GetStreamConfig() → []IceServer

GetStreamConfig 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 CloudBrowser.StartStream and apply the returned answer.

ice, err := browser.GetStreamConfig(ctx)
if err != nil { log.Fatal(err) }
// configure your RTCPeerConnection with ice, then create an offer …
Returns
[]IceServerthe ICE servers for the client RTCPeerConnection

GetUsage

method on CloudBrowser
GetUsage() → *SessionUsage

GetUsage reports what this session's browser has consumed so far.

Everything but MinMemory and AverageMemory only ever grows, so polling and diffing two readings gives the cost of what ran in between. The final figures need no call of their own: CloudBrowser.StopBrowser returns them.

before, _ := browser.GetUsage(ctx)
_, _ = browser.Navigate(ctx, "https://example.com", 0)
after, _ := browser.GetUsage(ctx)
fmt.Printf("navigation cost %.2fs of CPU\n", after.CpuTime-before.CpuTime)
Returns
*SessionUsage*SessionUsage as of now

GrpcUrl

method on CloudBrowser
GrpcUrl() → string

GrpcUrl returns the gRPC endpoint the session is connected to.

Returns
string

HighlightNode

method on CloudBrowser
HighlightNode(backendNodeId int32, frameId string)

HighlightNode paints 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.

Parameters
backendNodeIdint32id of the node to highlight, or <= 0 to clear
frameIdstringid of the frame the node lives in; empty targets the main frame
if err := browser.HighlightNode(ctx, res.BackendNodeId, res.FrameId); err != nil {
    log.Fatal(err)
}

InsertText

method on CloudBrowser
InsertText(text string)

InsertText pastes 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 CloudBrowser.Click or CloudBrowser.Fill first if you need a specific element to be focused.

Parameters
textstringthe text to insert at the caret
if err := browser.InsertText(ctx, "hello world"); err != nil {
    log.Fatal(err)
}
SeeCommandError for recovering the code with errors.As

InspectAtPosition

method on CloudBrowser
InspectAtPosition(x float64, y float64) → *InspectResult

InspectAtPosition hit-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.

Parameters
xfloat64viewport-relative x in CSS pixels
yfloat64viewport-relative y in CSS pixels
res, err := browser.InspectAtPosition(ctx, 200, 300)
if err != nil {
    log.Fatal(err)
}
fmt.Println(res.TagName, res.TextContent)
Returns
*InspectResult*InspectResult with the resolved backendNodeId, frameId, tag

ListReactions

method on CloudBrowser
ListReactions() → []ReactionInfo

ListReactions returns the still-pending reactions registered for the current page. Reactions that have already fired (one-shot) are not included.

pending, err := browser.ListReactions(ctx)
for _, r := range pending {
    log.Printf("reaction %s watching %s%s", r.ReactionID, r.MatchSelector, r.MatchJsExpression)
}
Returns
[]ReactionInfothe pending reactions for the page

ListScriptRuns

method on CloudBrowser
ListScriptRuns() → []ScriptRunInfo

ListScriptRuns reports the scripts still running in the session.

Only runs in flight — a finished run is reported once on the event stream and then forgotten, so this is not a history. Its use is finding work this caller did not start: a script a previous process left behind, which CloudBrowser.StopScripts needs an id to name.

runs, err := browser.ListScriptRuns(ctx)
if err != nil { log.Fatal(err) }
for _, run := range runs {
    fmt.Println(run.RunId, run.Running)
}
Returns
[]ScriptRunInfo[]ScriptRunInfo one entry per run still executing

LoadHTML

method on CloudBrowser
LoadHTML(url string, html string, headers []Header, statusCode int32)

LoadHTML serves 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 CloudBrowser.Navigate to trigger the load.

Parameters
urlstringthe URL pattern that, when navigated to, returns the html
htmlstringthe response body to serve
headers[]Headerextra response headers (Content-Type is set automatically)
statusCodeint32HTTP status code to serve; 0 means 200
_ = browser.LoadHTML(ctx, "https://example.com", "<h1>hi</h1>", nil, 0)
_, _ = browser.Navigate(ctx, "https://example.com", 0)
SeeCommandError for recovering the code with errors.As

MirrorDom

method on CloudBrowser
MirrorDom(opts DomMirrorOptions, onChange DomChangeHandler, onResync DomResyncHandler) → *DomMirror

MirrorDom starts mirroring the session's page and returns a live copy of its DOM.

One mirror covers the whole page as ONE tree. An <iframe> is an ordinary element whose single child is the document it hosts; expanding it fetches that document and starts mirroring the frame, however deeply nested and whether or not it is cross-origin. Unlike the inlining CloudBrowser.GetDOM does, these regions stay live — and frames nobody opened cost nothing.

This replaces polling CloudBrowser.GetDOMHash and re-fetching GetDOM: the browser reports changes to the part you actually expanded instead of re-serializing the document so you can hash it.

The subscription is established before the snapshot is taken, so no change between the two is lost. Call DomMirror.Stop when done — it stops the mirror server-side, which a cancelled context alone does not.

Parameters
optsDomMirrorOptionsinitial depth and whether to pierce shadow roots
onChangeDomChangeHandlercalled after every change, including the first snapshot;
onResyncDomResyncHandlercalled when the copy had to be rebuilt; may be nil
mirror, err := browser.MirrorDom(ctx, browserscale.DomMirrorOptions{Pierce: true},
    func(m *browserscale.DomMirror) {
        render(m.Root())
    }, nil)
if err != nil {
    log.Fatal(err)
}
defer mirror.Stop(ctx)

body := mirror.Node(mirror.MainFrameId(), bodyId)
_ = mirror.Expand(ctx, body, 0)
Returns
*DomMirror*DomMirror holding the tree
SeeCommandError for recovering the code with errors.As

ModifyRequest

method on CloudBrowser
ModifyRequest(urlPattern string, body string, timeoutMs float64, mods []HeaderModification) → *InterceptedRequest

ModifyRequest waits 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. Pass nil/empty mods to leave headers untouched and only override the body.

Parameters
urlPatternstringURL wildcard to wait for
bodystringreplacement request body; empty leaves the original body
timeoutMsfloat64per-call timeout in milliseconds; 0 uses the server default
mods[]HeaderModificationHeaderModification entries; see HeaderModification for the fields
req, err := browser.ModifyRequest(ctx, "*/api/me", "", 5000, []browserscale.HeaderModification{
    {Action: browserscale.HeaderModificationAdd, Name: "X-Trace", Value: "abc123"},
    {Action: browserscale.HeaderModificationRemove, Name: "Cookie"},
})
if err != nil {
    log.Fatal(err)
}
fmt.Println("forwarded headers:", req.Headers)
Returns
*InterceptedRequest*InterceptedRequest carrying the method/URL/headers/body that
SeeCommandError for recovering the code with errors.As

MoveTo

method on CloudBrowser
MoveTo(target *Locator) → *ElementResult

MoveTo moves 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 random center area (or to the viewport coordinate when target is At).

Parameters
target*Locatorlocator describing where to move; At is also valid
_, err := browser.MoveTo(ctx, browserscale.CSS("nav .menu"))
if err != nil {
    log.Fatal(err)
}
Returns
*ElementResult*ElementResult with the resolved frameId, backendNodeId,
SeeMoveError for recovering the code with errors.As

PressKey

method on CloudBrowser
PressKey(key string, code string, modifiers int32, location int32)

PressKey fires a single key-down event.

Only the keydown half is dispatched — pair with CloudBrowser.ReleaseKey for a full press cycle. The event targets whichever element currently has focus.

Parameters
keystringDOM KeyboardEvent.key value (e.g. "Enter", "a", "ArrowLeft")
codestringDOM KeyboardEvent.code value (e.g. "Enter", "KeyA"); empty falls back to key
modifiersint32bit-flag combination: Alt=1, Ctrl=2, Meta=4, Shift=8
locationint32DOM KeyboardEvent.location: 0=standard, 1=left, 2=right, 3=numpad
// Ctrl+A
_ = browser.PressKey(ctx, "a", "KeyA", 2, 0)
_ = browser.ReleaseKey(ctx, "a", "KeyA", 2, 0)
SeeCommandError for recovering the code with errors.As

ReadCanvas

method on CloudBrowser
ReadCanvas(target *Locator) → *ReadCanvasResult

ReadCanvas reads 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.

Parameters
target*Locatorlocator for the <canvas>; CSS, JS or Node
res, err := browser.ReadCanvas(ctx, browserscale.CSS("#game canvas"))
if err != nil {
    log.Fatal(err)
}
img, _ := base64.StdEncoding.DecodeString(res.DataBase64)
os.WriteFile("canvas.png", img, 0o644)
Returns
*ReadCanvasResult*ReadCanvasResult with the base64 image in DataBase64, the canvas
SeeCloudBrowser.ReadCanvasWith for format, quality, or a sub-rectangle · CommandError for recovering the code with errors.As

ReadCanvasWith

method on CloudBrowserinherits ReadCanvas
ReadCanvasWith(target *Locator, opts ReadCanvasOpts) → *ReadCanvasResult

ReadCanvasWith is the customizable variant of CloudBrowser.ReadCanvas.

Parameters
target*Locatorlocator for the <canvas>; CSS, JS or Node
optsReadCanvasOptsformat, quality, sub-rectangle and frame override; see ReadCanvasOpts
// Read the left half of the canvas as JPEG at quality 80.
res, err := browser.ReadCanvasWith(ctx, browserscale.CSS("canvas"),
    browserscale.ReadCanvasOpts{Format: "jpeg", Quality: 80, SW: 150, SH: 300})
Returns
*ReadCanvasResult*ReadCanvasResult with the base64 image in DataBase64, the canvas
SeeCloudBrowser.ReadCanvasWith for format, quality, or a sub-rectangle · CommandError for recovering the code with errors.As

ReadNetworkBody

method on CloudBrowser
ReadNetworkBody(bodyId string) → []byte, bool

ReadNetworkBody reads a whole captured body: an exchange's RequestBodyId or ResponseBodyId.

Bodies are stored by the browser, not sent with the exchange, so reading one is a separate call. They stay readable after the capture stops, until the session ends.

The body is fetched in ranges and assembled in memory. For very large bodies, use CloudBrowser.ReadNetworkBodyRange to process them piece by piece.

Parameters
bodyIdstringRequestBodyId or ResponseBodyId from a NetworkExchange
capture, _ := browser.CaptureNetwork(ctx, browserscale.NetworkCaptureOptions{
    Patterns: []string{"*/api/*"},
    Bodies:   browserscale.NetworkBodiesText,
}, func(ex browserscale.NetworkExchange) {
    if ex.ResponseBodyId == "" {
        return
    }
    go func() {
        body, _, err := browser.ReadNetworkBody(ctx, ex.ResponseBodyId)
        if err == nil {
            fmt.Println(ex.Url, len(body))
        }
    }()
})
defer capture.Stop(ctx)
Returns
[]byte, bool[]byte holding the body, bool reporting whether the kept body is
SeeCommandError for recovering the code with errors.As

ReadNetworkBodyRange

method on CloudBrowserinherits ReadNetworkBody
ReadNetworkBodyRange(bodyId string, offset int64, length int64) → *NetworkBodyRange

ReadNetworkBodyRange reads up to length bytes of a captured body starting at offset.

A single call returns at most 2 MiB; length 0 reads that much. Loop on offset + len(Data) until it reaches TotalSize to stream a large body.

Parameters
bodyIdstringRequestBodyId or ResponseBodyId from a NetworkExchange
offsetint64first byte to read
lengthint64bytes to read; 0 reads the per-call maximum
Returns
*NetworkBodyRange*NetworkBodyRange with the bytes and the body's total size, and an
SeeCommandError for recovering the code with errors.As

ReleaseDomSubtree

method on CloudBrowser
ReleaseDomSubtree(backendNodeId int32, frameId string)

ReleaseDomSubtree stops reporting changes inside a node, and inside any frame below it. DomMirror.Collapse calls this.

Skipping it is not an error, it is a slow leak: the browser's revealed set only grows, and eventually it is no longer filtering anything.

Parameters
backendNodeIdint32the node to close
frameIdstringthe frame its id belongs to; empty targets the main frame
SeeCommandError for recovering the code with errors.As

ReleaseKey

method on CloudBrowserinherits PressKey
ReleaseKey(key string, code string, modifiers int32, location int32)

ReleaseKey fires a single key-up event.

Mirror of CloudBrowser.PressKey. Same parameter semantics; use this to close a press cycle that was started with PressKey.

Parameters
keystringDOM KeyboardEvent.key value (e.g. "Enter", "a", "ArrowLeft")
codestringDOM KeyboardEvent.code value (e.g. "Enter", "KeyA"); empty falls back to key
modifiersint32bit-flag combination: Alt=1, Ctrl=2, Meta=4, Shift=8
locationint32DOM KeyboardEvent.location: 0=standard, 1=left, 2=right, 3=numpad
_ = browser.PressKey(ctx, "Shift", "ShiftLeft", 0, 1)
_ = browser.ReleaseKey(ctx, "Shift", "ShiftLeft", 0, 1)
SeeCommandError for recovering the code with errors.As

RemoveReaction

method on CloudBrowser
RemoveReaction(reactionID string) → bool

RemoveReaction removes a pending reaction by id. It returns false if the reaction had already fired (one-shot) or was never registered.

Parameters
reactionIDstringid returned by CloudBrowser.AddReaction
removed, err := browser.RemoveReaction(ctx, id)
Returns
booltrue if a pending reaction with this id existed and was removed

RevealDomNode

method on CloudBrowser
RevealDomNode(backendNodeId int32, frameId string) → *DomPath

RevealDomNode returns the chain from the main document down to a node, each ancestor with its own children, crossing into frames where it has to and starting the ones it passes through. DomMirror.Reveal calls this and splices it in.

Parameters
backendNodeIdint32the node to reach
frameIdstringthe frame its id belongs to; empty targets the main frame
Returns
*DomPath*DomPath with the ancestor chain as JSON and the sequence it is
SeeCommandError for recovering the code with errors.As

RunScript

method on CloudBrowser
RunScript(source string) → *ScriptResult

RunScript runs source in the session's browser and waits for it to finish.

The script runs beside the browser, in a V8 isolate of its own rather than in the page, and reaches the document through the engine: a cross-origin iframe is read as plain contentDocument with no frame ids anywhere, values come back as live objects it can assign to rather than snapshots, an element can be handed straight to browser.click, and the page sees nothing injected. Steps cost microseconds rather than network round trips, so work that is chatty by nature — polling for a selector, walking a list, following pagination — is affordable there. A guide for it is still to come.

This blocks for as long as the script runs, and cannot be bounded: the run id needed to cancel only arrives with the reply. Cancelling ctx abandons the wait but not the run. Use CloudBrowser.StartScript when the script may outlive the caller's patience, or CloudBrowser.StopScripts to abandon what this session is running.

Parameters
sourcestringJavaScript to execute; its return value comes back as JSON
result, err := browser.RunScript(ctx, `
    await browser.navigate("https://example.com");
    const items = [];
    for (const el of await browser.getDOM().querySelectorAll("h1")) {
        items.push(el.textContent);
    }
    return items;
`)
if err != nil {
    log.Fatal(err)
}
fmt.Println(result.Success, result.Result)
Returns
*ScriptResult*ScriptResult with the return value and the script's whole console

Screenshot

method on CloudBrowser
Screenshot(format string, quality int32) → *ScreenshotResult

Screenshot captures 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.

Parameters
formatstring"png" (default), "jpeg", or "webp"; pass "" for PNG
qualityint32encode quality 0-100 for "jpeg"/"webp" (ignored for
shot, err := browser.Screenshot(ctx, "png", 0)
if err != nil {
    log.Fatal(err)
}
img, _ := base64.StdEncoding.DecodeString(shot.DataBase64)
os.WriteFile("page.png", img, 0o644)
Returns
*ScreenshotResult*ScreenshotResult with the base64 image in DataBase64 and the
SeeCommandError for recovering the code with errors.As

ScrollTo

method on CloudBrowser
ScrollTo(target *Locator) → *ElementResult

ScrollTo scrolls 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.

Parameters
target*Locatorlocator describing the element to bring into view;
_, err := browser.ScrollTo(ctx, browserscale.CSS("#footer"))
if err != nil {
    log.Fatal(err)
}
Returns
*ElementResult*ElementResult with the resolved frameId, backendNodeId,
SeeScrollError for recovering the code with errors.As

SelectByIndex

method on CloudBrowser
SelectByIndex(target *Locator, index int32) → *SelectOptionResult

SelectByIndex picks 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 CloudBrowser.SelectByIndexWith with SelectOpts.NoEvents).

At is not a valid target — Select requires an actual <select> element.

Parameters
target*Locatorlocator describing the <select> element
indexint32zero-based option index
_, err := browser.SelectByIndex(ctx, browserscale.CSS("select#country"), 2)
Returns
*SelectOptionResult*SelectOptionResult with the resolved selectedIndex,
SeeCloudBrowser.SelectByIndexWith for suppressing events or · CloudBrowser.SelectByValue, CloudBrowser.SelectByText · SelectOptionError for recovering the code with errors.As

SelectByIndexWith

method on CloudBrowserinherits SelectByIndex
SelectByIndexWith(target *Locator, index int32, opts SelectOpts) → *SelectOptionResult

SelectByIndexWith is the customizable variant of CloudBrowser.SelectByIndex.

Sets the option as selected on the targeted <select>, then fires the standard input + change events (unless suppressed via CloudBrowser.SelectByIndexWith with SelectOpts.NoEvents).

At is not a valid target — Select requires an actual <select> element.

Parameters
target*Locatorlocator describing the <select> element
indexint32zero-based option index
optsSelectOptsselect customization; see SelectOpts
// Pick the option silently, no input/change events.
_, err := browser.SelectByIndexWith(ctx, browserscale.CSS("select#hidden"), 0, browserscale.SelectOpts{
    NoEvents: true,
})
Returns
*SelectOptionResult*SelectOptionResult with the resolved selectedIndex,
SeeCloudBrowser.SelectByIndexWith for suppressing events or · CloudBrowser.SelectByValue, CloudBrowser.SelectByText · SelectOptionError for recovering the code with errors.As

SelectByText

method on CloudBrowserinherits SelectByIndex
SelectByText(target *Locator, text string) → *SelectOptionResult

SelectByText picks 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 CloudBrowser.SelectByIndexWith with SelectOpts.NoEvents).

At is not a valid target — Select requires an actual <select> element.

Parameters
target*Locatorlocator describing the <select> element
textstringthe visible option text to match
_, err := browser.SelectByText(ctx, browserscale.CSS("select#country"), "Germany")
Returns
*SelectOptionResult*SelectOptionResult with the resolved selectedIndex,
SeeCloudBrowser.SelectByIndexWith for suppressing events or · CloudBrowser.SelectByValue, CloudBrowser.SelectByText · SelectOptionError for recovering the code with errors.As

SelectByTextWith

method on CloudBrowserinherits SelectByText
SelectByTextWith(target *Locator, text string, opts SelectOpts) → *SelectOptionResult

SelectByTextWith is the customizable variant of CloudBrowser.SelectByText.

Sets the option as selected on the targeted <select>, then fires the standard input + change events (unless suppressed via CloudBrowser.SelectByIndexWith with SelectOpts.NoEvents).

At is not a valid target — Select requires an actual <select> element.

Parameters
target*Locatorlocator describing the <select> element
textstringthe visible option text to match
optsSelectOptsselect customization; see SelectOpts
_, err := browser.SelectByTextWith(ctx, browserscale.CSS("select#country"), "Germany", browserscale.SelectOpts{
    NoEvents: true,
})
Returns
*SelectOptionResult*SelectOptionResult with the resolved selectedIndex,
SeeCloudBrowser.SelectByIndexWith for suppressing events or · CloudBrowser.SelectByValue, CloudBrowser.SelectByText · SelectOptionError for recovering the code with errors.As

SelectByValue

method on CloudBrowserinherits SelectByIndex
SelectByValue(target *Locator, value string) → *SelectOptionResult

SelectByValue picks 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 CloudBrowser.SelectByIndexWith with SelectOpts.NoEvents).

At is not a valid target — Select requires an actual <select> element.

Parameters
target*Locatorlocator describing the <select> element
valuestringthe value attribute to match
_, err := browser.SelectByValue(ctx, browserscale.CSS("select#country"), "DE")
Returns
*SelectOptionResult*SelectOptionResult with the resolved selectedIndex,
SeeCloudBrowser.SelectByIndexWith for suppressing events or · CloudBrowser.SelectByValue, CloudBrowser.SelectByText · SelectOptionError for recovering the code with errors.As

SelectByValueWith

method on CloudBrowserinherits SelectByValue
SelectByValueWith(target *Locator, value string, opts SelectOpts) → *SelectOptionResult

SelectByValueWith is the customizable variant of CloudBrowser.SelectByValue.

Sets the option as selected on the targeted <select>, then fires the standard input + change events (unless suppressed via CloudBrowser.SelectByIndexWith with SelectOpts.NoEvents).

At is not a valid target — Select requires an actual <select> element.

Parameters
target*Locatorlocator describing the <select> element
valuestringthe value attribute to match
optsSelectOptsselect customization; see SelectOpts
_, err := browser.SelectByValueWith(ctx, browserscale.CSS("select#country"), "DE", browserscale.SelectOpts{
    NoEvents: true,
})
Returns
*SelectOptionResult*SelectOptionResult with the resolved selectedIndex,
SeeCloudBrowser.SelectByIndexWith for suppressing events or · CloudBrowser.SelectByValue, CloudBrowser.SelectByText · SelectOptionError for recovering the code with errors.As

SessionId

method on CloudBrowser
SessionId() → string

SessionId returns the unique server-assigned id for this browser session.

Returns
string

SetAuthSession

method on CloudBrowser
SetAuthSession(session AuthSession)

SetAuthSession imports an auth session so the context comes up signed in (and syncing if SyncConsent) with its DBSC sessions restored.

Call before navigating. Pair with SetCookies / SetStorage to fully restore a persona.

Parameters
sessionAuthSessionsession as returned by GetAuthSession
_ = browser.SetAuthSession(ctx, *saved)
_ = browser.Navigate(ctx, "https://mail.google.com")

SetBlockList

method on CloudBrowser
SetBlockList(patterns []string)

SetBlockList replaces 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 a nil/empty slice to clear the blocklist and let everything through.

Parameters
patterns[]stringURL wildcards to block; nil or empty clears the list
_ = browser.SetBlockList(ctx, []string{
    "*.doubleclick.net/*",
    "*googletagmanager.com*",
})

SetCookies

method on CloudBrowser
SetCookies(cookies []CookieParam)

SetCookies writes the supplied cookies into the browser context.

Existing cookies with the same (name, domain, path) tuple are overwritten. Pass an empty slice for a no-op.

Parameters
cookies[]CookieParamcookies to write; empty slice is a no-op
secure := true
httpOnly := true
sameSite := "Lax"

_ = browser.SetCookies(ctx, []browserscale.CookieParam{
    {
        Name:     "auth",
        Value:    "tok",
        Domain:   "example.com",
        Path:     "/",
        Secure:   &secure,
        HTTPOnly: &httpOnly,
        SameSite: &sameSite,
    },
})

SetProxy

method on CloudBrowser
SetProxy(proxyHost string, proxyPort int32, proxyUsername string, proxyPassword string)

SetProxy changes 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.

Parameters
proxyHoststringupstream proxy host; empty disables the proxy
proxyPortint32upstream proxy port; ignored when proxyHost is empty
proxyUsernamestringproxy auth user (empty for unauthenticated proxies)
proxyPasswordstringproxy auth password (empty for unauthenticated proxies)
_ = browser.SetProxy(ctx, "proxy.example.com", 8080, "user", "pass")

SetStaticPaths

method on CloudBrowser
SetStaticPaths(blobName string, patterns []string)

SetStaticPaths configures 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 (blob storage, CDN, …) is configured server-side. Pass an empty patterns slice to disable caching for this session.

Parameters
blobNamestringserver-side identifier of the snapshot to serve from
patterns[]stringURL wildcards to redirect to the cache; nil/empty disables
_ = browser.SetStaticPaths(ctx, "snap-2026-05", []string{"*.example.com/*"})

SetStorage

method on CloudBrowser
SetStorage(storage []StorageOriginEntry)

SetStorage writes 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.

Parameters
storage[]StorageOriginEntryentries to write, grouped by origin
_ = browser.SetStorage(ctx, []browserscale.StorageOriginEntry{
    {
        Origin: "https://example.com",
        Items: []browserscale.StorageItem{
            {Key: "token", Value: "abc123"},
            {Key: "theme", Value: "dark"},
        },
    },
})

SolveCaptcha

method on CloudBrowser
SolveCaptcha(timeoutMs int32, retryAmount int32) → string

SolveCaptcha detects 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.

Parameters
timeoutMsint32how long to wait for a captcha to appear, in
retryAmountint32number of retries on a failed solve before giving up
if _, err := browser.SolveCaptcha(ctx, 0, 2); err != nil {
    log.Fatal(err)
}
Returns
stringempty string on success — the solution is applied server-side

StartDomMirror

method on CloudBrowser
StartDomMirror(opts DomMirrorOptions) → *DomSnapshot

StartDomMirror starts (or restarts) the page's mirror and returns the main document, without subscribing to changes. CloudBrowser.MirrorDom is what you normally want; this is the raw command.

Calling it again restarts the mirror, which is also the recovery path after a resync. Subscribe before calling it: changes between the snapshot and the subscription are not replayed.

Parameters
optsDomMirrorOptionsinitial depth and whether to pierce shadow roots
Returns
*DomSnapshot*DomSnapshot with the main document, its frame and the baseline
SeeCommandError for recovering the code with errors.As

StartNetworkCapture

method on CloudBrowser
StartNetworkCapture(opts NetworkCaptureOptions)

StartNetworkCapture arms a capture without subscribing to it.

Use it when the reader lives somewhere else — another process, or a later ConnectSession against the same session. Most callers want CloudBrowser.CaptureNetwork instead, which arms and subscribes together. Calling this again replaces the running capture.

Parameters
optsNetworkCaptureOptionswhich requests to capture and whether to keep bodies

StartScript

method on CloudBrowser
StartScript(source string, onEvent ScriptEventHandler) → *ScriptRun

StartScript launches source in the session's browser and returns as soon as the run is under way.

The counterpart to CloudBrowser.RunScript, for scripts that are not worth waiting on: a watcher that runs for the life of the session, work that should survive this process. Output arrives at onEvent while the caller gets on with something else, and ScriptRun.Wait collects the outcome if it is wanted.

Subscribing has to happen before the launch, because a detached run's output is not kept anywhere — the browser rejects a start with nobody listening rather than discard the script's log and result. This call does both in that order, so nothing the script prints is missed.

Parameters
sourcestringJavaScript to execute
onEventScriptEventHandlercalled per log line and once for the outcome; see
run, err := browser.StartScript(ctx, source, func(ev browserscale.ScriptEvent) {
    if ev.Log != nil {
        fmt.Println(ev.Log.Level, ev.Log.Message)
    }
})
if err != nil {
    log.Fatal(err)
}
outcome, err := run.Wait(ctx)
Returns
*ScriptRun*ScriptRun handle for awaiting or cancelling the run

StartStream

method on CloudBrowser
StartStream(offerSDP string) → StreamAnswer

StartStream answers your WebRTC SDP offer and starts streaming the page as a video track. The browser is the answerer; you are the offerer (see CloudBrowser.GetStreamConfig for the credentials to build the offer).

Parameters
offerSDPstringyour RTCPeerConnection's SDP offer
stream, err := browser.StartStream(ctx, offer.SDP)
if err != nil { log.Fatal(err) }
// peer.SetRemoteDescription({type: "answer", sdp: stream.AnswerSDP}) …
Returns
StreamAnswerthe SDP answer plus the viewport to map input coordinates into
SeeCommandError for recovering the code with errors.As

StopDomMirror

method on CloudBrowser
StopDomMirror()

StopDomMirror stops the page's mirror, every frame of it. Idempotent.

Reports only transport failures - a dead session, a page that is gone, a broken connection. Stopping a mirror that is not running is a no-op rather than a failure, so there are no error codes to branch on.

StopNetworkCapture

method on CloudBrowser
StopNetworkCapture() → bool

StopNetworkCapture disarms the session's capture.

Returns
boolbool reporting whether a capture was running, and an error

StopScripts

method on CloudBrowser
StopScripts(runId string) → int

StopScripts cancels runs in the session and reports how many it ended.

An empty runId cancels every run in the session, which is the only form available to a caller that never learned an id — notably one abandoning a blocking CloudBrowser.RunScript.

Parameters
runIdstringrun to cancel, or "" for all of them
_, err := browser.StopScripts(ctx, "") // abandon everything running
Returns
intint how many runs were cancelled; 0 when the id named nothing in

StopStream

method on CloudBrowser
StopStream()

StopStream tears down the live video stream for the session's page. It is safe to call even if no stream is running.

Reports only transport failures - a dead session, a page that is gone, a broken connection. Stopping a stream that is not running is a no-op rather than a failure, so there are no error codes to branch on.

if err := browser.StopStream(ctx); err != nil { log.Fatal(err) }

StreamNetworkExchanges

method on CloudBrowser
StreamNetworkExchanges(onExchange NetworkExchangeHandler) → *NetworkCapture

StreamNetworkExchanges subscribes to the session's capture without arming one, for reading a capture that CloudBrowser.StartNetworkCapture armed elsewhere. Several readers can watch the same capture, each with its own buffer.

Stopping the returned view detaches this reader and leaves the capture running, since other readers may still be attached.

Parameters
onExchangeNetworkExchangeHandlercalled per exchange; see NetworkExchangeHandler for the
Returns
*NetworkCapture*NetworkCapture attached to whatever capture is running; onExchange

Timezone

method on CloudBrowser
Timezone() → string

Timezone returns the IANA timezone the session was provisioned with (e.g. "Europe/Berlin").

Returns
string

Type

method on CloudBrowser
Type(text string, clearFirst bool)

Type types 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 CloudBrowser.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 CloudBrowser.Fill instead (strict, target-bound, per-key focus-verified).

Nothing is focused for you: CloudBrowser.Click (or Fill) the field first, or otherwise ensure focus, before calling Type.

Parameters
textstringthe text to type as real key events
clearFirstboolwhen true, clears the focused field (Ctrl+A, Delete) first
// OTP field that auto-advances across boxes.
_, _ = browser.Click(ctx, browserscale.CSS("input.otp-0"))
if err := browser.Type(ctx, "123456", false); err != nil {
    log.Fatal(err)
}

Wait

method on CloudBrowser
Wait(args ...WaitArg) → *WaitResult

Wait blocks until any of the supplied locators matches.

Pass one or more Locators (built with CSS, JS, …) plus optional wait-level arguments such as Timeout. When several locators are supplied, the first one to match wins; the others are abandoned.

Anything left unset is defaulted by the API, not by this SDK: - timeout: 30s — override with Timeout - per-locator visible and steady: visibility required, 500ms of settling. For JS expressions returning a non-Element value (bool/string/number/ object) both are no-ops. Override with Locator.Visible / Locator.Steady on individual locators.

Node and At are not valid wait conditions — they only make sense as action targets — and produce an error at send time.

Parameters
args...WaitArgone or more Locators plus optional wait-level options;
// Wait for either a success banner or a JS condition, max 5s.
res, err := browser.Wait(ctx,
    browserscale.CSS(".success"),
    browserscale.JS("window.__ready === true"),
    browserscale.Timeout(5000),
)
if err != nil {
    var we *browserscale.WaitError
    if errors.As(err, &we) {
        for _, c := range we.Conditions {
            log.Printf("condition %d: %s", c.Index, c.State)
        }
    }
    log.Fatal(err)
}
_ = res
Returns
*WaitResult*WaitResult for the first matching condition (carries the
SeeWaitError for the timeout detail

WaitForAnyRequest

method on CloudBrowser
WaitForAnyRequest(timeoutMs float64, patterns []RequestPattern) → int32, *InterceptedRequest

WaitForAnyRequest 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.

Parameters
timeoutMsfloat64per-call timeout in milliseconds; 0 uses the server default
patterns[]RequestPatternone or more URL patterns (with optional Abort flags)
idx, req, err := browser.WaitForAnyRequest(ctx, 5000, []browserscale.RequestPattern{
    {URL: "*/api/login"},
})
if err != nil {
    log.Fatal(err)
}
_ = idx
fmt.Println(req.Method, req.Url)
Returns
int32, *InterceptedRequestint32 index of the matched pattern, *InterceptedRequest with
SeeCommandError for recovering the code with errors.As

WaitForAnyResponse

method on CloudBrowserinherits WaitForAnyRequest
WaitForAnyResponse(timeoutMs float64, patterns []RequestPattern) → int32, *InterceptedResponse

WaitForAnyResponse blocks until the next response whose URL matches one of the supplied patterns is observed.

Same shape as CloudBrowser.WaitForAnyRequest but on the response phase. When patternsi.Abort is true the page receives an empty 200 instead of the real response.

Parameters
timeoutMsfloat64per-call timeout in milliseconds; 0 uses the server default
patterns[]RequestPatternone or more URL patterns (with optional Abort flags)
idx, resp, err := browser.WaitForAnyResponse(ctx, 5000, []browserscale.RequestPattern{
    {URL: "*/api/login"},
})
if err != nil {
    log.Fatal(err)
}
_ = idx
fmt.Println(resp.StatusCode)
Returns
int32, *InterceptedResponseint32 index of the matched pattern, *InterceptedResponse with
SeeCommandError for recovering the code with errors.As
type

Locator

4 methods

Locator is the universal "what element / what condition" type. It is used both as a wait condition (passed to Wait) and as a target for element actions (passed to Click, Fill, etc.).

Not every field is meaningful in every context: - selector / jsExpression → both wait and actions - backendNodeId → actions only (Wait rejects it) - visible / steadyTime → wait only (silently ignored by actions) - x / y → actions only (Wait rejects it) - frameId → both, may be overridden by call-level browserscale.InFrame() / browserscale.InAllFrames() options

Use the CSS / JS / Node / At constructors instead of building this struct by hand.

InAllFrames

method on Locator
InAllFrames() → *Locator

InAllFrames scopes 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.

_, _ = browser.Wait(ctx, browserscale.CSS("button.consent").InAllFrames())
Returns
*Locatorthe same Locator for chaining

InFrame

method on Locator
InFrame(id string) → *Locator

InFrame scopes this Locator to a specific frameId.

Use the frameId from a previous result or CloudBrowser.GetPages to target elements inside a known iframe.

Parameters
idstringid of the frame to scope to
pages, _ := browser.GetPages(ctx)
iframeId := pages[0].FrameTree.Children[0].FrameId
_, _ = browser.Click(ctx, browserscale.CSS("button").InFrame(iframeId))
Returns
*Locatorthe same Locator for chaining

Steady

method on Locator
Steady(ms float64) → *Locator

Steady requires the element to keep a stable position and size for at least ms milliseconds before the wait matches.

Settling defaults to 500ms, so pass 0 to match the instant the element is found. Has no effect for JS expressions that return a non-Element value, nor when the Locator is used as an action target.

Parameters
msfloat64steady-state duration in milliseconds; 0 disables
_, _ = browser.Wait(ctx, browserscale.CSS(".banner").Steady(0))
Returns
*Locatorthe same Locator for chaining

Visible

method on Locator
Visible(v bool) → *Locator

Visible enforces or disables the visibility check for this Locator's wait condition.

Visibility is required by default, so pass false to wait for DOM presence alone. Has no effect when the Locator is used as an action target — actions never check visibility before dispatching.

Parameters
vbooltrue to require visibility, false to skip the check
_, _ = browser.Wait(ctx, browserscale.CSS("#hidden").Visible(false))
Returns
*Locatorthe same Locator for chaining
type

BrowserConfig

5 methods

BrowserConfig holds all parameters for renting a browser session. Use NewBrowserConfig with the required fields, then chain optional setters.

UnstableWithFakeGpu

method on BrowserConfig
UnstableWithFakeGpu(renderer string, vendor string, extensions []string) → *BrowserConfig

UnstableWithFakeGpu overrides WebGL UNMASKED_RENDERER_WEBGL, UNMASKED_VENDOR_WEBGL and getSupportedExtensions().

Unstable API — likely to be reshaped or removed without notice. Use only when you have a specific WebGL-fingerprint requirement.

Parameters
rendererstringvalue to return for UNMASKED_RENDERER_WEBGL
vendorstringvalue to return for UNMASKED_VENDOR_WEBGL
extensions[]stringlist returned by getSupportedExtensions()
cfg.UnstableWithFakeGpu("ANGLE", "Google Inc.", []string{"OES_texture_float"})
Returns
*BrowserConfigthe modified *BrowserConfig for chaining

UnstableWithGpuEnabled

method on BrowserConfig
UnstableWithGpuEnabled(enabled bool) → *BrowserConfig

UnstableWithGpuEnabled restricts the rental to hosts that render on a physical GPU instead of the software renderer.

Unstable API — do not build on it. It exists to compare GPU-backed hosts against software rendering while that rollout is in progress; once every host is GPU-backed the flag becomes meaningless and is removed. Note that it narrows the pool: the rental fails rather than falling back to a software-rendered host, so it can report no capacity while ordinary rentals still succeed.

Parameters
enabledbooltrue to require a GPU-backed host
cfg := browserscale.NewBrowserConfig(apiKey, 600, "", 0, "", "").UnstableWithGpuEnabled(true)
Returns
*BrowserConfigthe modified *BrowserConfig for chaining

WithCountryCode

method on BrowserConfig
WithCountryCode(countryCode string) → *BrowserConfig

WithCountryCode sets 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.

Parameters
countryCodestringISO-3166 country code (e.g. "DE", "US")
cfg := browserscale.NewBrowserConfig(apiKey, 600, "", 0, "", "").WithCountryCode("DE")
Returns
*BrowserConfigthe modified *BrowserConfig for chaining

WithFingerprint

method on BrowserConfig
WithFingerprint(fingerprint string) → *BrowserConfig

WithFingerprint pins 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.

Parameters
fingerprintstringserver-side fingerprint id
cfg := browserscale.NewBrowserConfig(apiKey, 600, "", 0, "", "").WithFingerprint("fp_abc123")
Returns
*BrowserConfigthe modified *BrowserConfig for chaining

WithTimezone

method on BrowserConfig
WithTimezone(timezone string) → *BrowserConfig

WithTimezone sets the IANA timezone for the rented session.

Parameters
timezonestringIANA timezone (e.g. "Europe/Berlin")
cfg := browserscale.NewBrowserConfig(apiKey, 600, "", 0, "", "").WithTimezone("Europe/Berlin")
Returns
*BrowserConfigthe modified *BrowserConfig for chaining
type

BrowserInfo

1 method

BrowserInfo describes one running session as ListBrowsers reports it.

Fields
SessionIdstring
GrpcUrlstringGrpcUrl is the endpoint this session is driven from — the same one rent returned. It is what makes a listed id usable: pass it to ConnectSession, or call BrowserInfo.Connect.
StartTimeint64StartTime is unix seconds.
RentDurationintRentDuration is the rental length in seconds; 0 means unlimited.
RemainingSeconds?*intRemainingSeconds counts down to the end of the rental, and is nil for an unlimited one.
CountryCodestring
Timezonestring
ProxyHoststring
PublicIpstringPublicIp is the address the session egresses from.
GpuIndex?*intGpuIndex is the physical card the session renders on, nil on a software-rendered host.

Connect

method on BrowserInfo
Connect(apiKey string) → *CloudBrowser

Connect attaches to this listed session over gRPC.

Shorthand for ConnectSession with the URL and id already in hand. The returned handle owns no rental, so CloudBrowser.CloseConn detaches without ending the session — which is usually what you want for a session you found rather than rented.

Parameters
apiKeystringAPI key the session was rented with
browsers, _ := browserscale.ListBrowsers(ctx, apiKey)
browser, err := browsers[0].Connect(ctx, apiKey)
if err != nil { log.Fatal(err) }
defer browser.CloseConn() // detach; the session keeps running
Returns
*CloudBrowser*CloudBrowser attached to the session
type

DomMirror

13 methods

DomMirror is a live copy of a page's DOM, across every frame in it, returned by CloudBrowser.MirrorDom.

The browser sends the top of the tree once and from then on only what changed in the part you expanded, so a page that churns inside a collapsed subtree costs one number per batch instead of a re-serialized document.

It is one tree. An <iframe> is an element whose one child is the document it hosts; expanding it fetches that document and starts mirroring the frame, collapsing it stops again, and a frame navigating arrives as its owner's child being replaced.

Node ids restart per frame, so a node's address is the pair (DomNode.FrameId, DomNode.BackendNodeId) and never the id alone.

Every method is safe to call from any goroutine.

Collapse

method on DomMirror
Collapse(node *DomNode)

Collapse stops reporting changes inside a node, called when the user closes it. The node itself stays in the tree and keeps reporting its child count. A child frame below it stops being mirrored too.

Parameters
node*DomNodethe node to close
SeeCommandError for recovering the code with errors.As

Err

method on DomMirror
Err()

Err reports why the mirror ended. It returns nil while it is still running, and after a clean stop, a cancelled context, or the session ending normally.

Expand

method on DomMirror
Expand(node *DomNode, depth int32)

Expand fetches a node's children and starts reporting changes inside them. This is what a tree view calls when the user opens a node.

On an <iframe> the one child is the document it hosts, and this call is what starts mirroring that frame. Nothing about the result says a process boundary was crossed; it is a child list like any other.

A node that left the tree while the call was in flight is not an error and changes nothing.

Parameters
node*DomNodethe node to open, from DomMirror.Root or DomMirror.Node
depthint32levels below the node; 0 uses the server default of 1
SeeCommandError for recovering the code with errors.As

FrameIds

method on DomMirror
FrameIds() → []string

FrameIds returns every frame with a document in the tree, main frame first. A frame whose <iframe> has not been expanded is not mirrored and not listed.

Returns
[]string

IsExpanded

method on DomMirror
IsExpanded(node *DomNode) → bool

IsExpanded reports whether this node's children are known. Changes inside a node that is not expanded arrive only as an updated ChildNodeCount.

Parameters
node*DomNode
Returns
bool

MainFrameId

method on DomMirror
MainFrameId() → string

MainFrameId returns the page's main frame.

Returns
string

Node

method on DomMirror
Node(frameId string, backendNodeId int32) → *DomNode

Node looks up a node by its address, or nil if the mirror does not hold it.

Parameters
frameIdstring
backendNodeIdint32
Returns

Resync

method on DomMirror
Resync()

Resync throws away the local copy of the whole page and fetches a fresh one. It happens automatically whenever the browser says the copy is void, so you rarely need to call it.

SeeCommandError for recovering the code with errors.As

Reveal

method on DomMirror
Reveal(backendNodeId int32, frameId string) → []*DomNode

Reveal brings a node into the tree together with its ancestors and their siblings, and starts reporting changes along that path.

Use it to focus a node you do not hold — an CloudBrowser.InspectAtPosition hit, say. You cannot walk up to it yourself: it is not in your tree, so there is nothing to walk from.

The node may be in a frame nobody opened, and that works: the chain comes back crossing the frame boundaries it has to, and those frames start being mirrored, exactly as if you had expanded your way there by hand.

Parameters
backendNodeIdint32the node to reach
frameIdstringthe frame its id belongs to; empty targets the main frame
Returns
[]*DomNode[]*DomNode the ancestor chain, the main document first, or nil if the
SeeCommandError for recovering the code with errors.As

Root

method on DomMirror
Root() → *DomNode

Root returns the main frame's document, or nil before the first snapshot arrived.

The result is an immutable snapshot: the mirror will not modify the nodes it hands out, so it stays consistent to walk while the page keeps changing.

Returns

Seq

method on DomMirror
Seq() → uint64

Seq returns the page sequence of the last change applied. One clock for the whole page: a change in an out-of-process iframe and one in the main document are ordered against each other.

Returns
uint64

Stop

method on DomMirror
Stop()

Stop stops mirroring and detaches the reader. Idempotent, and safe to defer.

Once it returns, the change handler is no longer running and everything it wrote is visible to the calling goroutine.

To stop from inside the handler, call CloudBrowser.StopDomMirror instead: Stop waits for the handler to return, so calling it from there would wait on itself until ctx expires.

ctx covers the call that stops the mirror server-side, so pass a live one: the context the mirror was created with may already be cancelled by the time you stop.

Reports only transport failures - a dead session, a page that is gone, a broken connection. The local reader is shut down regardless, and stopping a mirror that is not running is a no-op, so there are no error codes to branch on.

Wait

method on DomMirror
Wait()

Wait blocks until the mirror ends — DomMirror.Stop, a cancelled context, a dead session or a transport failure — and returns DomMirror.Err.

type

NetworkCapture

4 methods

NetworkCapture is a running capture, returned by CloudBrowser.CaptureNetwork. Exchanges are delivered to the handler passed there; this handle only exists to stop the capture and to report how it went.

Dropped

method on NetworkCapture
Dropped() → uint64

Dropped reports how many exchanges the server discarded because this reader fell behind. Anything above zero means the log has holes: make the handler cheaper or narrow Patterns.

Returns
uint64

Err

method on NetworkCapture
Err()

Err reports why the capture ended. It returns nil while the capture is still running, and after a clean stop, a cancelled context, or the session ending normally.

Stop

method on NetworkCapture
Stop()

Stop ends the capture. Idempotent, and safe to defer.

Once it returns, the handler is no longer running and everything it wrote is visible to the calling goroutine — so a handler may append to a slice without locking, as long as you only read that slice after Stop. Views from CloudBrowser.StreamNetworkExchanges only detach — they never disarm a capture other readers may share.

To stop from inside the handler, call CloudBrowser.StopNetworkCapture instead: Stop waits for the handler to return, so calling it from there would wait on itself until ctx expires.

ctx covers the disarm call, so pass a live one: the context the capture was created with may already be cancelled by the time you stop.

Reports only transport failures, and the local reader is shut down regardless. Disarming a capture that is not running is a no-op rather than a failure, so there are no error codes to branch on.

Wait

method on NetworkCapture
Wait()

Wait blocks until the capture ends — NetworkCapture.Stop, a cancelled context, a dead session or a transport failure — and returns NetworkCapture.Err.

Use it to capture for as long as the session lives. It is not needed when you drive the browser yourself and call Stop when done.

type

ScriptFollow

4 methods

ScriptFollow is a read-only view of script output, returned by CloudBrowser.FollowScript.

Dropped

method on ScriptFollow
Dropped() → uint64

Dropped reports how many events the server discarded because this reader fell behind.

Returns
uint64

Err

method on ScriptFollow
Err()

Err reports why the subscription ended, or nil while it is still open and after a clean stop.

Stop

method on ScriptFollow
Stop()

Stop ends the subscription. Idempotent, and safe to defer. It never cancels a run: other readers, and the script itself, are unaffected.

Once it returns, the handler is no longer running and everything it wrote is visible to the calling goroutine.

Wait

method on ScriptFollow
Wait()

Wait blocks until the subscription ends — ScriptFollow.Stop, a cancelled context, a dead session or a transport failure — and returns ScriptFollow.Err.

type

ScriptRun

6 methods

ScriptRun is a script running in the background, returned by CloudBrowser.StartScript. Its output is delivered to the handler passed there; this handle exists to wait for the outcome and to cancel the run.

Detach

method on ScriptRun
Detach()

Detach stops reading this run's output without cancelling the run. The script keeps going with nobody watching, which is what makes a detached run outlive the process that started it.

Dropped

method on ScriptRun
Dropped() → uint64

Dropped reports how many events the server discarded because this reader fell behind. Anything above zero means the log has holes: make the handler cheaper, or have the script print less.

Returns
uint64

Err

method on ScriptRun
Err()

Err reports why the stream ended, or nil while it is still open and after a clean stop, a cancelled context, or the session ending normally.

RunId

method on ScriptRun
RunId() → string

RunId is the id the browser gave this run. Pass it to CloudBrowser.StopScripts to cancel the run from elsewhere, or to CloudBrowser.FollowScript to watch it from another process.

Returns
string

Stop

method on ScriptRun
Stop()

Stop cancels the run and detaches this reader. Idempotent, and safe to defer.

A script that is executing is interrupted; one parked on an await unwinds at its next operation in the page. Either way the handler sees a Finished with Stopped set, unless the local reader is torn down first.

ctx covers the cancel call, so pass a live one: the context the run was started with may already be cancelled by the time you stop.

Reports only transport failures, and the local reader is detached regardless. Cancelling a run that has already finished is a no-op rather than a failure.

Wait

method on ScriptRun
Wait() → *ScriptFinished

Wait blocks until the run ends and returns how it ended.

A script that threw is an outcome, not an error: it comes back with Success false. An error means the run's fate is unknown — the stream broke, the session died, or ctx expired before the script finished.

Returns
*ScriptFinished*ScriptFinished describing how the script ended

Functions

13 functions

Package-level functions: renting, listing, connecting to and stopping sessions, and the locator constructors.

At

function
At(x float64, y float64) → *Locator

At 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 CloudBrowser.Wait returns an error at send time. Note that only Click and MoveTo accept At; Scroll, Drag, Fill and Select all require a real element.

Parameters
xfloat64viewport-relative x in CSS pixels
yfloat64viewport-relative y in CSS pixels
// Click at canvas-relative coordinates.
_, _ = browser.Click(ctx, browserscale.At(120, 240))
Returns
*Locator*Locator usable only as an action target
ConnectSession(grpcUrl string, apiKey string, sessionId string) → *CloudBrowser

ConnectSession attaches to an already-running session via gRPC.

Use this when you have a session id and gRPC URL from a previous RentBrowser (for example stored across process restarts). Unlike RentBrowser this does not call the rent API — the session must already exist server-side.

Parameters
grpcUrlstringthe session's gRPC endpoint as returned by CloudBrowser.GrpcUrl,
apiKeystringAPI key authorizing access to the session
sessionIdstringid of the existing session to attach to
browser, err := browserscale.ConnectSession(ctx, "grpcs://api.browserscale.cloud:443", apiKey, sessionId)
if err != nil {
    log.Fatal(err)
}
defer browser.Close()
Returns
*CloudBrowser*CloudBrowser attached to the existing session; the returned

CSS

function
CSS(selector string) → *Locator

CSS waits for / targets an element matching the given CSS selector.

When used in CloudBrowser.Wait, the condition requires the element to be visible and to hold still for 500ms before it matches — the API's defaults for a condition that does not set them. Override per call with Locator.Visible / Locator.Steady (use .Steady(0) to disable the steady check).

When used as an action target (Click, etc.) the visible/steady fields are ignored — there are no corresponding fields on the action requests.

Parameters
selectorstringCSS selector matching the element
// As a wait condition.
_, _ = browser.Wait(ctx, browserscale.CSS("button.submit"))
// As an action target.
_, _ = browser.Click(ctx, browserscale.CSS("button.submit"))
Returns
*Locator*Locator usable as a wait condition or as an action target

JS

function
JS(expression string) → *Locator

JS waits for / targets the result of a JavaScript expression.

Same wait defaults as CSS (visible, 500ms steady); these only apply when the expression returns a DOM Element. For non-Element truthy values (boolean, string, number, plain object) both are no-ops and the condition matches as soon as the value is truthy.

Use Locator.Visible(false) / Locator.Steady(0) on the returned Locator to opt out.

Parameters
expressionstringJavaScript expression evaluated in the target frame
_, _ = browser.Wait(ctx, browserscale.JS("window.__ready === true"))
Returns
*Locator*Locator usable as a wait condition or as an action target
ListBrowsers(apiKey string) → []BrowserInfo

ListBrowsers reports the sessions an API key currently holds.

Use it to recover session ids the process lost — after a restart, or from a different machine entirely. Without it a rental is only reachable through the handle that created it, so a crash between rent and stop leaves a paid session running with nothing able to name it.

Only live sessions are listed; a stopped one is gone, not reported as ended.

Parameters
apiKeystringAPI key whose sessions to list
browsers, err := browserscale.ListBrowsers(ctx, apiKey)
if err != nil {
    log.Fatal(err)
}
for _, b := range browsers {
    fmt.Println(b.SessionId, b.CountryCode)
}
Returns
[]BrowserInfo[]BrowserInfo oldest first, empty when the key holds none
NewBrowserConfig(apiKey string, rentDuration int, proxyHost string, proxyPort int, proxyUsername string, proxyPassword string) → *BrowserConfig

NewBrowserConfig returns a BrowserConfig populated with the required rental fields. Optional fields are configured via the chainable With… setters before passing the config to RentBrowser.

Parameters
apiKeystringAPI key authenticating the rental
rentDurationintlifetime of the session in seconds
proxyHoststringupstream proxy host (empty string disables the proxy)
proxyPortintupstream proxy port (ignored when proxyHost is empty)
proxyUsernamestringproxy auth user (empty for unauthenticated proxies)
proxyPasswordstringproxy auth password (empty for unauthenticated proxies)
cfg := browserscale.NewBrowserConfig("sk_…", 600, "", 0, "", "").
    WithCountryCode("DE").
    WithTimezone("Europe/Berlin")
Returns
*BrowserConfig*BrowserConfig ready to be customized further or passed to RentBrowser

Node

function
Node(backendNodeId int32) → *Locator

Node targets an element by its DevTools backendNodeId.

Use this when you already have a backendNodeId from a previous result (e.g. WaitResult or EvaluateResult) and want to act on the exact same element without re-resolving by selector. Action-only — using it in CloudBrowser.Wait returns an error at send time.

Parameters
backendNodeIdint32DevTools backendNodeId of the target element
res, _ := browser.Click(ctx, browserscale.CSS("button.open"))
_, _ = browser.Click(ctx, browserscale.Node(res.BackendNodeId))
Returns
*Locator*Locator usable only as an action target

Ptr

function
Ptr(v T) → *T

Ptr returns a pointer to v. It is a convenience for the SDK's optional pointer fields where a zero value is meaningful and must be distinguished from "unset" — e.g. FillOpts.TimeoutMs: browserscale.Ptr(0.0) makes Fill one-shot, whereas a nil field takes the server default.

Parameters
vT
Returns
*T

RentBrowser

function
RentBrowser(config *BrowserConfig) → *CloudBrowser

RentBrowser rents 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. On any failure the partially-rented session is best-effort released.

Parameters
config*BrowserConfigrental parameters built with NewBrowserConfig
cfg := browserscale.NewBrowserConfig("sk_…", 600, "", 0, "", "")
browser, err := browserscale.RentBrowser(ctx, cfg)
if err != nil {
    log.Fatal(err)
}
defer browser.Close()
Returns
*CloudBrowser*CloudBrowser ready to drive the rented session; call
SetApiEndpoint(endpoint string)

SetApiEndpoint overrides 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.

Parameters
endpointstringbase URL of the rent/stop service, with no trailing slash
browserscale.SetApiEndpoint("https://browserscale.internal.example.com")
StopAllBrowsers(apiKey string) → int

StopAllBrowsers releases every session an API key holds.

The blunt instrument, for cleaning up after a run that leaked sessions — a crashed worker pool, an interrupted test. It ends sessions this process never created, including ones another machine is using, so it is not a way to tidy up "my" sessions in a shared account.

Unused credits are refunded per session, as with StopBrowser.

Parameters
apiKeystringAPI key whose sessions to release
stopped, err := browserscale.StopAllBrowsers(ctx, apiKey)
Returns
intint how many sessions were stopped

StopBrowser

function
StopBrowser(apiKey string, sessionId string) → *SessionUsage

StopBrowser releases 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.

Parameters
apiKeystringAPI key the session was rented with
sessionIdstringid of the session to release
usage, err := browserscale.StopBrowser(context.Background(), apiKey, sessionId)
Returns
*SessionUsage*SessionUsage what the session consumed over its whole life; nil

Timeout

function
Timeout(ms float64) → WaitArg

Timeout overrides the CloudBrowser.Wait timeout.

When omitted, the API's default of 30s applies. Pass once per Wait call as one of the variadic arguments.

Parameters
msfloat64timeout in milliseconds
_, _ = browser.Wait(ctx, browserscale.CSS("#done"), browserscale.Timeout(5000))
Returns
WaitArga WaitArg suitable for passing to Wait

Errors

8 errors

Returned as the error of the command they belong to, each with a stable code and typed detail. Recover them with errors.As.

ClickError is returned as the error from CloudBrowser.Click / CloudBrowser.ClickWith when the click did not land (the element was occluded and the point could not be reached). It implements the error interface, so the ordinary res, err := browser.Click(...) shape keeps working; recover the structured detail with errors.As:

res, err := browser.Click(ctx, browserscale.CSS("#buy")) var ce *browserscale.ClickError if errors.As(err, &ce) { // ce.Code, ce.Message, ce.Occluder describe the blocker }

Fields
CodestringCode is a machine-stable failure code, e.g. "occluded_no_reachable_point" (target fully covered, no exposed part reachable) or "occluded_after_evade" (a reposition was tried but the target was still covered).
MessagestringMessage is a human-readable description.
Occluder?*OccluderInfoOccluder is the intercepting element (present for occlusion codes).
EvadeAttemptedboolEvadeAttempted reports whether a pointer reposition was tried before giving up.

CommandError is the failure detail of a command the browser carried out but the page would not go along with. It is the error type for the commands that have nothing to report beyond what went wrong; the richer failures have their own type (ClickError, FillError, DragError) carrying the same Code/Message pair plus their own detail.

It implements the error interface, so the ordinary res, err := ... shape keeps working and res stays readable alongside it. Recover the code with errors.As:

res, err := browser.Evaluate(ctx, "document.title.toUpperCase()") var ce *browserscale.CommandError if errors.As(err, &ce) && ce.Code == "threw" { // the expression itself is broken; ce.Message has the exception text }

A CommandError never reports an outage. A dead session, a closed page or a malformed call arrive as a plain transport error instead, so errors.As matching here tells you the fault is in the page or in what you asked of it — which is the difference between retrying and fixing your code.

Fields
CommandstringCommand is the call that failed, e.g. "evaluate".
CodestringCode is machine-stable and lowercase, and is scoped to Command: the same string can mean different things for different commands, so branch on it together with the call you made.
MessagestringMessage is human-readable detail and may be empty. Never parse it; Code is the contract and this text is free to change.

DragError is returned as the error from CloudBrowser.Drag variants 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/Message mirror it and the full click diagnostics live under ClickError. Implements the error interface; recover with errors.As.

Fields
CodestringCode is mirrored from the underlying click failure: "not_found", "occluded_no_reachable_point" or "occluded_after_evade".
MessagestringMessage is a human-readable description (mirrors ClickError.Message).
ClickError?*ClickErrorClickError is the underlying click-core failure at the source pickup.

FillError is returned as the error from CloudBrowser.Fill / CloudBrowser.FillWith when the field could not be focused/typed. Fill focuses the field with the exact same smart click as CloudBrowser.Click, so a pre-typing failure is a click failure: Code/Message mirror it and the full click diagnostics live under ClickError. It implements the error interface, so the ordinary res, err := browser.Fill(...) shape keeps working; recover the detail with errors.As:

res, err := browser.Fill(ctx, browserscale.CSS("#email"), "a@b.com") var fe *browserscale.FillError if errors.As(err, &fe) && fe.ClickError != nil { // fe.ClickError.Occluder describes the blocker }

Fields
CodestringCode is the machine-stable failure code. 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 Type.
MessagestringMessage is a human-readable description (mirrors ClickError.Message).
ClickError?*ClickErrorClickError is the underlying click-core failure (locate or occlusion) that prevented focusing/typing. Present for the click-phase codes; absent for "focus_stolen"/"focus_lost".
FocusedBackendNodeIdint32FocusedBackendNodeId is the node that held focus when Fill gave up (0 if nothing was focused), for the "focus_stolen"/"focus_lost" codes.
FocusedElement?*ElementRefFocusedElement describes the element that grabbed focus instead of the target ("focus_stolen"), so you can act on it (e.g. a consent button).
TargetEditable?*boolTargetEditable and TargetValueLength report 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. Both nil when not reported.
TargetValueLength?*int

MoveError is returned as the error from CloudBrowser.MoveTo when the target could not be located. A move has no occlusion notion, so this is the only semantic failure. Implements the error interface; recover with errors.As.

Fields
CodestringCode is currently always "not_found".
MessagestringMessage is a human-readable description.

ScrollError is returned as the error from CloudBrowser.ScrollTo when the target could not be located/scrolled. Implements the error interface; recover with errors.As.

Fields
CodestringCode is currently always "not_found".
MessagestringMessage is a human-readable description.

SelectOptionError is returned as the error from CloudBrowser SelectByXxx calls when the option could not be selected. selectOption is programmatic (no pointer gate), so it only reports semantic failures. Implements the error interface; recover with errors.As.

Fields
CodestringCode is "not_found" (the <select> was not located) or "option_not_found" (no option matched the requested index/value/text).
MessagestringMessage is a human-readable description.

WaitError is returned as the error from CloudBrowser.Wait when no condition matched before the deadline. It implements the error interface, so the ordinary res, err := browser.Wait(...) shape keeps working; recover the structured detail (including the per-condition breakdown) with errors.As:

res, err := browser.Wait(ctx, browserscale.CSS(".ready")) var we *browserscale.WaitError if errors.As(err, &we) { for _, c := range we.Conditions { log.Printf("condition %d: %s", c.Index, c.State) } }

Fields
CodestringCode is a machine-stable failure code, currently always "timeout".
MessagestringMessage is a human-readable description.
Conditions[]WaitConditionStatusConditions holds the per-condition status, same order/length as the conditions passed to Wait.

Options

9 types

Optional settings a command accepts.

ClickOpts customizes a CloudBrowser.ClickWith call. Zero/empty values mean "use the server default".

Fields
InFramestringInFrame overrides the locator's own frame. Empty = use the locator's frame (or the main frame if none). Pass a specific frameId, or AllFrames, to search elsewhere.
ButtonstringButton is the mouse button to use. Valid: "left" (default), "right", "middle".
ClickCountint32ClickCount controls single/double-click. 0 or 1 = single click (default), 2 = double-click.
ActionstringAction selects the mouse phase. "" or "click" = full mouseDown+mouseUp (default). "press" only dispatches mouseDown. "release" only dispatches mouseUp at the current cursor position.

CookieParam is one cookie returned by GetCookies / passed to SetCookies. Name, Value, Domain, and Path are the common required identity fields; optional attributes mirror the browser's CookieParam shape: URL, Secure, HTTPOnly, SameSite, Expires, Priority, SourceScheme, SourcePort, and PartitionKey.

Fields
Namestring
Valuestring
URL?*string
Domainstring
Pathstring
Secure?*bool
HTTPOnly?*bool
SameSite?*string
Expires?*float64
Priority?*string
SourceScheme?*string
SourcePort?*int
PartitionKey?*CookiePartitionKey

DomMirrorOptions configures CloudBrowser.MirrorDom and CloudBrowser.StartDomMirror.

Fields
Depthint32Depth is how many levels to serialize up front. 0 uses the server default of 2 — #document → <html> → <head>/<body>, enough to draw a collapsed tree. -1 walks everything and gives up what the mirror is for.
PierceboolPierce descends into author shadow roots. Fixed for the life of the mirror.

FillOpts

struct

FillOpts customizes a CloudBrowser.FillWith call. Zero/empty values mean "use the server default".

Fields
InFramestringInFrame overrides the locator's own frame. Empty = use the locator's frame (or the main frame if none). Pass a specific frameId, or AllFrames, to search elsewhere.
ClearFirstboolClearFirst, when true, wipes the field's existing content with Ctrl+A, Delete before typing. Default (false) appends to whatever is already there.
TimeoutMs?*float64TimeoutMs bounds focus acquisition (locate, scroll, settle, un-occlude) in ms, mirroring the click timeout. nil = server default (5000). It is a pointer because 0 is meaningful: browserscale.Ptr(0.0) makes Fill one-shot (no retry).
SteadyMs?*float64SteadyMs is the settle window in ms before the focus click, mirroring the click steady-time. nil = server default (750); browserscale.Ptr(0.0) skips settling.

NetworkCaptureOptions configures CloudBrowser.CaptureNetwork.

There is deliberately no byte-cap option: kept bodies are stored on a machine shared with other sessions, so the server owns the quota. When a session's bodies exceed it, the oldest are dropped first.

Fields
Patterns[]stringPatterns are URL wildcards to capture; nil captures every request the session makes. Prefix a pattern with "!" to exclude it, which is the short way to say "everything except this".
BodiesNetworkBodiesBodies selects response-body capture. Empty means NetworkBodiesNone. Request bodies are kept whenever a request has one.
BodyPatterns[]stringBodyPatterns narrows body capture to a subset of the captured requests; nil applies Bodies to all of them. Use it to log every request but only keep the payloads you care about.

ObservationOpts customizes a CloudBrowser.GetObservationWith call. Zero/empty values mean "use the server default".

Fields
FormatstringFormat is "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.
MaxElementsPerFrameint32MaxElementsPerFrame caps emitted elements per frame. 0 = server default (800). This is a safety net against runaway documents; MaxTotalTokens is the limit that normally binds.
MaxTextLengthint32MaxTextLength caps human-readable strings (labels, text, values) in characters. 0 = server default (300). Identifier-like attributes (type, name, role) have their own fixed, shorter cap and are unaffected.
MaxTotalTokensint32MaxTotalTokens budgets the whole page in estimated tokens rather than characters, because the same character count is worth roughly four times as many tokens in CJK text as in ASCII. 0 = server default (8000). Frames are visited in tree order and each gets whatever is left.
IncludeBoundsboolIncludeBounds adds bounds="x,y,w,h" to every row. Off by default; bounds cost about as much as the rest of a row and are rarely needed, since elements are addressed by backendNodeId.
ViewportOnlyboolViewportOnly limits the walk to elements intersecting the frame's current viewport. Off by default.
BackendNodeIdint32Subtree 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.
Selectorstring
JSExpressionstring
InFramestringInFrame looks up the scope root: empty = main frame, a frameId, or AllFrames. Ignored when observing the whole page.

ReactionOpts customizes CloudBrowser.AddReactionWith. Zero/empty values mean "use the server default".

Fields
On?*LocatorOn overrides the click target. Nil = click the matched element itself. Provide a CSS or 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.
ButtonstringButton is the mouse button for the click. Valid: "left" (default), "right", "middle".
ClickCountint32ClickCount controls single/double-click. 0 or 1 = single click (default), 2 = double-click.
IntervalMsfloat64IntervalMs is the poll cadence in milliseconds for the shared page loop. 0 = server default (300ms).

ReadCanvasOpts customizes a CloudBrowser.ReadCanvasWith call. Zero/empty values mean "use the server default".

Fields
InFramestringInFrame overrides the locator's own frame. Empty = use the locator's frame (or the main frame if none). Pass a specific frameId, or AllFrames, to search elsewhere.
FormatstringFormat is the output encoding. "" or "png" (default), "jpeg", "webp", or "rgba" for the raw unpremultiplied RGBA pixel buffer.
Qualityint32Quality is the encode quality 0-100 for "jpeg"/"webp" (ignored otherwise). 0 = server default (90).
SXint32SX, SY, SW, SH is an optional sub-rectangle in canvas pixels (mirrors getImageData(sx, sy, sw, sh)). The full canvas is read when SW/SH <= 0.
SYint32SX, SY, SW, SH is an optional sub-rectangle in canvas pixels (mirrors getImageData(sx, sy, sw, sh)). The full canvas is read when SW/SH <= 0.
SWint32SX, SY, SW, SH is an optional sub-rectangle in canvas pixels (mirrors getImageData(sx, sy, sw, sh)). The full canvas is read when SW/SH <= 0.
SHint32SX, SY, SW, SH is an optional sub-rectangle in canvas pixels (mirrors getImageData(sx, sy, sw, sh)). The full canvas is read when SW/SH <= 0.

SelectOpts customizes a SelectByXxxWith call. Zero/empty values mean "use the server default".

Fields
InFramestringInFrame overrides the locator's own frame. Empty = use the locator's frame (or the main frame if none). Pass a specific frameId, or AllFrames, to search elsewhere.
NoEventsboolNoEvents picks the option silently without firing input/change events. Default (false) fires the standard events.

Results

18 types

What commands hand back.

DragResult is the outcome of a CloudBrowser.Drag gesture: the resolved source element and the start/end coordinates of the performed drag.

Fields
Successbool
FrameIdstring
BackendNodeIdint32
StartXfloat64
StartYfloat64
EndXfloat64
EndYfloat64

ElementResult 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.

Fields
Successbool
FrameIdstring
BackendNodeIdint32
IsVisiblebool
BoundsRect
RootXfloat64
RootYfloat64

EvaluateResult carries the outcome of a JS evaluate call.

If the expression returned a DOM element, BackendNodeId/IsVisible/Bounds are populated and Value is nil. Otherwise Value holds the parsed JSON value (string/number/bool/[]any/mapstringany/nil). On parse failure Value falls back to the raw server string so the caller is never empty- handed.

Fields
SuccessboolSuccess is false only when the expression never produced a value, in which case the error carries the reason. An expression that answers falsy is a successful evaluation, so this does not mean "the answer was false".
Valueany
BackendNodeIdint32
IsVisiblebool
BoundsRect

FrameInfo describes a single frame within a page's frame tree.

Fields
FrameIdstring
Urlstring
IsOOPIFbool
HasJSContextbool
IsLoadingbool
IsVisiblebool
AbsoluteRectRect
RelativeRectRect
Children[]*FrameInfo

InspectResult describes the topmost element hit at viewport-relative (x, y). BackendNodeId == 0 means nothing was found at that position.

Fields
BackendNodeIdint32
FrameIdstring
TagNamestring
TextContentstring
IsVisiblebool
BoundsRect

InterceptedResponse describes a network response captured by CloudBrowser.WaitForAnyResponse.

Fields
Urlstring
StatusCodeint32
Headers[]Header
Bodystring

OccluderInfo 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).

Fields
BackendNodeIdint32
FrameIdstring
TagNamestring
Idstring
ClassNamestring
Textstring
BoundsRect
PointerEventsstringPointerEvents is the blocker's computed pointer-events keyword (e.g. "auto", "none", "all"). Lets you tell an invisible pass-through layer from one that genuinely swallows the click.
VisibilitystringVisibility is the blocker's computed visibility keyword ("visible", "hidden", "collapse").
Opacityfloat64Opacity is the blocker's computed opacity (0..1). 0 means visually invisible but it may still intercept clicks depending on PointerEvents.
ZIndexstringZIndex is the blocker's computed effective z-index as a string ("0" when auto / not stacked).
HittableWhileInvisibleboolHittableWhileInvisible is 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.
PositionstringPosition is the 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

struct

PageInfo describes an open page (tab or popup) inside a browser context.

Fields
PageIdstring
BrowserContextIdstring
Urlstring
Titlestring
ViewportRect
FrameTreeFrameInfo

ReactionInfo describes a still-pending reaction, as returned by CloudBrowser.ListReactions. One-shot reactions that have already fired are gone and never appear here.

Fields
ReactionIDstringReactionID is the stable id assigned by AddReaction (pass to RemoveReaction).
MatchSelectorstringMatchSelector is set if the reaction matches by CSS selector.
MatchJsExpressionstringMatchJsExpression is set if the reaction matches by JS expression.
ActionSelectorstringActionSelector is set if the click target differs from the matched element.
ActionJsExpressionstringActionJsExpression is set if the click target differs from the matched element.
FrameIDstringFrameID is the frame scope: "" for the main frame, a specific frameId, or AllFrames.
VisibleboolVisible reports whether the match additionally requires visibility.

ReadCanvasResult 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 Opts.Format == "rgba". OriginClean reports whether the canvas was untainted (informational; the read succeeds either way).

Fields
Successbool
FrameIdstring
BackendNodeIdint32
DataBase64string
Widthint32
Heightint32
OriginCleanbool

ScreenshotResult 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.

Fields
DataBase64string
Widthint32
Heightint32

ScriptFinished says how a run ended.

Fields
SuccessboolSuccess is false when the script failed to compile or threw; Result then holds the message.
ResultstringResult is the return value as JSON, or the error message.
StoppedboolStopped is true when the run was cancelled, or the session went away under it, rather than the script returning on its own.

ScriptResult is the outcome of a blocking CloudBrowser.RunScript.

Fields
SuccessboolSuccess is false when the script failed to compile or threw; Result then holds the message.
ResultstringResult is the return value as JSON, or "undefined" when the script returned nothing. On failure it is the error message.
RunIdstringRunId names the run. It arrives with the reply, so it is only useful after the fact — to match up log lines a separate follower already saw.
Log[]ScriptLogEntryLog is everything the script printed, in order.
TruncatedboolTruncated is true when the script printed more than the reply holds, in which case Log is the tail of the output rather than all of it.

ScriptRunInfo is one run still in flight, as CloudBrowser.ListScriptRuns reports it.

Fields
RunIdstring
Runningtime.DurationRunning is how long the run has been going.

SelectOptionResult reports which <option> a SelectByXxx call ended up selecting.

Fields
Successbool
SelectedIndexint32
SelectedValuestring
SelectedTextstring

StreamAnswer is the browser's reply to a CloudBrowser.StartStream.

Fields
AnswerSDPstringSDP answer to apply as your peer's remote description.
ViewportRectRoot viewport in CSS pixels, the coordinate space the stream's input data channels expect. X/Y are always 0. Map your on-screen pointer positions into this space before sending them; the video may be displayed at any size. It arrives with the answer rather than from a separate GetPages so it cannot race the stream, and the browser pushes {"type":"viewport","width":W,"height":H} on the reliable "input" channel whenever it changes.

WaitResult is the outcome of a CloudBrowser.Wait / CloudBrowser.WaitForAny call: which condition matched (Index, in argument order) and where the matched element lives.

Fields
Indexint32
FrameIdstring
BackendNodeIdint32
IsVisiblebool
BoundsRect

Data types

31 types

Everything else the API passes around: handles, events, records and enums.

AuthSession is a portable snapshot of a context's signed-in Google account and/or DBSC sessions. All fields are optional so a context that only has DBSC (no primary account) or only a sign-in (no DBSC) round-trips.

Pair with CloudBrowser.GetCookies / CloudBrowser.SetCookies and CloudBrowser.GetStorage / CloudBrowser.SetStorage to fully move a persona between fresh contexts. Call CloudBrowser.SetAuthSession before navigating.

Fields
GaiaID?*string
Email?*string
RefreshToken?*string
WrappedBindingKey?*string
SigninScopedDeviceID?*string
SyncConsent?*bool
DbscSessions[]DbscSession

CookiePartitionKey describes CHIPS partitioning metadata for partitioned cookies.

Fields
TopLevelSitestring
HasCrossSiteAncestorbool

DbscSession is one Device Bound Session Credentials entry.

Fields
SitestringSite is the serialized schemeful site key, e.g. "https://google.com".
SessionstringSession is base64 of the serialized DBSC Session proto (includes the wrapped binding key; portable under WRC's software key provider).
type DomChangeHandler = func(...)

DomChangeHandler is called after the mirrored tree changed, including once for the opening snapshot. Read the new state from DomMirror.Root.

Calls are serialized on a goroutine the SDK owns, so the handler needs no locking of its own, and it is safe to call back into the mirror from it. Calls are also coalesced: several changes in quick succession may produce a single call, which always sees the newest tree. Treat it as "something moved, re-read the root" rather than as one call per edit.

DomChildren is the reply to CloudBrowser.GetDomChildren.

Fields
ChildrenstringChildren is a JSON array of DOM.Node. Empty for an id the mirror never handed out, which is also what a stale id from before a resync looks like.
Sequint64Seq is the page sequence this payload is valid as of.

DomNode

struct

DomNode is a node in the mirrored page, in CDP's DOM.Node shape — the same shape CloudBrowser.GetDOM returns, with two additions the mirror needs and a caller usually wants anyway: DomNode.FrameId and DomNode.ContentFrameId.

An <iframe> is an ordinary element here. The document it hosts is its one entry in Children, present once the element has been expanded, and nothing about walking the tree has to know a process boundary runs through it.

Nodes are immutable once handed out. The mirror applies a change by replacing the nodes from the root down to the one that moved, so a tree you took from DomMirror.Root stays a consistent snapshot while the mirror moves on, and unchanged subtrees keep their identity. Do not modify them.

Fields
NodeIdint32
BackendNodeIdint32
NodeTypeint32
NodeNamestring
LocalNamestring
NodeValuestring
Attributes[]stringAttributes is flat name, value, name, value, ..., as CDP sends it.
ChildNodeCountint32ChildNodeCount is the total children in the page, whether or not they are in Children. An <iframe> reports 1: the document it hosts.
Children[]*DomNodeChildren is non-nil once the node has been expanded — empty and non-nil for a node that is expanded and has none.
ShadowRoots[]*DomNodeShadowRoots holds author shadow roots, when the mirror was started with DomMirrorOptions.Pierce.
FrameIdstringFrameId is the frame this node lives in. Always set. Together with BackendNodeId this is the node's address: node ids are handed out per renderer and restart per frame, so two frames can and do use the same one, and the id on its own is ambiguous across a page.
ContentFrameIdstringContentFrameId is set on an element that hosts a frame (<iframe>, <frame>, <object>): the frame it hosts, which is a different frame from FrameId and is the one its child document's ids belong to.

DomPath

struct

DomPath is the reply to CloudBrowser.RevealDomNode.

Fields
PathstringPath is a JSON array of DOM.Node, the main document first, each carrying one level of children, crossing into frames at the document nodes along it. Empty if the node is not on the page.
Sequint64Seq is the page sequence this payload is valid as of.
type DomResyncHandler = func(...)

DomResyncHandler is called when the mirror had to be rebuilt, after the new tree is already in place. Rebuilding is automatic; this exists to tell a user why their expanded nodes collapsed.

The reason is one of "documentReplaced", "overflow", "rendererGone", "slowReader" or "manual", and is worth treating as an open set.

DomSnapshot is the opening snapshot: the main frame's document. Child frames are not in it — their documents are fetched by expanding the <iframe> elements that host them, which is also what starts mirroring them.

Fields
RootstringRoot is the main frame's document as CDP DOM.Node-shaped JSON, the same format GetDOM returns.
FrameIdstringFrameId is the page's main frame.
Sequint64Seq is the page sequence this snapshot is the baseline for. Every update after it carries a higher one.

ElementRef 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.

Fields
BackendNodeIdint32BackendNodeId is the element's stable backend node id.
TagNamestringTagName is the upper-case tag name, e.g. "INPUT", "BUTTON", "DIV".
IdstringId is the id attribute, if present.
NamestringName is the name attribute, if present.
ClassNamestringClassName is the class attribute, if present.
InputTypestringInputType is the <input> type, if the element is an <input>.
TextstringText is a whitespace-collapsed textContent/value snippet (max 120 chars).
EditableboolEditable is true when the element is itself an editable text sink (input / textarea / contenteditable).

HeaderModification is one entry passed to CloudBrowser.ModifyRequest. Build it as a plain struct literal.

Fields
ActionHeaderModificationActionAction selects what happens: HeaderModificationAdd inserts a new header, HeaderModificationEdit replaces an existing header's value, HeaderModificationRemove drops the header.
NamestringName is the header name the action applies to.
ValuestringValue is the header value for add/edit; ignored for remove.
BeforestringBefore positions an "add" immediately before the named existing header; otherwise the header is appended at the end. Ignored for edit/remove.
AfterstringAfter positions an "add" immediately after the named existing header. Mirror of Before; ignored for edit/remove.
type HeaderModificationAction = string

HeaderModificationAction is the verb of a HeaderModification. Matches the add/edit/remove action strings; use the HeaderModificationXxx constants.

IceServer is one entry for a WebRTC RTCPeerConnection's ICE configuration: a TURN (or STUN) URL plus the short-lived credentials to authenticate with it. Pass these to your peer before creating the SDP offer.

Fields
URLs[]stringURLs are the ICE server URLs (e.g. "turn:relay.example.com:3478?transport=udp").
UsernamestringUsername is the short-lived TURN REST username (empty for plain STUN).
CredentialstringCredential is the short-lived TURN REST credential (empty for plain STUN).

InterceptedRequest describes an outgoing request captured by CloudBrowser.WaitForAnyRequest.

Fields
Methodstring
Urlstring
Headers[]Header
Bodystring
ResourceTypestring

NetworkBodies

type alias
type NetworkBodies = string

NetworkBodies selects which response bodies network capture keeps. Kept bodies are not part of the exchange; read them with CloudBrowser.ReadNetworkBody.

NetworkBodyRange is one range of a captured body, as returned by CloudBrowser.ReadNetworkBodyRange.

Fields
Data[]byteData holds the bytes read; empty past the end of the body.
TotalSizeint64TotalSize is the number of bytes kept for the body as a whole.
TruncatedboolTruncated matches the exchange's truncated flag for this body.

NetworkExchange is one request together with the response it received, as reported by CloudBrowser.CaptureNetwork.

A redirect chain arrives as one exchange per hop: the hops share ChainId and count up RedirectIndex, so a 302 and the request it points at are two exchanges, each with its own headers and status.

Fields
RequestIdstringRequestId is unique per hop.
ChainIdstringChainId is shared by every hop of one redirect chain.
RedirectIndexint32RedirectIndex is 0 for the original request and counts up once per redirect followed.
FrameIdstringFrameId is the frame that issued the request; empty for worker traffic.
IsOOPIFboolIsOOPIF reports whether that frame runs in its own process. Capture happens in the browser process, so cross-process iframes are included.
ResourceTypeNetworkResourceType
Methodstring
Urlstring
InitiatorUrlstringInitiatorUrl is the origin that started the request; empty when the browser itself did.
RequestHeaders[]Header
RequestHeadersAreWireboolRequestHeadersAreWire reports whether RequestHeaders are the bytes actually sent — Cookie, User-Agent and Sec-* included — rather than what the page asked for before the network stack filled in the rest.
RequestBodyIdstringRequestBodyId names the request body; read it with CloudBrowser.ReadNetworkBody. Empty when the request had no body. Bodies never travel with the exchange.
RequestBodySizeint64RequestBodySize is the number of bytes kept for the request body.
RequestBodyTruncatedboolRequestBodyTruncated reports that part of the request body is missing: it hit the per-body cap, or it was a file or streamed upload, which are not kept.
HasResponseboolHasResponse is false when the request failed before any response arrived; Error then says why.
StatusCodeint32
StatusTextstring
MimeTypestring
ProtocolstringProtocol is the negotiated ALPN protocol, e.g. "h2" or "http/1.1".
RemoteAddressstring
ServedFromNetworkServedFrom
ResponseHeaders[]Header
ResponseHeadersAreWirebool
ResponseBodyIdstringResponseBodyId names the response body; read it with CloudBrowser.ReadNetworkBody. Empty when body capture did not apply to this exchange — see NetworkCaptureOptions.Bodies.
ResponseBodySizeint64ResponseBodySize is the number of bytes kept for the response body, after content decoding.
ResponseBodyTruncatedboolResponseBodyTruncated reports that the kept body is shorter than the one the page received: it hit the per-body cap or the load ended early.
EncodedDataLengthint64
ErrorstringError is the net error name (e.g. "net::ERR_ABORTED"), empty on success.
type NetworkExchangeHandler = func(...)

NetworkExchangeHandler is called once per completed exchange.

Calls are sequential and in the order the browser finished the requests, so the hops of a redirect chain arrive in order and the handler needs no locking of its own. It runs on a goroutine the SDK owns, not the caller's.

Blocking here stalls the capture: the server buffers a bounded amount per reader and then drops its oldest entries, which NetworkCapture.Dropped reports. Hand slow work (disk, HTTP, a database) to another goroutine.

type NetworkResourceType = string

NetworkResourceType is the kind of load an exchange belongs to. It is a string rather than a closed enum so an exchange from a newer browser still round-trips instead of decoding to an empty value; compare against the NetworkResource* constants.

type NetworkServedFrom = string

NetworkServedFrom says where an exchange's response came from.

Rect

struct

Rect describes a position and size in CSS pixels.

Fields
Xfloat64
Yfloat64
Widthfloat64
Heightfloat64

RequestPattern 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.

Fields
URLstring
Abortbool

ScriptEvent is one item on a session's script event stream. Exactly one of Log and Finished is set.

Fields
RunIdstringRunId is the run that produced this event.
Log?*ScriptLogEntryLog is a console line the script printed.
Finished?*ScriptFinishedFinished marks the end of the run. No further event for that run follows.
type ScriptEventHandler = func(...)

ScriptEventHandler is called once per script event.

Calls are sequential and in the order the browser produced them, so a run's last log line always arrives before its Finished and the handler needs no locking of its own. It runs on a goroutine the SDK owns, not the caller's.

Blocking here stalls delivery: the server buffers a bounded number of events per reader and then drops its oldest, which ScriptRun.Dropped reports. Hand slow work to another goroutine.

ScriptLogEntry is one console.* call from a script.

Fields
LevelstringLevel is "info", "warning" or "error", from console.log / .warn / .error.
MessagestringMessage holds the logged arguments, already stringified the way console does it.
Timestamptime.TimeTimestamp is when the script printed the line, stamped in the browser.

SessionUsage is what a session's browser has consumed since the session started: the CPU time and memory of every process that rendered its pages — main frames, cross-site iframes and the workers they host — including processes that have since exited. Work done on the session's behalf in processes it shares with other sessions is not included.

CloudBrowser.GetUsage reports it while the session runs, and CloudBrowser.StopBrowser returns the final figures, so there is no need to read it right before stopping.

Fields
WallTimefloat64WallTime is the real time since the session's browser was created, in seconds.
CpuTimefloat64CpuTime is user plus kernel CPU time in seconds. Only time a thread actually ran on a core counts; waiting and idling do not.
MinMemoryint64MinMemory is the least memory the session held once its browser was ready, in bytes. Sampled about once a second.
AverageMemoryint64AverageMemory is the memory held, averaged over WallTime, in bytes; AverageMemory * WallTime is the memory-time used. Sampled about once a second, so short spikes count toward the peak but barely toward the average.
PeakMemoryint64PeakMemory is the most memory held at any one moment, in bytes.
RenderersUsedintRenderersUsed counts the renderer processes that hosted at least one of the session's frames: one per site its pages and cross-site iframes needed.
FramesCreatedintFramesCreated counts the child frames created in the session's pages, whether or not they got a process of their own.

StorageItem is a single localStorage key/value pair.

Fields
Keystring
Valuestring

StorageOriginEntry 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.

Fields
Originstring
Items[]StorageItem

WaitArg

interface

WaitArg is the marker interface for everything Wait accepts: a Locator (treated as a condition) or a wait-level option such as Timeout / InFrame / InAllFrames.

WaitConditionStatus 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.

Fields
Indexint32Index into the condition list this entry describes.
StatestringState is the last observed state: "not_found", "found_hidden", "found_occluded" (only when the condition required visibility), or "pending_steady".
BackendNodeIdint32BackendNodeId last seen for this condition (0 if never found).
FrameIdstringFrameId where it was last seen (empty if never found).
IsVisibleboolIsVisible reports whether it was CSS-visible at the last observation.
Bounds?*RectBounds is the last known rect in root-viewport coordinates (nil if never found).
Occluder?*OccluderInfoOccluder is the intercepting element, present iff State == "found_occluded".