API Reference

Give LLMs and agents a real browser they can see and control.

Base URL https://api.browserbeam.com
Auth Authorization: Bearer YOUR_API_KEY
Format JSON request and response bodies

Endpoints

Method Path Description
POST/v1/sessionsCreate a browser session
GET/v1/sessions/:idGet session info
POST/v1/sessions/:id/actExecute steps on a session
DELETE/v1/sessions/:idDestroy a session
GET/v1/sessionsList active sessions

Key concepts

Session — an isolated browser tab with its own cookies, storage, and viewport. Usage is billed in credits. Runtime, proxy bandwidth, AI tokens, and CAPTCHA solves all draw from a single credit pool.

Steps — sequential browser actions (click, fill, extract, etc.) sent as a JSON array. On failure, execution stops and the error is returned alongside current page state.

Refs — stable element identifiers (e1, e2, …) assigned during observation. Use refs to target elements in follow-up steps. Refs are reassigned on every observation — always use the refs from the most recent response.

Auto-observe — every successful call returns fresh page state automatically: content, interactive elements with refs, scroll position, and a diff of what changed.

Session lifecycle

POST /sessions Navigate Auto-observe
POST /act Steps Auto-observe ↺ repeat
DELETE /sessions/:id

Getting Started

Go from zero to your first browser session in under a minute. All you need is an API key.

1. Get your API key

Sign up at browserbeam.com and create an API key from the dashboard.

2. Create a session and navigate to a page

Open your terminal and run:

curl -X POST https://api.browserbeam.com/v1/sessions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

3. Read the response

The response includes the page content as markdown, interactive elements with refs, and scroll position:

201CreatedResponse
{
  "session_id": "ses_abc123",
  "expires_at": "2026-03-18T14:05:00Z",
  "request_id": "req_1a2b3c4d5e6f",
  "completed": 1,
  "page": {
    "url": "https://example.com",
    "title": "Example Domain",
    "stable": true,
    "markdown": {
      "content": "# Example Domain\n\nThis domain is for use in illustrative examples..."
    },
    "interactive_elements": [
      {"ref": "e1", "tag": "a", "role": "link", "label": "More information...", "in": "main"}
    ],
    "forms": [],
    "map": [
      {"section": "header", "selector": "header", "hint": "Example Domain (1 link)"},
      {"section": "main", "selector": "main", "hint": "Example Domain (1 link)"},
      {"section": "footer", "selector": "footer", "hint": "More information... (1 link)"}
    ],
    "changes": null,
    "scroll": {"y": 0, "height": 600, "viewport": 720, "percent": 100}
  },
  "media": [],
  "extraction": null,
  "blockers_dismissed": ["cookie_consent"],
  "error": null
}

4. Interact with the page

Use the element refs from the response to click, fill, or otherwise interact:

curl -X POST https://api.browserbeam.com/v1/sessions/ses_abc123/act \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"steps": [{"click": {"ref": "e1"}}]}'

5. Destroy the session

Always clean up when done. This frees resources and stops credit consumption:

curl -X DELETE https://api.browserbeam.com/v1/sessions/ses_abc123 \
  -H "Authorization: Bearer YOUR_API_KEY"

6. Next steps

→ Browse Step Types to see everything you can do (click, fill, extract, screenshot, etc.)

→ See Workflows for common patterns like login flows and data extraction

→ Read Element Targeting to understand refs, text, and label selectors

Authentication

Every request requires an API key in the Authorization header:

Authorization: Bearer YOUR_API_KEY

Get your API key from the dashboard.

Keep keys secret. Never expose API keys in client-side code, public repos, or logs. Use environment variables to store keys in your application.

Missing or invalid keys return 401:

401UnauthorizedResponse
{
  "error": {
    "code": "unauthorized",
    "message": "Invalid API key"
  }
}

POST /v1/sessions

Create a browser session. Optionally navigate to a URL and execute steps in the same call.

Parameters (all optional)

ParamTypeDefaultDescription
urlstringNavigate to this URL after creation
stepsarraySteps to execute after navigation
timeoutinteger300Session lifetime in seconds (10–1800)
viewportobject{1280, 720}{width, height}
user_agentstringautoCustom User-Agent string. When omitted, a realistic user agent is assigned automatically from a rotating pool.
localestringBrowser locale (e.g. en-US)
timezonestringTimezone (e.g. America/New_York)
proxyobject | stringdatacenter, autoAll sessions are routed through a proxy. Datacenter is the default; use residential for sites that require it. Pass an object {"kind": "datacenter"|"residential", "country": "us"|"auto"} to customize, or a string URL to bring your own proxy (e.g. http://user:pass@proxy:8080).
Datacenter countries: br, cn, de, fr, gb, kr, nl, ro, sg, us, eu
Residential countries (151)
ad, ae, af, al, am, ao, ar, at, au, aw, az, ba, bd, be, bg, bh, bj, bn, bo, br, bs, bt, by, bz, ca, cf, ch, ci, cl, cm, cn, co, cr, cu, cy, cz, de, dj, dk, dm, do, dz, ec, ee, eg, es, et, eu, fi, fj, fr, gb, ge, gh, gm, gr, gt, hk, hn, hr, ht, hu, id, ie, il, in, iq, ir, is, it, jm, jo, jp, ke, kh, kr, kw, kz, la, lb, li, lk, lr, lt, lu, lv, ma, mc, md, me, mg, mk, ml, mm, mn, mr, mt, mu, mv, mx, my, mz, na, ng, nl, no, np, nz, om, pa, pe, ph, pk, pl, pr, pt, py, qa, ro, rs, ru, sa, sc, sd, se, sg, si, sk, sn, ss, td, tg, th, tm, tn, tr, tt, tw, tz, ua, ug, us, uy, uz, ve, vg, vn, ye, za, zm, zw
block_resourcesarray["image", "font"]Resource types to block. Allowed values: image, font, stylesheet, script. Media (video/audio) is always blocked. Pass [] to unblock images and fonts.
auto_dismiss_blockersbooleantrueAuto-dismiss cookie banners and popups
cookiesarrayArray of cookie objects to inject before navigation. Each requires name, value, and either domain or url. Optional: path, expires, httpOnly, secure, sameSite

Behavior

urlstepsResult
Bare session, no page loaded
setNavigate → auto-observe → page state returned
setsetNavigate → run steps → auto-observe
setRun steps (first should be goto)

Example — navigate to a page

curl -X POST https://api.browserbeam.com/v1/sessions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'
201CreatedResponse
{
  "session_id": "ses_abc123",
  "expires_at": "2026-03-18T14:05:00Z",
  "request_id": "req_1a2b3c4d5e6f",
  "completed": 1,
  "page": {
    "url": "https://example.com",
    "title": "Example Domain",
    "stable": true,
    "markdown": {
      "content": "# Example Domain\n\nThis domain is for use in illustrative examples..."
    },
    "interactive_elements": [
      {"ref": "e1", "tag": "a", "role": "link", "label": "More information...", "in": "main"}
    ],
    "forms": [],
    "map": [
      {"section": "header", "selector": "header", "hint": "Example Domain (1 link)"},
      {"section": "main", "selector": "main", "hint": "Example Domain (1 link)"},
      {"section": "footer", "selector": "footer", "hint": "More information... (1 link)"}
    ],
    "changes": null,
    "scroll": {"y": 0, "height": 600, "viewport": 720, "percent": 100}
  },
  "media": [],
  "extraction": null,
  "blockers_dismissed": ["cookie_consent"],
  "error": null
}

Example — navigate + steps

POST/v1/sessionsRequest
{
  "url": "https://example.com/login",
  "steps": [
    {
      "fill_form": {
        "fields": {"Email": "user@test.com", "Password": "secret"},
        "submit": true
      }
    },
    {"screenshot": {}},
    {"close": {}}
  ]
}

Example — custom options

POST/v1/sessionsRequest
{
  "url": "https://example.com",
  "timeout": 600,
  "viewport": {"width": 1920, "height": 1080},
  "locale": "en-US",
  "timezone": "America/New_York",
  "block_resources": [],
  "auto_dismiss_blockers": true
}

GET /v1/sessions/:id

Get session status and metadata.

Response fields

FieldTypeDescription
session_idstringSession identifier
statusstringactive, closed, or failed (fatal error — session cannot continue)
started_atstringISO 8601 creation timestamp
ended_atstring|nullISO 8601 end timestamp, or null if active
duration_secondsinteger|nullTotal runtime in seconds, or null if active
expires_atstringISO 8601 expiry timestamp
error_codestring|nullWhen status is failed, engine error code (e.g. access_denied)
error_messagestring|nullWhen status is failed, human-readable details
curl https://api.browserbeam.com/v1/sessions/ses_abc123 \
  -H "Authorization: Bearer YOUR_API_KEY"
200OKResponse
{
  "session_id": "ses_abc123",
  "status": "active",
  "started_at": "2026-03-18T13:55:00Z",
  "ended_at": null,
  "duration_seconds": null,
  "expires_at": "2026-03-18T14:00:00Z"
}

When the session ended with a fatal error (unsolvable block, 403, etc.):

{
  "session_id": "ses_abc123",
  "status": "failed",
  "started_at": "2026-03-18T13:55:00Z",
  "ended_at": "2026-03-18T13:56:20Z",
  "duration_seconds": 80,
  "expires_at": "2026-03-18T14:00:00Z",
  "error_code": "access_denied",
  "error_message": "Page returned HTTP 403 — access denied or geo-restricted"
}

POST /v1/sessions/:id/act

Execute steps on an existing session. Steps run sequentially. On failure, execution stops and the error is returned alongside current page state. Auto-observe runs at the end.

Request body

ParamTypeRequiredDescription
stepsarrayyesArray of step objects to execute

Each step is a JSON object with one key (the step type) and its params as the value. See Step Types for all available actions.

curl -X POST https://api.browserbeam.com/v1/sessions/ses_abc123/act \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "steps": [
      {"fill": {"ref": "e1", "value": "search query"}},
      {"click": {"ref": "e3"}},
      {"screenshot": {}}
    ]
  }'
200OKResponse
{
  "session_id": "ses_abc123",
  "expires_at": "2026-03-18T14:05:00Z",
  "request_id": "req_9c4b3dc2e5f6",
  "completed": 3,
  "page": {
    "url": "https://example.com/results?q=search+query",
    "title": "Search Results",
    "stable": true,
    "markdown": {"content": "# Search Results\n\n## 1. First result..."},
    "interactive_elements": [
      {"ref": "e1", "tag": "input", "role": "search", "label": "Search", "value": "search query", "in": "form", "form": "f1"},
      {"ref": "e2", "tag": "a", "role": "link", "label": "First result", "in": "main", "near": "Search Results"},
      {"ref": "e3", "tag": "a", "role": "link", "label": "Second result", "in": "main", "near": "Search Results"}
    ],
    "forms": [
      {"ref": "f1", "id": "search", "action": "/search", "method": "GET", "fields": ["e1"]}
    ],
    "changes": {
      "content_changed": true,
      "elements_added": [{"ref": "e2"}, {"ref": "e3"}],
      "elements_removed": []
    },
    "scroll": {"y": 0, "height": 3000, "viewport": 720, "percent": 24}
  },
  "media": [{"type": "screenshot", "format": "png", "data": "<base64>"}],
  "extraction": null,
  "blockers_dismissed": [],
  "error": null
}

DELETE /v1/sessions/:id

Destroy a session and release browser resources. Runtime is recorded for billing.

Always destroy sessions when done. This frees resources and stops credit consumption. Sessions also auto-expire based on their timeout.

Returns 204 No Content on success. Destroying an already-destroyed session returns 404.

curl -X DELETE https://api.browserbeam.com/v1/sessions/ses_abc123 \
  -H "Authorization: Bearer YOUR_API_KEY"
204No ContentResponse
# Empty response — session destroyed

GET /v1/sessions

List sessions for the authenticated API key. Supports cursor-based pagination and status filtering.

Query parameters

ParamTypeDefaultDescription
statusstringallactive, closed, or failed
limitinteger25Results per page (1–100)
afterstringCursor from next_cursor in previous response
curl "https://api.browserbeam.com/v1/sessions?status=active&limit=25" \
  -H "Authorization: Bearer YOUR_API_KEY"
200OKResponse
{
  "sessions": [
    {
      "session_id": "ses_abc123",
      "status": "active",
      "started_at": "2026-03-18T13:55:00Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Step Types

Each step is a JSON object with one key (the step type) and its params as the value. Send steps in the steps array of a create or act call.

Steps execute sequentially. On failure, execution stops and the error is returned. An auto-observe runs at the end of every call.

goto

Navigate to a URL. Waits for page load and stability checks.

ParamTypeRequiredDefaultDescription
urlstringyesURL to navigate to
wait_forstringnoCSS selector to wait for after navigation
wait_untilstringnoJavaScript expression to wait for (must become truthy)
wait_timeoutintegerno10000Max ms to wait for wait_for / wait_until
{"goto": {"url": "https://example.com"}}

{"goto": {"url": "https://example.com", "wait_for": "#main-content", "wait_timeout": 15000}}

{"goto": {"url": "https://example.com", "wait_until": "window.__APP_READY === true", "wait_timeout": 10000}}

On failure (DNS error, timeout, SSL), returns error code navigation_failed.

observe

Force a page observation. Auto-observe runs at the end of every call, so explicit observe is only needed to change format or scope mid-pipeline.

ParamTypeRequiredDefaultDescription
formatstringnomarkdownmarkdown or html
modestringnomainmain returns main content area. full returns all page sections (nav, aside, footer, etc.) organized by region headers.
include_page_mapbooleannofalseInclude a lightweight section map (page.map) showing available page regions with hints. Auto-included on the first observe in a session.
scopestringnoCSS selector to limit observation
include_linksbooleannofalseInclude links as interactive elements
max_text_lengthintegerno12000Content length limit (default 20000 for mode: "full")
{"observe": {}}

{"observe": {"format": "html"}}

{"observe": {"scope": "#content", "include_links": true}}

{"observe": {"mode": "full", "max_text_length": 20000}}

{"observe": {"include_page_map": true}}

click

Click an element. Exactly one targeting param required (see Element Targeting).

ParamTypeRequiredDescription
ref / text / labelstringone requiredElement targeting (see below)
{"click": {"ref": "e3"}}

{"click": {"text": "Submit"}}

{"click": {"label": "Sign in"}}

fill

Clear and replace the value of an input. For character-by-character typing, use type instead.

ParamTypeRequiredDescription
ref / text / labelstringone requiredElement targeting
valuestringyesValue to fill
{"fill": {"ref": "e1", "value": "hello world"}}

{"fill": {"label": "Email", "value": "user@example.com"}}

type

Type character-by-character with a delay. Use for autocomplete and search-as-you-type inputs.

ParamTypeRequiredDefaultDescription
ref / text / labelstringone requiredElement targeting
valuestringyesText to type
delayintegerno50Milliseconds between keystrokes
{"type": {"label": "Search", "value": "browserbeam api", "delay": 100}}

select

Select an option from a <select> dropdown.

ParamTypeRequiredDescription
ref / text / labelstringone requiredElement targeting
valuestringyesOption value to select
{"select": {"label": "Country", "value": "US"}}

{"select": {"ref": "e4", "value": "option_value"}}

check

Check or uncheck a checkbox/radio button.

ParamTypeRequiredDefaultDescription
ref / text / labelstringone requiredElement targeting
checkedbooleannotruefalse to uncheck
{"check": {"label": "Remember me"}}

{"check": {"label": "Terms", "checked": false}}

scroll

Scroll the page or scroll an element into view.

ParamTypeRequiredDefaultDescription
tostringone of to/direction/refbottom or top
directionstringup or down
amountintegerno500Pixels per scroll step
timesintegerno1Repeat scroll N times
{"scroll": {"to": "bottom"}}

{"scroll": {"direction": "down", "amount": 500, "times": 3}}

{"scroll": {"ref": "e6"}}

scroll_collect

Scroll through the entire page, wait for lazy-loaded content at each position, and return a unified observation. Ideal for infinite scroll and long pages.

ParamTypeRequiredDefaultDescription
max_scrollsintegerno50Safety limit on scroll iterations
wait_msintegerno500Pause between scrolls (ms)
timeout_msintegerno60000Total time budget (ms)
max_text_lengthintegerno100000Content length limit
{"scroll_collect": {}}

{"scroll_collect": {"max_scrolls": 30, "max_text_length": 50000}}

screenshot

Capture a screenshot. Base64 data appears in the media array with type: "screenshot".

ParamTypeRequiredDefaultDescription
full_pagebooleannofalseFull scrollable page
selectorstringnoCSS selector to screenshot a specific element
formatstringnopngpng or jpeg
qualityintegerno80JPEG quality (1–100)
{"screenshot": {}}

{"screenshot": {"full_page": true, "format": "jpeg", "quality": 80}}

{"screenshot": {"selector": "#chart"}}

wait

Wait for a condition. Exactly one of ms, selector, text, or until is required.

{"wait": {"ms": 2000}}

{"wait": {"selector": "#results", "timeout": 10000}}

{"wait": {"text": "Loading complete", "timeout": 5000}}

// Wait for a JS expression to become truthy
{"wait": {"until": "document.querySelectorAll('.item').length >= 10", "timeout": 15000}}

extract

Structured data extraction. Keys are your field names, values are CSS/XPath selectors. Results appear in the extraction object of the response.

Selector syntax

// Pattern: "selector >> function"
// Functions: text, href (any attr), json, or omit for raw HTML

"title":      "h1 >> text"
"link":       "a.main >> href"
"image":      "img.hero >> src"
"meta":       "meta[name=description] >> content"
"html_block": "div.content"

Arrays

// Wrap in [ ] to collect all matches
"all_links": ["a >> href"]
"headings":  ["h2 >> text"]

Repeating structures

// Use [{_parent}] for repeating items like product cards
"products": [
  {
    "_parent": ".product-card",
    "name":    "h2 >> text",
    "price":   ".price >> text",
    "url":     "a >> href"
  }
]

Tables

// Tables are auto-parsed into arrays using headers as keys
"people": "table.contacts"
// → [{"Name": "Alice", "Email": "alice@example.com"}, ...]

JavaScript expressions

// Use js >> prefix to run JavaScript in the browser
"count": "js >> document.querySelectorAll('.item').length"
"title": "js >> document.querySelector('h1').textContent.trim()"

AI-powered selectors

Use the ai >> prefix to describe an element in plain English. The engine resolves it to a real CSS selector via AI, caches it per user and domain, and reuses it on subsequent calls at zero additional cost.

// Mix AI selectors with regular CSS selectors in the same schema
"products": [
  {
    "_parent": "article.product_pod",
    "name":  "ai >> the product title",
    "price": "ai >> the price including currency symbol",
    "stock": ".instock >> text"
  }
]

AI selectors consume AI tokens (billed as credits). Once cached, subsequent calls reuse the resolved CSS selector for free. Use refresh_selectors: true inside the extract step to force re-resolution if a site's structure changes.

Full example

POST/v1/sessionsRequest
{
  "url": "https://example.com/products",
  "steps": [
    {
      "extract": {
        "page_title": "h1 >> text",
        "description": "meta[name=description] >> content",
        "nav_links": ["nav a >> text"],
        "articles": [
          {
            "_parent": ".article-card",
            "title": "h2 >> text",
            "url": "a >> href",
            "author": ".byline >> text"
          }
        ],
        "stats_table": "table.statistics"
      }
    },
    {"close": {}}
  ]
}
201CreatedResponse
{
  "session_id": "ses_xyz789",
  "completed": 2,
  "page": { "..." : "..." },
  "extraction": {
    "page_title": "Our Products",
    "description": "Browse our full catalog",
    "nav_links": ["Home", "Products", "About", "Contact"],
    "articles": [
      {"title": "Widget Pro", "url": "https://example.com/widget-pro", "author": "Jane"},
      {"title": "Gadget X", "url": "https://example.com/gadget-x", "author": "John"}
    ],
    "stats_table": [
      {"Product": "Widget Pro", "Sales": "1,234", "Rating": "4.8"},
      {"Product": "Gadget X", "Sales": "567", "Rating": "4.5"}
    ]
  },
  "media": [],
  "error": null
}

fill_form

Fill multiple form fields by label and optionally submit. Auto-detects field types (text, select, checkbox).

ParamTypeRequiredDefaultDescription
fieldsobjectyes{label: value} pairs
submitbooleannofalseAuto-click submit button
{
  "fill_form": {
    "fields": {
      "Email": "user@example.com",
      "Password": "secret",
      "Country": "US",
      "Remember me": true
    },
    "submit": true
  }
}

upload

Upload files to a file input. Downloads from provided URLs and attaches them.

ParamTypeRequiredDescription
ref / text / labelstringone requiredElement targeting
filesarrayyesArray of file URLs to download and attach
{"upload": {"ref": "e5", "files": ["https://example.com/doc.pdf"]}}

{"upload": {"label": "Resume", "files": ["https://example.com/resume.pdf"]}}

pdf

Generate a PDF of the current page. Base64 data in the media array with type: "pdf".

ParamTypeRequiredDefaultDescription
formatstringnoA4Paper size (A4, Letter, Legal)
landscapebooleannofalseLandscape orientation
print_backgroundbooleannotrueInclude backgrounds
scalenumberno1Scale factor (0.1–2)
marginobjectno{top, right, bottom, left} in CSS units
{"pdf": {}}

{"pdf": {"format": "A4", "landscape": true, "margin": {"top": "1cm", "bottom": "1cm"}}}

execute_js

Run custom JavaScript in the browser context. The return value is placed in the extraction object under the specified key.

ParamTypeRequiredDefaultDescription
codestringyesJavaScript code to execute. Use return to send values back
result_keystringnojs_resultKey name in the extraction object for the return value
timeoutintegerno10000Maximum execution time in milliseconds
// Get the page title
{"execute_js": {"code": "return document.title"}}

// Count elements on the page
{"execute_js": {"code": "return document.querySelectorAll('.product').length", "result_key": "product_count"}}

// Extract computed data
{"execute_js": {"code": "return { url: location.href, cookies: document.cookie, scrollY: window.scrollY }"}}

The code runs inside a new Function() wrapper, so use return to send values back. Execution is sandboxed within the page context — no access to Node.js APIs.

close

Destroy the session at the end of step execution. Must be the last step. Useful for fire-and-forget workflows.

{"close": {}}

Element Targeting

Steps that interact with elements (click, fill, type, select, check, scroll, upload) accept exactly one targeting param:

KeyExampleBest for
ref"ref": "e3"Known elements from prior observe — most precise
text"text": "Submit"Buttons and links by visible text
label"label": "Email"Input fields by label/placeholder/aria-label

Label matching checks (in order): aria-label, placeholder, associated <label>, name attribute, nearby text.

Ref stability: Refs are reassigned on every observation. After any step that changes the page (click, goto, fill_form with submit), the previous refs may no longer be valid. Always use the refs from the most recent response.

Response Format

Create and act calls return the same response structure.

FieldTypeDescription
session_idstringSession identifier
expires_atstringISO 8601 expiry timestamp
request_idstringUnique request ID for debugging (e.g. req_8f3a2b...)
completedintegerNumber of steps successfully executed
pageobject|nullCurrent page state (see below)
page.urlstringCurrent URL
page.titlestringPage title
page.stablebooleantrue when the page passed stability checks (network idle 300ms + DOM mutations quiet 500ms). If false, the page is still loading — consider adding a wait step.
page.markdownobject{content, length?} — page content as markdown
page.interactive_elementsarrayElements with refs and context: in (landmark), near (heading), form (parent form ref)
page.formsarrayForms with element associations: {ref, id, action, method, fields: [refs]}
page.maparray|undefinedLightweight section map: [{section, selector, hint}]. Auto-included on first observe; request again with include_page_map: true. Not included in mode: "full".
page.changesobject|nullDiff from previous observe. null on first.
page.scrollobject{y, height, viewport, percent}
mediaarray{type, format, data} objects. type: screenshot or pdf.
extractionobject|nullnull when no extract steps used. Otherwise, extraction results.
blockers_dismissedarrayAuto-dismissed blockers (e.g. cookie_consent)
errorobject|nullnull on success. On failure: error details.

Errors

All errors follow a consistent JSON format. On step failure, the response includes both the error and the current page state so you can decide what to do next:

200OK — with step errorResponse
{
  "completed": 1,
  "page": {
    "url": "https://example.com",
    "title": "Example Domain",
    "interactive_elements": ["..."]
  },
  "error": {
    "step": 1,
    "action": "click",
    "code": "element_not_found",
    "message": "No visible element found matching text \"Submit\"",
    "context": {}
  }
}

HTTP errors

StatusCodeWhen
401unauthorizedMissing or invalid API key
404session_not_foundSession doesn't exist or expired
429rate_limitedToo many requests
429quota_exceededCredit quota exhausted
503engine_unavailableBrowser engine temporarily down

Step error codes

CodeDescription
element_not_foundNo visible element matches the target
navigation_failedGoto failed (timeout, DNS, SSL, etc.)
captcha_detectedCAPTCHA detected on page
captcha_unsolvableUnsolvable bot/Vendor challenge (e.g. PerimeterX) — session is closed
access_deniedHTTP 403/451 or access blocked — session is closed
action_failedElement detached, intercepted, etc.
extract_failedExtraction step failed
invalid_requestUnknown step type or invalid params

Recovery patterns

ErrorWhat to do
element_not_foundRe-observe the page. Try label instead of ref, or use text matching. The page may have changed.
navigation_failedCheck URL scheme (must include https://). Retry with a longer wait_timeout. May be a DNS or SSL issue.
captcha_detectedTake a screenshot for human review. Consider using a proxy or rotating IP addresses.
captcha_unsolvableDo not retry the same target through automation. Use GET /v1/sessions/:id to read error_code / error_message. Choose a different URL, proxy, or flow.
access_deniedSite or geo blocks the session. Check HTTP status in the error, try another region/proxy, or a different page.
rate_limitedRead the Retry-After header. Use exponential backoff. Do not retry immediately.
quota_exceededYour plan's credits are exhausted. Top up or upgrade your plan, or wait for the next billing cycle.
engine_unavailableRetry after Retry-After seconds. If 3+ consecutive failures, check the status page.
session_not_foundSession expired or was destroyed. Create a new session and replay your steps.

Retry example

import time, requests

def call_with_retry(url, headers, json, max_retries=3):
    for attempt in range(max_retries):
        resp = requests.post(url, headers=headers, json=json)
        if resp.status_code == 429:
            wait = int(resp.headers.get("Retry-After", 2 ** attempt))
            time.sleep(wait)
            continue
        if resp.status_code == 503:
            time.sleep(2 ** attempt)
            continue
        return resp
    raise Exception(f"Failed after {max_retries} retries")

Rate Limits & Quotas

Usage is metered in credits. Runtime, proxy bandwidth, AI selector resolutions, and CAPTCHA solves all consume credits from a single pool. Limits depend on your plan.

Response headers

Every API response includes rate limit headers so you can track your quota:

HeaderDescription
X-RateLimit-LimitRequests allowed per minute
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when window resets
X-Request-IdUnique request ID for debugging
Retry-AfterSeconds to wait (on 429/503 responses)

Plans

PlanCredits / moConcurrentMax SessionRate Limit
Trial5,00015 min60 req/min
Starter500,000515 min600 req/min
Pro2,000,0005030 min1,200 req/min
Scale10,000,0001001 hour3,000 req/min

See Billing & Credits for credit rates and how each service is metered.

Workflows

Common patterns showing how to combine sessions and steps.

Explore then act — 2 calls

Get page state first, then use element refs to interact.

POST/v1/sessionsStep 1
{"url": "https://example.com"}
POST/v1/sessions/ses_abc123/actStep 2
{
  "steps": [
    {"fill": {"ref": "e1", "value": "search query"}},
    {"click": {"ref": "e3"}}
  ]
}

Login + screenshot — 1 call

Fill a login form, take a screenshot, destroy the session — all at once.

curl -X POST https://api.browserbeam.com/v1/sessions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/login",
    "steps": [
      {"fill_form": {"fields": {"Email": "user@test.com", "Password": "pass"}, "submit": true}},
      {"wait": {"ms": 2000}},
      {"screenshot": {"full_page": true}},
      {"close": {}}
    ]
  }'

Full-page scrape — 1 call

Scroll through the entire page, collecting all lazy-loaded content.

POST/v1/sessionsRequest
{
  "url": "https://example.com/long-article",
  "steps": [{"scroll_collect": {"max_text_length": 50000}}]
}

Structured extraction — 1 call

Extract structured data and close the session in one request.

POST/v1/sessionsRequest
{
  "url": "https://example.com/products",
  "steps": [
    {"extract": {"products": [{"_parent": ".product", "name": "h2 >> text", "price": ".price >> text", "url": "a >> href"}]}},
    {"close": {}}
  ]
}

PDF generation — 1 call

Generate a PDF and close the session.

POST/v1/sessionsRequest
{
  "url": "https://example.com/report",
  "steps": [{"pdf": {"format": "A4", "landscape": true}}, {"close": {}}]
}

Search + extract — 2 calls

Navigate, perform a search, then extract results.

POST/v1/sessionsStep 1
{
  "url": "https://example.com",
  "steps": [
    {"fill": {"label": "Search", "value": "browser automation"}},
    {"click": {"text": "Search"}}
  ]
}
POST/v1/sessions/ses_abc123/actStep 2
{
  "steps": [
    {"extract": {"results": [{"_parent": ".result", "title": "h3 >> text", "url": "a >> href"}]}},
    {"close": {}}
  ]
}

Building an LLM agent loop — N calls

The most common pattern for AI agents: create a session, observe, decide, act, repeat until done.

from browserbeam import Browserbeam

client = Browserbeam(api_key="YOUR_API_KEY")

# 1. Create session and navigate
session = client.sessions.create(url="https://example.com")

# 2. Agent loop: observe → decide → act
while True:
    page = session.page
    elements = page.interactive_elements

    # 3. Send page state to your LLM to decide next action
    next_steps = llm_decide(page.markdown.content, elements)

    if next_steps is None:
        break  # Goal reached

    # 4. Execute the steps
    session.act(next_steps)

    if session.error:
        print(f"Step failed: {session.error.message}")
        break

# 5. Clean up
client.sessions.destroy(session.session_id)

The key insight: every response includes fresh page state via auto-observe, so your LLM always has up-to-date content and element refs to decide its next action.

Give your AI agent a faster, leaner browser

Structured page data instead of raw HTML. Your agent processes less, decides faster, and costs less to run.

Stability detection built in
Fraction of the payload size
Diffs after every action
No credit card required. 5,000 free credits included.