---
title: "Drive a browser across several calls, keeping the page, its cookies and its login in between. The loop is: open a session on a URL, snapshot it to list the interactive elements as refs (@e1, @e2 ...), act on those refs, read the content (the whole page by default, onlyMainContent: true for the main article block alone), close. Because the page stays open you can look before each step instead of committing to a whole chain up front, so a wrong selector costs one call rather than all of them. Not for a page that renders without interaction (scrape), and not for an interaction you can write out in advance — that is one scrape_with_actions call."
method: POST
path: "/tools/browser_session"
tags: ["tools"]
---

# Drive a browser across several calls, keeping the page, its cookies and its login in between. The loop is: open a session on a URL, snapshot it to list the interactive elements as refs (@e1, @e2 ...), act on those refs, read the content (the whole page by default, onlyMainContent: true for the main article block alone), close. Because the page stays open you can look before each step instead of committing to a whole chain up front, so a wrong selector costs one call rather than all of them. Not for a page that renders without interaction (scrape), and not for an interaction you can write out in advance — that is one scrape_with_actions call.

`POST /tools/browser_session`

## Request

- Base URL: `https://www.crawlforge.dev/api/v1`
- URL: `https://www.crawlforge.dev/api/v1/tools/browser_session`
- Auth: API key in header `X-API-Key`

## Request body

- BrowserSessionRequest
  - `operation` 'open' | 'snapshot' | 'act' | 'read' | 'screenshot' | 'close' | 'list', required: What this call does to the session. Every operation but open and list needs session_id. Priced per operation, not per call: open 3, read 2, snapshot / act / screenshot / close / list 1 each.
  - `session_id` string: The id operation "open" returned. Required by snapshot, act, read, screenshot and close.
  - `url` string: open: the URL to load the session on
  - `stealth` boolean: open: run the session in the stealth browser instead of the standard pool
  - `ttl` number: open: seconds the session may live from the moment it opens (30-3600, default 600)
  - `activity_ttl` number: open: seconds the session may sit idle between calls (10-3600, default 300). The session dies at whichever of the two clocks runs out first.
  - `viewport` object: open: viewport size
    - `width` number: 800-1920
    - `height` number: 600-1080
  - `timeout` number: Per-action timeout in ms (10000-120000). The REST call itself waits up to ~50s, so a timeout above that cannot be reached here.
  - `respect_robots` boolean: Respect the target site's robots.txt. Omitted, the compliant default (true) applies: a URL disallowed for CrawlForge is refused before the browser opens and no credits are charged, and every navigate action inside the session 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 on each call that navigates. Setting this to false is honoured, returns a warning in the response, and is recorded against your API key.
  - `interactive_only` boolean: snapshot: give refs to interactive elements only. Set false to list headings and landmarks too; only interactive elements are ever given a ref.
  - `max_nodes` number: snapshot: cap on how many nodes the tree lists (1-1000). The result reports truncated: true when the cap stopped the walk.
  - `actions` object[]: act: the actions to run against the open page, 1-20 of them, in the same shape scrape_with_actions takes — see that tool for every per-action field. Target an element by a @e ref from the most recent snapshot (for example "@e2") in selector, or by a CSS selector. Navigation invalidates refs, so snapshot again after one.
    - `type` 'wait' | 'click' | 'type' | 'press' | 'scroll' | 'screenshot' | 'executeJavaScript' | 'select' | 'hover' | 'navigate' | 'snapshot': Action to perform. executeJavaScript is refused in a session on the hosted API — the script would run in a browser on our servers, not on your machine.
    - `selector` string: What the action targets: a CSS selector, or a @e ref from the last snapshot
  - `continue_on_error` boolean: act: keep going past a failed action instead of stopping the call
  - `formats` unknown[]: read: formats to return from the live DOM — markdown, html, text, json. The page is read as it stands after everything the session has done, cookies and all; nothing is re-fetched.
    - unknown
  - `onlyMainContent` boolean: read: false (default) returns the whole page as markdown/text (markdown leaves out nav, footer and aside elements, as scrape's does; text leaves out nothing); true keeps only the main article block via Readability, which drops navigation and footers but can also drop list items on listing and app pages. The result's extractionMethod says which ran ("full_page" for the whole page).
  - `full_page` boolean: screenshot: capture the full scrollable page
  - `format` 'png' | 'jpeg': screenshot: image format
  - `quality` number: screenshot: JPEG quality (0-100)
  - `selector` string: screenshot: capture just this element (a @e ref works)
  - `max_inline_chars` number: Largest result returned inline, in characters of its JSON (1000-10000000; env CRAWLFORGE_MAX_INLINE_CHARS sets the default). Over it, the result is stored for 1 hour and the response carries a preview, a result_handle, total_chars and truncated: true; read the rest with read_result (1 credit).
  - `redact_pii` union: Remove personal data from the text this call returns, before it is stored or sent back. true is shorthand for { mode: "fast" }: every entity, tagged. As an object: entities (any of EMAIL, PHONE, FINANCIAL, SECRET; omitted or empty means all four, and any other name is a 400 rather than a silent no-op), replace_style ("tag" → <EMAIL>, "mask" → [REDACTED], "remove" → nothing; default "tag") and mode ("fast", the default, is regex-only and costs no extra credits; "model" covers PERSON and LOCATION, needs an LLM and is rejected here — use the CrawlForge MCP server). The response carries redaction: { entities, count, mode } inside data, saying what was removed. Detection is deliberately conservative: a card number must pass Luhn and an IBAN mod-97, so a false positive cannot silently destroy real page content. URLs, queries and identifiers the response uses to name what was fetched are left intact, and counters derived from the text (content_length, word_count, character_count) describe the text as it was extracted, before redaction.
    - boolean
    - object
      - `entities` string[]
      - `replace_style` 'tag' | 'mask' | 'remove'
      - `mode` 'fast' | 'model'

## Response `200`

The tool's result; 3 credits charged (see x-credits-note and x-extra for add-ons).

- ToolSuccess: The envelope every tool returns on success. Credits are deducted only after the tool succeeded, so credits_used is the price of this call and an error response never charges.
  - `success` true, required
  - `data` object, required: The tool's result. Its shape is tool-specific and documented on the tool's docs page (x-docs-url on the operation).
  - `credits_used` integer, required: Credits charged for this call: the operation's x-credits, plus any add-on x-credits-note or x-extra describes.
  - `credits_remaining` integer, required: The account's credit balance after this call.
  - `processing_time` integer, required: Server-side processing time in milliseconds.
  - `warnings` string[]: Non-fatal notes: a robots.txt override that was recorded, a format that could not be produced, a redaction that changed the payload.

## Other responses

- `400`: VALIDATION_ERROR: the body does not match the request schema.
- `401`: MISSING_API_KEY or INVALID_API_KEY.
- `402`: INSUFFICIENT_CREDITS: the balance does not cover the tool's base price. X-Auto-Recharge-Triggered says whether an automatic recharge was started; retry once it lands.
- `429`: RATE_LIMIT_EXCEEDED: your plan's rate limit. Retry-After: 60.
- `500`: TOOL_ERROR, INTERNAL_ERROR or CREDIT_DEDUCTION_FAILED.
- `default`: Any other error. Which of 403, 404, 413, 422, 501, 502, 503 and 504 a tool can return depends on what it does (fetching a page, calling the execution backend, reading stored results); the code vocabulary is listed on the ErrorResponse schema.

---

[API](https://skmtc.dev/crawlforge/apis/crawlforge-rest-api.md) · [All operations](https://skmtc.dev/crawlforge/apis/crawlforge-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/crawlforge/apis/crawlforge-rest-api/revisions/a5532fa8d5d5?raw)
