Docs
Agents and SDKs

Browser sessions

Give an agent a persistent browser, connect over CDP, and watch or take control.

A browser session keeps one headful Chrome open while your agent navigates, fills forms, and downloads files. Use the action API, MCP tools, or a CDP client. These connections share the same tabs. Use the same workspace API key as the rest of Berrycrawl.

Use the dashboard

Open Browser sessions. The Browser section in the sidebar keeps sessions, agent tasks, profiles, and recordings together. On smaller screens, use the workspace tabs or the sidebar menu.

  • Sessions: search all sessions by ID, filter by status, start time, or a key:value tag, and page through older sessions. Filters stay in the URL. Live rows show the time left and can copy a fresh CDP URL or close the browser; Close all closes every live browser after one confirmation. Background refreshes update rows in place and keep the last successful results visible if a request fails. New browser sets the connection and exit country, duration and idle timeouts, video recording, tags, viewport, resource blocking, a saved profile, and an explicit credit limit. Matching cURL, JavaScript and Python requests are shown beside the form. The playground keeps its separate five-minute direct trial.
  • Live view: opens automatically once a session is ready. The viewer works like a browser: tabs with titles, back, forward, reload, and an address bar that takes URLs or searches. These controls work while you hold control. Take control pauses agent actions; Release control returns to watching. Use Fullscreen for more room or New tab for a standalone viewer; Reconnect issues a fresh ten-minute viewer link. Hiding the view or closing its tab does not stop the billable browser: use Close session. Connect & settings can mint and copy a ten-minute CDP URL. Keep these capability URLs private.
  • Recording: sessions started with Record video save a WebM video of each tab when the browser closes. Watch or download it from the session's Recording tab for seven days.
  • Profiles: create a named profile, choose Set up login, open the viewer and sign in with human control. Close & save profile saves the encrypted login state. Later sessions can reuse it; turn on Save profile changes on close only when you want to update that profile. A saved profile keeps its existing country and connection route. Tasks reuse profiles without saving login changes back automatically.
  • Agent tasks: create a task with a goal and start URL or attach a ready browser. Set credit and step limits; advanced controls include model presets, additional allowed origins, an output schema and a completion webhook. Button/form permissions start off. A task that stops before such an action shows Needs confirmation and its pending step; it is not silently resumed. Review completed steps before starting another task. Results link to the browser and its files.
  • Recordings: save a session's supported action journal or an agent task, then replay it with required variables and a credit limit. Healing and button/form permissions start off. Run history shows status, output, changes from the previous successful run, steps and usage. A healed candidate becomes a new recording only when you explicitly save it. Recordings are action recipes, not videos; manual viewer clicks and arbitrary CDP interactions are not converted into saved steps.

The Files tab lists uploads and downloads, supports uploads up to 10 MiB, and obtains a fresh private download link when selected. Files expire after seven days. For persistent documents, import the downloaded artifact into your own file or document system before expiry.

New session, task and replay requests are not retried automatically. If a response is lost, check history before starting another run: the first request may already have been accepted and billed. Berrycrawl does not schedule tasks; a scheduler such as Berry Chat must call the existing API or MCP tools and import resulting files. This dashboard does not configure Berry Chat's integration.

Credits and limits

Time costs 1 credit per started minute, from ready until close, with a one-minute minimum. Proxied traffic costs 6 credits per decimal MB, counting uploads and downloads at the proxy. Direct traffic and traffic through your own proxy are included, up to 2 GB per session. Actions, live view, files, and profiles have no separate fee. AI extraction and hosted-task tokens are currently recorded without an additional token charge. A page blocked by a site still consumes time and traffic. Startup failures are free; a lost runner settles known counters.

ExampleCredits
One minute, direct, 3 MB1
One minute, proxied, 3 MB19
Ten minutes, proxied, 40 MB250
Ten minutes, direct10

Set max_credits to cap a session's bill. Credit holds reserve small portions of your balance and release unused credits at close. A session may stop when its available credit authorization ends. Time and proxy components round up separately at final settlement. Media and fonts are blocked by default; also block images when you do not need them to reduce traffic.

Free accounts and the dashboard playground support direct sessions for up to five minutes. Proxies require a paid tier. Session concurrency is 1/2/5/10/25/100 for Free/Starter/Developer/Pro/Business/Enterprise. Paid sessions run up to one hour, defaulting to fifteen minutes. Keepalive/status requests can refresh activity; use explicit close when finished.

Create and close

curl https://api.berrycrawl.com/api/v1/browser/sessions \
  -H "Authorization: Bearer $BERRYCRAWL_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"proxy":"auto","start_url":"https://example.com","max_credits":50}'

The response envelope's data contains id, state, cdp_url, live_view_url, expires_at, route, and cumulative usage. Keep the returned connection URLs private. To close, send DELETE /api/v1/browser/sessions/{id} with your bearer key. Closing is idempotent. Disconnecting a CDP client leaves the session running and billable.

proxy accepts none, datacenter, residential, auto, or custom (your own proxy, see below). Auto can escalate before the first successful navigation; it then keeps its route to preserve login state. country uses a two-letter country code. Saved profiles reuse their pinned country and route.

Connect over CDP

Playwright 1.64 supports noDefaults, which is required because Berrycrawl owns download behavior:

import { chromium } from "playwright";
const browser = await chromium.connectOverCDP(session.cdp_url, { noDefaults: true });
const context = browser.contexts()[0];
const page = context.pages()[0] ?? await context.newPage();
await page.goto("https://example.com");
await browser.close(); // disconnect; close the Berrycrawl session separately

Puppeteer uses its normal connection:

import puppeteer from "puppeteer-core";
const browser = await puppeteer.connect({ browserWSEndpoint: session.cdp_url });
const [page] = await browser.pages();
await page.goto("https://example.com");
browser.disconnect();

Browser Use accepts a remote CDP URL:

from browser_use import Browser
browser = Browser(cdp_url=session["cdp_url"])

Stagehand v3 accepts one in its local configuration:

import { Stagehand } from "@browserbasehq/stagehand";
const stagehand = new Stagehand({
  env: "LOCAL",
  localBrowserLaunchOptions: { cdpUrl: session.cdp_url },
});
await stagehand.init();

Follow Browser Use's remote-browser guide and Stagehand's browser configuration for the installed client version. Browser Use and Stagehand examples describe connection configuration; their complete agent flows have not yet been benchmarked against this preview. Some client versions try to configure downloads or browser-wide settings at initialization and will receive a CDP error. Stock Puppeteer and Playwright with noDefaults have been checked sequentially on the same tab. Simultaneous auto-attaching clients can interfere with target discovery; use one driver at a time.

Berrycrawl uses Patchright for its own driver. A raw CDP client's own instrumentation can affect stealth. Browser termination, download relocation, proxy changes, extensions, runner-local file access, and privileged browser commands are refused. Use the file and upload APIs for files. CDP allows five clients per session, 16 MiB messages, and 30-second heartbeat checks.

Action API and MCP

curl "https://api.berrycrawl.com/api/v1/browser/sessions/$SESSION_ID/actions" \
  -H "Authorization: Bearer $BERRYCRAWL_API_KEY" -H 'Content-Type: application/json' \
  -d '{"actions":[{"type":"snapshot","max_chars":16000}]}'

Snapshots return opaque element refs. Pass a fresh ref to click, write, select, hover, or drag; refs expire after navigation. Selectors and coordinates are also supported. Actions include navigate, back, forward, reload, snapshot, click, write, press, select, hover, drag, scroll, wait, screenshot, scrape, extract, pdf, tabs, upload, dialog, cookies, and evaluate. {"type":"wait","download":true} waits up to 30 seconds for a download started earlier in the batch and returns its file. cookies reads (op: "get"), sets, or clears the browser's cookies. Failed actions return the browser's reason in error.message, except for sensitive write actions.

Every action that works in a page also accepts a tab_id from tabs or a response's tabs list. The action runs in that tab without switching to it, and the active tab is unchanged. Omit tab_id to use the active tab. Refs belong to the tab whose snapshot issued them. An unknown or closed tab fails with INVALID_TAB. dialog, cookies and download waits cover the whole session and take no tab_id.

evaluate runs expression in the page's main world, so it sees the page's own globals and framework state. Promises are awaited. An expression gets 10 seconds; Chrome stops synchronous code at that point and the action fails with ACTION_TIMEOUT. The result must be JSON of at most 100 KB, otherwise RESULT_TOO_LARGE. undefined, NaN and Infinity return null, and DOM nodes, dates and functions return {}, so convert them in the expression. A thrown error's first line is returned in error.message. Page scripts can observe and alter main-world code, so do not put secrets in an expression. Batches accept 1–25 actions, with a default 30-second timeout and maximum 60 seconds. A session runs one action batch at a time. Human control returns 423 HUMAN_CONTROL_ACTIVE for agent actions.

MCP exposes berrycrawl_browser_open, navigate, snapshot, click, type, press, scroll, screenshot, read, tabs, files, act, and close (each with the berrycrawl_browser_ prefix). navigate, snapshot, click, type, press, scroll, screenshot and read accept tab_id; their fresh snapshot comes from the same tab. Use act for other actions, including evaluate. files with a file_id and content: true returns a downloaded file of up to 2 MB: text as UTF-8, images as an image, other files as base64. MCP responses exclude connection credentials. The returned human viewer link opens the authenticated dashboard. See the MCP guide.

No CAPTCHA solver is offered. A CAPTCHA or site block is reported to the agent; a person can open the live viewer and clear it using Take control.

Live view and take-over

Mint a live_view or live_control token with POST /browser/sessions/{id}/tokens { "scope": "live_control", "ttl_seconds": 600 }. The returned HTTPS url opens the viewer. It can also be embedded:

<iframe title="Browser session" src="PRIVATE_VIEWER_URL"
  referrerpolicy="no-referrer" sandbox="allow-scripts allow-same-origin"></iframe>

The viewer shows JPEG frames, tabs, and explicit Take control / Release controls. Viewing alone cannot send input. Only one person holds control. Closing or revoking tokens disconnects existing clients. View and control WebSockets use /browser/sessions/{id}/live/stream; CDP uses /browser/sessions/{id}/cdp. These paths include the /api/v1 prefix in production.

The URLs carry short-lived capability tokens. Do not put them in logs, analytics, or shared pages. Authorization headers are preferred where supported: Authorization: Bearer TOKEN, then x-berrycrawl-token, then the URL query. A supplied invalid header does not fall back to a query. Maintenance drain closes WebSockets with 4001; ordinary session close uses 4409.

Connections, tags, and history

proxy: "auto" (the default on paid plans) starts each site direct and moves to datacenter, then residential, only when that site is blocked or the connection fails. Berrycrawl remembers the connection each site needed for the rest of the session; DNS failures never escalate. country picks the proxy exit country. The free tier defaults to proxy: "none". Responses report the connection type actually used in route.

Your own proxy

Pass proxy_url to send every request through a proxy you run or rent. proxy may be omitted or set to custom; any other mode with proxy_url is rejected.

curl https://api.berrycrawl.com/api/v1/browser/sessions \
  -H "Authorization: Bearer $BERRYCRAWL_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"proxy_url":"socks5://USERNAME:PASSWORD@proxy.example.com:1080","country":"DE"}'
  • Schemes are http://, https:// and socks5://, with optional user:password@ (percent-encode special characters; each part is at most 255 bytes). Default ports are 80, 443 and 1080. Other ports must be 1024 or higher.
  • The host must be public. Private, loopback, link-local, internal names and addresses, and names that resolve to them are refused with 403 PROXY_HOST_BLOCKED; the runner checks again on every connection. A malformed URL returns 400 INVALID_PROXY_URL.
  • Berrycrawl resolves each site's address and asks your proxy to connect to that IP on port 80 or 443. An https:// proxy needs a publicly trusted certificate for its hostname.
  • Traffic through your proxy has no per-MB fee. It appears in usage.direct_bytes and counts toward the 2 GB per-session cap. Session time is billed as usual. Custom proxies need a paid plan.
  • The URL is used only to start the browser. Berrycrawl does not store it, return it, or log it. Responses report proxy: "custom" and route: "custom".
  • country only sets the browser's language and timezone; your proxy decides where traffic exits.
  • A saved profile used with a custom proxy stays pinned to one: later sessions with that profile must pass proxy_url again (409 PROFILE_ROUTE_MISMATCH otherwise). Recordings made from a custom-proxy session replay without a proxy, and hosted tasks cannot open one, though a task can attach to a running custom-proxy session with session_id.
  • 503 CUSTOM_PROXY_UNAVAILABLE means custom proxies are temporarily turned off; retry later or use a managed proxy.

Pass up to ten string tags as metadata, for example {"user":"u_123","chat":"c_42"}, then list sessions with GET /browser/sessions?tag=user:u_123. The list also accepts q (part of a session ID), created_after, created_before (ISO 8601), and state. Each session reports created_at, closed_at, proxy, country, record, and metadata.

record: true saves a WebM video of each tab as a session file with kind: "recording" when the browser closes. idle_timeout_seconds counts actions, navigation, CDP traffic, and live-view input; reading a session does not keep it open.

Private files and saved logins

GET /browser/sessions/{id}/files lists files even after a session closes. GET /browser/files/{fileId} returns metadata and a fresh, object-scoped download URL lasting fifteen minutes. DELETE /browser/files/{fileId} deletes it. Files expire after seven days. Downloads are capped at 100 MB per file and 500 MB total per session. Oversized downloads are cancelled with FILE_TOO_LARGE. Screenshots and PDFs have a 25 MB generation cap.

Upload up to 10 MiB (10,485,760 bytes) using POST /browser/sessions/{id}/files with { "name": "report.csv", "content_base64": "..." }. Pass its file id to an upload action with a file-input selector. Runner paths are never exposed. Private file links use attachment disposition and are not served from the public asset CDN.

Create a profile with POST /browser/profiles { "name": "Reports login" }, then create a session with profile: { id: "bprof_...", persist: true }. Close after logging in to save it. A later session with that profile restores cookies, local storage, and IndexedDB. API profile endpoints return metadata and cookie domains, never saved values. State is encrypted; three versions are retained. There are twenty profiles per account and a 5 MB version limit. Lost runners do not save profiles. Deleting a profile also prevents an already-running session from saving into it.

Errors and generated clients

ErrorHandling
NO_BROWSER_CAPACITY / 503Retry after the response's delay.
BROWSER_SESSIONS_DRAINING / 503Admission is paused for maintenance. Retry later.
SESSION_LIMIT / 429Close another session or use a higher tier.
INSUFFICIENT_CREDITS / 402Add credits or lower the requested budget.
SESSION_BUSY / 409Wait for the current batch.
HUMAN_CONTROL_ACTIVE / 423Wait for the human to release control.
STALE_REFTake another snapshot.
FILE_TOO_LARGEUse a smaller file.
PROFILE_TOO_LARGE / PROFILE_ROUTE_MISMATCHInspect the safe profile-save event.
SESSION_CLOSED / 409Create a new session.

The generated REST reference contains every request and response schema. SDK operation names use the browser resource: TypeScript createSession, listSessions, getSession, closeSession, act, listFiles, and createProfile; Python generators use snake_case equivalents. Browser methods require a client generated from the current contract. If your installed SDK does not expose them yet, use REST or MCP. WebSocket protocol details are documented here because they are not OpenAPI operations.

Hosted browser tasks

Use POST /browser/tasks (SDK client.browser.runTask, Python client.browser.run_task) when you want Berrycrawl to run the agent loop. berrycrawl_browser_run_task starts the same async job; poll GET /jobs/{id} or berrycrawl_get_job. Existing jobs pages display browser_task jobs.

{
  "task": "Read the latest invoice total and return it as total.",
  "start_url": "https://portal.example.com/invoices",
  "session": { "proxy": "auto", "profile_id": "prof_example" },
  "output_schema": {
    "type": "object",
    "properties": { "total": { "type": "string" } },
    "required": ["total"],
    "additionalProperties": false
  },
  "max_steps": 25,
  "max_credits": 2000,
  "model": "default"
}

Alternatively pass session_id for an existing session, omitting session and start_url. A task creates and closes its own session; an attached session stays open and keeps billing until you close it. Task results include output, final URL, completed steps, private screenshot/file references, usage and any stop reason. Screenshot URLs require the account's API authentication; file metadata endpoints return fresh signed URLs. Artifacts retain the normal seven-day lifetime.

Tasks use the existing session holds for time, traffic and model credits, with no task or step fee. Current AI credits follow extraction's reporting-only zero rate; token counts are still recorded per model and call. Model choices default, fallback and smart select configured extraction roles, never arbitrary provider/model IDs. A task on an existing session applies a temporary additional spending cap and restores its original cap afterward.

The limit is 25 steps by default, at most 100. Invalid model decisions consume a step and get one correction. Three repeated actions on the same target or three consecutive action failures stop the task. Credits, timeouts, cancellation and worker loss also stop it. A partial task is never retried automatically, including after a stalled worker; completed steps and any action whose outcome was unknown are retained. Completion/failure hooks use browser_task.completed and browser_task.failed through the normal webhook service.

Page text is untrusted data. Browser tasks stay on the starting origin or the existing session's current origin; use allowed_origins for up to ten additional origins needed by the task. Cross-origin instructions from a page do not authorize a new destination. Hosted tasks cannot use JavaScript evaluation, upload files or type into password/payment-secret fields. A person creates logged-in profiles through live control; do not put passwords in task text.

Purchases and irreversible submissions require allow_irreversible: true. Without it, the runner conservatively pauses button clicks, form submission, selection changes and dialog acceptance, returning result status needs_confirmation and the concrete pending_step. Ordinary same-origin links and read actions can proceed. Review the pending step before creating an explicitly approved task; owned sessions are closed when the task stops. An attached session remains available for human control. This flag does not relax origin or credential restrictions.

Output schemas use bounded local JSON Schema. Remote references, regex patterns and format validators are rejected; keep schemas under 16 KB and twenty levels of nesting.

Record a path and repeat it

Recorded runs are the cheaper monitoring path: replay uses the session's time and traffic meters, with no model call. Optional healing uses hosted-task AI tokens at the existing token price. Berrycrawl does not schedule recordings; your agent or Berry Chat scheduled task calls the run endpoint and decides whom to alert.

After a successful session or hosted task, save its actions:

POST /api/v1/browser/recordings
Authorization: Bearer bc_YOUR_KEY
Content-Type: application/json

{
  "name": "Invoice total",
  "session_id": "bses_YOUR_SESSION",
  "goal": "Open the invoice report and read its total",
  "output": {
    "type": "extract",
    "fields": { "total": { "selector": "#total", "attribute": "text" } }
  }
}

Pass task_id instead of session_id to save a completed hosted task. The recording inherits the source session's proxy, country, timeout and optional saved profile. A new session opens for each replay; it does not reuse the source session or modify its profile.

Targets prefer exact accessible role and name, for example {"locator":{"role":"button","name":"Open report"}}. These survive CSS class changes. A CSS selector is the fallback; coordinates remain only when the original action used them. Ambiguous or missing replay targets fail promptly. Observation actions such as snapshots and screenshots are omitted. Evaluation, uploads, password fields, iframe targets, switching/closing old tab IDs and actions in a tab other than the active one cannot become recordings. A session created before replay journaling was enabled cannot be reconstructed from its structural audit events; record the path again.

Writes are sensitive by default. Their values are replaced with placeholders such as {{value_1}}; the response lists required_variables. Supply exactly those variables when running. Passwords, payment fields and verification codes cannot be recorded or supplied this way. A person should log in through live control and save a profile. Replay definitions, action journals, runtime variables and run outputs are encrypted with the configured profile encryption key. They never appear in operational logs. Keep that key available when rotating or migrating these records.

POST /api/v1/browser/recordings/brec_YOUR_RECORDING/runs
Authorization: Bearer bc_YOUR_KEY
Content-Type: application/json

{
  "variables": { "value_1": "invoice search" },
  "max_credits": 100,
  "heal": false,
  "allow_irreversible": false
}

Omit variables for a path without placeholders. The response contains id, job_id and a jobs URL. Poll GET /api/v1/jobs/{job_id} or GET /api/v1/browser/recordings/{id}/runs/{runId}. The dashboard's Recordings workspace shows run history and detailed results. The generic jobs page also shows runs. Run history is available at GET /api/v1/browser/recordings/{id}/runs (latest 50). List/get/delete recordings at /browser/recordings and /browser/recordings/{id}. Deletion stops future runs; existing run results remain in the job history.

output.type: "scrape" returns markdown. output.type: "extract" reads the specified CSS fields deterministically: use text or a supported safe attribute (content, href, src, title, aria-label, or data-*). A field must match exactly one non-credential element. Missing/ambiguous fields fail the run. This output format takes no extraction prompt and makes no AI call. Output is limited to 256 KB; recordings allow 100 steps and a 200 KB definition. An account can save 100 recordings. New runs use normal session capacity and credit limits.

Completed results include output, healed, changed, diff, completed steps and usage. The first successful output establishes the baseline (changed: false). Later runs compare with the previous successful completion: extract results use JSON field paths, markdown uses a bounded line diff. A failed run with missing output reports output_missing: true and, when a previous output exists, its removal in the diff. Failed runs never advance the baseline. Read status alongside changed when deciding whether to alert.

Set heal: true explicitly to let the hosted agent continue after a known failed step. It gets the recording's goal, the current page and completed action types. It does not repeat completed steps automatically. The run returns healed: true only when healing completes. Unknown outcomes after worker/transport loss fail without replay. Purchases, submissions and other irreversible actions still require allow_irreversible: true.

A successful healed run may return suggested_recording. The saved recording is never changed automatically. To accept the new path, create a separate recording explicitly:

{
  "name": "Invoice total — revised path",
  "source_run_id": "brun_YOUR_HEALED_RUN"
}

Send that body to POST /browser/recordings. Keep the old recording until you choose to delete it. The MCP equivalents are berrycrawl_browser_save_recording and berrycrawl_browser_run_recording; poll berrycrawl_get_job for the result.