Skip to content

Page reports API reference

Request and response shapes for the five inference-free report endpoints on a session: consent, agent view, destinations, cancellation and screenshot.

Last updated:

Five endpoints on a live session answer structural questions about a page without ever calling a model: which consent platform is showing and what the browser held before any choice, what the agent's tree looks like, where every control leads, whether a cancellation control is reachable, and a picture of the page. All five are POSTs against a session id carrying your bb_ key as a bearer token, and all five are computed from the same perception the agent runs on — which is why they still work on a deployment that has sessions and no inference gateway at all.

They arrived in protocol 1.5. A client that announces x-browserberg-protocol: 1.5.0 to an older server is refused with protocol_incompatible rather than discovering the gap route by route. A deployment that offers them lists reports in the features array of GET /v1/me; one that does not never registers the routes, so a call gets not_found.

Three failures are worth branching on. A body that fails validation is invalid_request (400) with the first ten schema issues in details.issues. A session that does not exist, or belongs to another organisation, is not_found (404) — the same answer for both, deliberately. A URL the browser refuses to open, for DNS, TLS or a blocked scheme, is navigation_failed (422). A page that simply never finishes loading is not a failure at all: after fifteen seconds the report is taken as the page stands and a line is added to warnings.

POST /v1/sessions/:id/consent-report

Which consent platform is showing, what the browser held before any choice, and what a reject changed.

POST /v1/sessions/:id/agent-view

The page as the agent reads it, rendered at up to three fidelities, with the interactive controls it found.

Agent view request

Name Type Description
url string Opened first, as above. Omit it for the page the session is on.
fidelities string[] One to three of `full`, `economy` and `lean`. Every entry renders the SAME tree; only how much is elided differs, so the element ids match across renderings. Default: [full, economy, lean]
screenshot boolean Adds a viewport JPEG at quality 60. Default: true
maxChars integer 1000 to 400000, a ceiling applied to each rendered view separately. Truncation is announced in `views[].truncated`, never silent.
consent string `reject`, `accept` or `off` — how a banner is handled before the page is read. Default: reject

Agent view response

Name Type Description
url string The page that was read.
views array One entry per requested fidelity: `{fidelity, text, chars, lines, truncated}`.
controls array One entry per interactive element, without its subtree: `{encodedId, role, name, tag, jsClickable, hasAccessibleName}`. Enough to judge whether a page is legible, and not enough to rebuild it.
stats object `{rawNodes, keptNodes, frames, occluded, offscreen, warnings}` — how much of the page survived pruning, and why.
world string `extension` or `cdp-fallback`: which execution world did the reading.
consentDismissed boolean Whether a banner was actually cleared before the tree was captured.
screenshot object Present unless you set `screenshot` to false.
warnings string[] The navigation's warnings and the page preparation's, concatenated.
durationMs integer Wall-clock time for the whole call.

Reading the controls array

jsClickable marks an element that has no interactive role of its own and is clickable only because a script listens on it — common on portals built out of styled divs. hasAccessibleName is false for a control neither an agent nor a screen reader can address by name, which is usually the single most useful number on the page: an interactive surface where half the buttons are nameless is one an agent will struggle with for reasons that have nothing to do with the model.

The rendered text is page content. Treat it as untrusted and fence it before it enters another prompt, exactly as you would the tree that comes back from observe.

POST /v1/sessions/:id/destination-report

Resolves, in the page, where every link, button and form actually leads, and how the destination guard would judge each one.

Destination report request

Name Type Description
url string Opened first. Omit it for the page the session is on.
limit integer How many controls to resolve, in document order, 1 to 500. When more existed, `truncated` is true. Default: 200
consent string `reject`, `accept` or `off`. A banner left standing hides the controls behind it. Default: reject

Destination report response

Name Type Description
url string The page the census was taken on.
anchorSite string | null The page's own registrable site — what `sameSite` is measured against.
secure boolean The page itself was served over https.
controls array `{encodedId, role, name, action, destination, site, sameSite, risk, blockedUnderDefault, blockedUnderStrict}`, one per resolved control.
summary object `{total, sameSite, offSite, offSiteSubmit, insecureSubmit, unsafeScheme, scriptOnly, unresolved}` — the counts most callers actually branch on.
truncated boolean More controls existed than `limit` allowed.
warnings string[] Navigation and page-preparation warnings.
durationMs integer Wall-clock time for the whole call.

How one control is judged

action is what an agent would do with the element — click, type, select or scroll — decided from its role and tag, never from an instruction. destination is {url, via, method?, target?, hasFileInput?, unresolved?}, and via records how the target was found: href, ancestor-href, formaction, form, implicit-submit, script when only code knows where it goes, or none when nothing was found at all.

risk is the destination guard's finding for that one control, judged on its own. The guard normally stops at the first blocked step of a plan, which is right for a plan and wrong for a census, so each control is run through it separately. off_site_submit, insecure_submit and unsafe_scheme are refused under the default policy and set blockedUnderDefault; off_site_navigation is permitted by default — an SSO redirect leaves the site legitimately — and sets only blockedUnderStrict. A script-scheme href is not a risk at all: legacy portals write one on every grid link, so the guard leaves it alone and the report says only what it saw.

POST /v1/sessions/:id/cancellation-report

Looks for a control labelled like a cancellation on a start page, resolves where it leads, and describes the page behind it.

Cancellation report request

Name Type Description
url required string The page a consumer would start from. Required, because the question this report answers is reachability from here.
consent string `reject`, `accept` or `off`. Default: reject
follow boolean Open the best candidate's resolved target and describe it. The control is never clicked and no form is ever submitted; the target URL is opened directly. Default: true
screenshot boolean Captures the start page, and the followed page too when one was followed. Viewport JPEG at quality 60. Default: true

Cancellation report response

Name Type Description
url string The start page you asked for.
finalUrl string Where that page ended up after redirects.
candidates array `{encodedId, role, name, matchedPhrase, destination, site, sameSite}`. `matchedPhrase` is the entry from the product's cancellation vocabulary that the label matched, so a reader can see exactly why a control was picked out.
followed object | null `{encodedId, targetUrl, confirmationControls, fields, screenshot?}`, or null when nothing was followed.
screenshot object The start page, when you asked for pictures.
warnings string[] Says when no candidate was found, and when candidates existed but none could be followed.
durationMs integer Wall-clock time for the whole call, both pages included.

What follow actually does

The candidate that gets followed is the first one whose destination has a URL and does not lead to another registrable site. A candidate whose target only a script knows cannot be followed without pressing it, and pressing a cancellation unattended is exactly what the product refuses to do — so it is skipped and a warning says why. followed is therefore null in four different situations: no candidate was found, follow was false, every candidate led off-site or was script-only, or opening the target failed.

When a page was followed, confirmationControls lists the buttons and links on it whose label reads like the confirming press — the cancellation vocabulary again, plus the ordinary confirm and submit words in German and English. fields lists what the page asks for as {role, name, required}, where required is null when the page said nothing either way. That is the interesting half for a consumer question: a cancellation reachable in one click that then demands a customer number is a different experience from one that does not.

POST /v1/sessions/:id/screenshot

A picture of the page after the consent banner has been handled, viewport or whole document.

Screenshot request

Name Type Description
url string Opened first. Omit it to capture the page the session is on.
format string `jpeg` or `png`. JPEG is the default because nobody reads the pixels and a full-page portal capture is megabytes as PNG. Default: jpeg
quality integer 1 to 100. JPEG only; ignored for PNG. Default: 60
fullPage boolean Capture the whole document rather than the viewport. The height is taken from the page's layout metrics and cut at 16384 CSS pixels, because a 200000-pixel capture is not a screenshot. Default: false
consent string `reject`, `accept` or `off`. Only `off` skips the dismissal entirely and leaves the banner in the picture. Default: reject
waitMs integer Extra settling time after the load, 0 to 15000, for a page that paints late. The network is then given up to 1.5 s to go quiet regardless. Default: 0

Screenshot response

Name Type Description
url string The page that was captured.
contentType string `image/jpeg` or `image/png`.
base64 string The image bytes, base64-encoded, so a report stays one JSON document a caller can keep.
width integer Capture width in CSS pixels.
height integer Capture height in CSS pixels, after the full-page cut.
fullPage boolean Echoes what was asked for.
consentDismissed boolean Whether a banner was actually cleared before the shutter.
durationMs integer Wall-clock time for the whole call.

Note · Observations, never verdicts

The consent report says which cookies were set before a choice was offered. It does not say a site is compliant, and no field on the wire carries a grade. The cancellation report says whether a control labelled like a cancellation was found, where it led and what the page behind it asked for; it does not say a legal requirement is satisfied. The judgement belongs to whoever reads the report, and a shape that carried a verdict would be quoted as one.

Two reports on one session

One session, two reports, no inference. The cURL variant shows the raw wire shape; the SDKs return the same document parsed.

Requires: api-key

BASE="https://browserberg.com"
AUTH="Authorization: Bearer $BROWSERBERG_API_KEY"
JSON="Content-Type: application/json"

ID=$(curl -s -X POST "$BASE/v1/sessions" -H "$AUTH" -H "$JSON" -d '{"ttlSeconds": 180}' \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["session"]["id"])')

# No model call: the report is computed from the page, so it costs browser time only.
curl -s -X POST "$BASE/v1/sessions/$ID/consent-report" -H "$AUTH" -H "$JSON" -d '{
  "url": "https://shop.example.com/", "policy": "reject", "waitMs": 5000
}' | python3 -c 'import json,sys; r = json.load(sys.stdin); print(json.dumps({
      "cmp": r["cmp"],
      "bannerDetectedAtMs": r["bannerDetectedAtMs"],
      "summary": r["summary"]}, indent=2))'

curl -s -X DELETE "$BASE/v1/sessions/$ID" -H "$AUTH" > /dev/null

Keep going

  • Consent and destination reports The same five endpoints as a task, end to end
  • Consent autopilot How a banner is recognised and cleared
  • Session verbs The model-backed half: observe, act, extract
  • Errors and retries The envelope every failure above shares