Skip to content
Advanced Tool3 credits

browser_session

One browser page you keep across several API calls. Open a session, take a snapshot to see what the page offers, act on the refs that snapshot handed back, look again — and pay for the login once instead of once per call.

Use Cases

Log In Once, Read Many Pages

Sign in on the first call, then navigate and read behind the login for as long as the session lives — without repeating the login every time

Explore an Unfamiliar App

Snapshot a page you have never seen, read its interactive elements out of the response, and act on them in the next call instead of guessing CSS selectors

Agent Loops

Give an agent a see-then-act loop: the snapshot tree is the observation, the refs are the action space, and the next snapshot is the feedback

Multi-Step Wizards

Walk a checkout or an onboarding flow one step per call, checking what the page became before choosing the next action

Debugging a Failing Chain

When a one-shot action chain fails on a guessed selector, open a session and step through it, taking a screenshot between steps

Reading After the Interaction

Extract markdown, HTML, text or metadata from the live DOM as it stands after everything the session has clicked

Endpoint

POST/api/v1/tools/browser_session
Auth Required
1 req/s on Free plan
3 credits

Parameters

NameTypeRequiredDefaultDescription
operation
stringRequired-
Which step of the session this call performs: `open`, `snapshot`, `act`, `read`, `screenshot`, `close` or `list`. Every operation except `open` and `list` needs `session_id`. The operation also sets the price — see **Operations and what they cost** below.
Example: snapshot
session_id
stringOptional-
The id `operation: "open"` returned, carried on every later call in the session. Required by `snapshot`, `act`, `read`, `screenshot` and `close`. An id that is unknown, expired, closed, or belongs to another account all give the same "Session not found" — ids are not enumerable, so the error never tells you which of the four you hit.
Example: 9f2c1e6a-4b7d-4c3e-8a5f-1d2e3f4a5b6c
url
stringOptional-
The page the session opens on. Required by `open` and ignored by the other operations — once a session exists you move it with a `navigate` action inside `act`. The URL passes the SSRF guard and the target's robots.txt before a browser is launched, and so does every in-session navigation.
Example: https://app.example.com/login
stealth
booleanOptionalfalse
`open` only. Run the session in the stealth Chromium engine at its `medium` profile instead of the standard browser pool. It is slower to start, and it renders JavaScript rather than solving challenges. The session keeps this setting for its whole life.
Example: false
ttl
numberOptional600
`open` only. How long the session may live at all, in seconds (30-3600). The session closes on this clock whatever you are in the middle of, so size it to the work you have planned.
Example: 600
activity_ttl
numberOptional300
`open` only. How long the session may sit idle between calls, in seconds (10-3600). Every operation restarts this clock; whichever clock expires first closes the session and frees its page.
Example: 300
viewport
objectOptional-
`open` only. The browser window the session runs in: `{ width, height }`, width 800-1920 and height 600-1080. Defaults to the browser pool's own size.
Example: {"width": 1440, "height": 900}
timeout
numberOptional30000
Time budget in milliseconds for the browser work this call does (10000-120000): the first navigation on `open`, the action chain on `act`. Keep it inside the ~25s REST window.
Example: 30000
respect_robots
booleanOptionaltrue
Respect the target site's robots.txt. Omit it and the compliant default (`true`) applies: a URL disallowed for `CrawlForge` is refused before the browser opens and this endpoint charges nothing for it, and every `navigate` action inside `act` is checked the same way. It applies to the call it is sent on and is never remembered by the session, so an override has to be repeated as deliberately as it was made. Set it to `false` only for a target you have your own agreement with — the override is recorded against your API key.
Example: true
interactive_only
booleanOptionaltrue
`snapshot` only. List just the elements that take a pointer or the keyboard, which are the ones that get a ref. Set it to false to list headings and landmarks as well — useful for finding your way around a page, but those nodes never get a ref.
Example: true
max_nodes
numberOptional200
`snapshot` only. Caps how many nodes the tree lists (1-1000) — under the default `interactive_only` that is one ref each. The result reports `truncated: true` when the cap stopped the walk.
Example: 200
actions
arrayOptional-
`act` only. 1-20 browser actions run against the page the session already holds, in the same vocabulary [scrape_with_actions](/docs/api-reference/tools/scrape-with-actions) takes — `wait`, `click`, `type`, `press`, `scroll`, `screenshot`, `select`, `hover`, `navigate`, `snapshot` — with their type-specific fields. Point `selector` at a `@e1` ref from the session's last snapshot instead of a guessed CSS selector. `executeJavaScript` is refused on the hosted API: the script would run in a browser on our infrastructure rather than on your machine.
Example: [{"type": "type", "selector": "@e1", "text": "user@example.com"}, {"type": "click", "selector": "@e3"}]
continue_on_error
booleanOptionalfalse
`act` only. Keep running the remaining actions when one fails instead of stopping the chain. The per-action results say which ones ran.
Example: false
formats
arrayOptional["markdown"]
`read` only. What to extract from the page as it stands right now: `markdown`, `html`, `text`, `json` (title, metadata and structured data). Content comes from the live DOM, so it reflects the session's cookies and everything it has clicked — not a fresh fetch of the URL.
Example: ["markdown", "json"]
full_page
booleanOptionalfalse
`screenshot` only. Capture the whole scrollable page instead of just the viewport.
Example: false
format
stringOptionalpng
`screenshot` only. Image format: `png` or `jpeg`.
Example: png
quality
numberOptional80
`screenshot` only. JPEG quality, 0-100. PNG ignores it.
Example: 80
selector
stringOptional-
`screenshot` only. Capture one element instead of the page — a CSS selector, or an `@e1` ref from the session's last snapshot.
Example: @e2
max_inline_chars
numberOptional40000
`snapshot`, `act` and `read` only — the operations that return page content. Largest result to return inline, in characters of its JSON (1,000-10,000,000). Over it the response carries `preview`, `result_handle`, `total_chars`, `truncated: true` and `expires_at`, and [read_result](/docs/api-reference/tools/read-result) reads the rest for 1 credit per call; the fields measured are `content.markdown`, `content.text`, `content.html` and `snapshot.tree`. Stored results are kept for 1 hour. The session is untouched by this — the page stays open and the next operation still sees all of it.
Example: 40000
redact_pii
boolean | objectOptionalfalse
`snapshot`, `act` and `read` only; the other operations return bookkeeping and are left untouched. Remove personal data from the text this call returns, before the result is stored or sent back — a logged-in page whose snapshot `tree` and extracted content carry the account holder's details is what this is for. `true` is shorthand for `{ mode: "fast" }` — all four regex classes, tagged. Whenever you ask for redaction the response carries `redaction: { entities, count, mode }` inside `data`, even when nothing matched (`count: 0`), so "found nothing" is never mistaken for "the parameter was ignored". Redaction runs **before** the result is stored, so an oversized result read back later with [read_result](/docs/api-reference/tools/read-result) is already redacted. Two deliberate limits: addresses (`url`, `link`, `href`, `canonical_url`) are never redacted, and counters derived from the text (`content_length`, `word_count`, `character_count`) describe it as extracted, before redaction.
Example: true

Operations and what they cost

Each call is billed on its own operation, so a cheap look does not pay for an expensive open. Nothing runs for free: close and list still cost 1 credit each.

open — 3 credits
Launches a browser on url and returns a sessionId plus both expiry clocks. The dearest operation because it is the one that starts a browser — strictly more work than a one-shot scrape.
snapshot — 1 credit
Returns the page's accessibility tree with a stable ref on every interactive element — @e1, @e2, … in document order. This is the "look" half of the loop, and it is what the next call aims at.
act — 1 credit
Runs up to 20 actions against the page the session holds — one credit for the call, not per action. Target the refs the last snapshot returned.
read — 2 credits
Extracts the live DOM in the formats you ask for, after everything the session has clicked and with its cookies in place. Priced with scrape, because it is the same content extraction.
screenshot — 1 credit
Captures the page, or one element, as it stands. The image comes back as a crawlforge://screenshot/{id} resource URI rather than inline base64, and this REST endpoint passes that URI through without resolving it — so for now the bytes are readable only from the CrawlForge MCP server.
close — 1 credit
Ends the session and gives its browser page back. Close as soon as you are done rather than waiting for a TTL to expire — the slot is small and shared.
list — 1 credit
Your live sessions with their ids, current URLs and both expiry times. Useful when you have lost an id, or want to know whether a session is still there before acting on it.

How long a session lives, and how many you get

Targeting elements by ref

browser_session or scrape_with_actions?

Both drive a real browser and take the same action vocabulary. The difference is whether you already know what the page looks like.

Use scrape_with_actions
A one-shot chain on a page you understand: the selectors are known, the flow is fixed, and you want the content back in the same call. 5 credits, one round trip, and the browser closes when it returns.
Use browser_session
Exploratory or multi-call work where you need to see the page before acting, or where several calls should share one login. A login-then-read flow — open, snapshot, act, act, read, close — costs 9 credits against 5 for a one-shot chain that is far likelier to fail on a guessed selector.

Persistent logins are not available here

Request Examples

terminalBash
# 1. Open the session (3 credits). The id comes back as data.sessionId.
curl -X POST https://crawlforge.dev/api/v1/tools/browser_session \
  -H "X-API-Key: cf_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operation": "open",
    "url": "https://app.example.com/login",
    "ttl": 600
  }'

# {"success": true, "data": {"sessionId": "9f2c1e6a-4b7d-4c3e-8a5f-1d2e3f4a5b6c", ...}}

# 2. Look at the page before touching it (1 credit).
curl -X POST https://crawlforge.dev/api/v1/tools/browser_session \
  -H "X-API-Key: cf_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operation": "snapshot",
    "session_id": "9f2c1e6a-4b7d-4c3e-8a5f-1d2e3f4a5b6c"
  }'

# data.snapshot.tree comes back as:
#   [document] "Sign in"
#     @e1 [textbox] "Email"
#     @e2 [textbox] "Password"
#     @e3 [button] "Sign in"

# 3. Act on those refs in a SEPARATE call (1 credit). Same page, same cookies.
curl -X POST https://crawlforge.dev/api/v1/tools/browser_session \
  -H "X-API-Key: cf_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operation": "act",
    "session_id": "9f2c1e6a-4b7d-4c3e-8a5f-1d2e3f4a5b6c",
    "actions": [
      {"type": "type", "selector": "@e1", "text": "user@example.com"},
      {"type": "type", "selector": "@e2", "text": "secret123"},
      {"type": "click", "selector": "@e3"},
      {"type": "wait", "duration": 1000}
    ]
  }'

# 4. Read the page the login landed on (2 credits).
curl -X POST https://crawlforge.dev/api/v1/tools/browser_session \
  -H "X-API-Key: cf_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operation": "read",
    "session_id": "9f2c1e6a-4b7d-4c3e-8a5f-1d2e3f4a5b6c",
    "formats": ["markdown"]
  }'

# 5. Close it rather than waiting for the TTL (1 credit). 8 credits in all.
curl -X POST https://crawlforge.dev/api/v1/tools/browser_session \
  -H "X-API-Key: cf_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operation": "close",
    "session_id": "9f2c1e6a-4b7d-4c3e-8a5f-1d2e3f4a5b6c"
  }'

Response Example

200 OK180ms
{
"success": true,
"data": {
"success": true,
"operation": "snapshot",
"sessionId": "9f2c1e6a-4b7d-4c3e-8a5f-1d2e3f4a5b6c",
"url": "https://app.example.com/login",
"stealth": false,
"expiresAt": 1789459200000,
"idleExpiresAt": 1789458900000,
"snapshot": {
"snapshotId": "a3f19c2d",
"url": "https://app.example.com/login",
"title": "Sign in",
"tree": "[document] \"Sign in\"\n @e1 [textbox] \"Email\"\n @e2 [textbox] \"Password\"\n @e3 [button] \"Sign in\"",
"refCount": 3,
"nodeCount": 3,
"truncated": false,
"interactiveOnly": true
}
},
"credits_used": 1,
"credits_remaining": 996,
"processing_time": 180
}
Field Descriptions
data.operationThe operation this call performed — every response echoes it back
data.sessionIdSend this on every later call in the session
data.urlWhere the session's page is right now, which a navigation moves
data.expiresAtWhen the absolute `ttl` clock expires, in milliseconds since the epoch
data.idleExpiresAtWhen the idle `activity_ttl` clock expires; every operation pushes it forward
data.snapshot.treeThe accessibility tree. Each interactive element carries the ref you target in the next call
data.snapshot.refCountHow many elements got a ref in this snapshot
data.snapshot.truncatedTrue when `max_nodes` stopped the walk before the end of the page
credits_usedCredits deducted for this call — 1 for a snapshot, 3 for an open
processing_timeTime in ms for this call alone, not the session

Error Handling

Session not found (502 TOOL_ERROR)

The session_id is unknown, expired, already closed, or belongs to another account — all four answer alike, so ids cannot be probed from outside. Sessions also do not survive a restart of the execution backend. Open a new one and carry on; nothing is charged for the failed call.

Session limit reached (502 TOOL_ERROR)

You already hold the maximum of one open session. The call is refused rather than queued, because a session slot frees on its TTL minutes from now. Send operation: "close" for the session you have — operation: "list" tells you its id — or wait for its TTL.

Browser runtime not configured (503 TOOL_NOT_AVAILABLE)

This tool needs a browser automation runtime. When the hosted execution backend is not configured the call returns 503 immediately and no credits are charged.

Execution backend timed out (504 MCP_UPSTREAM_TIMEOUT)

The navigation or the action chain exceeded the execution backend's time budget. Shorten waits, split the chain across two act calls — the session is still there — or retry. Failures are not charged.

Blocked by robots.txt (502 TOOL_ERROR)

The target's robots.txt disallows this URL for CrawlForge, so no browser was launched and nothing was charged. Every navigate action inside act is checked the same way, not just the URL you opened on. Set respect_robots: false to override if you have your own agreement with the target — the override is recorded against your API key.

Invalid request (400 Bad Request)

The operation is missing a parameter it needs — open without url, act without actions, or any operation other than open and list without session_id — or an action failed its own schema. Nothing is charged.

Insufficient Credits (402 Payment Required)

Your account doesn't have enough credits for this operation (up to 3). Purchase more credits or upgrade your plan.

Rate Limit Exceeded (429 Too Many Requests)

You've exceeded your plan's rate limit. Wait a moment or upgrade your plan for higher limits.

Credit Cost

3 credits
1-3 credits per operation
browser_session is billed per operation, not per tool: open 3, read 2, and snapshot, act, screenshot, close and list 1 each. 3 credits is the ceiling — what open costs, and what an unrecognised operation is charged. A login-then-read flow (open, snapshot, act, act, read, close) comes to 9 credits.

Free Plan: 1,000 one-time trial credits = about 110 login-then-read sessions

Hobby Plan: 5,000 credits/month = about 550 sessions ($19/mo)

Professional Plan: 50,000 credits/month = about 5,500 sessions ($99/mo)

Business Plan: 250,000 credits/month = about 27,000 sessions ($399/mo)

Related Tools