> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nodemaven.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Scraping Browser API reference

> Run a real Chrome browser on NodeMaven infrastructure through your proxy. Sessions, profiles, automation endpoints, and connection options.

## Run a real Chrome browser, on our infrastructure, through your proxy.

The Scraping Browser API spins up a remote, fingerprint-hardened Chrome session routed through your NodeMaven proxy, then hands you plain REST endpoints to configure it, drive it, and pull back whatever the page gave you - HTML, a screenshot, a PDF, or the return value of a script you ran on it.

* `api.browser.nodemaven.com` - sessions and automation
* **Bearer token** - request auth
* **dashboard** - where your token lives
* **JSON** everywhere

## Quickstart flow

Four steps, start to finish - from opening your dashboard to reading back scraped data.

<Steps>
  <Step title="Copy your token">
    Open the Scraping Browser page in the NodeMaven dashboard and copy the API token shown there. Every call below is authenticated with it.

    `dashboard → Scraping Browser`
  </Step>

  <Step title="Configure and launch">
    Pick a country/city, stealth options, and proxy protocol, then create a session.

    `POST /sessions`
  </Step>

  <Step title="Automate it">
    Navigate, click, type, or run a script - or connect your own Playwright/Selenium/Puppeteer script directly.

    `/tools/*, CDP, Selenium`
  </Step>

  <Step title="Read the results">
    Pull back the page's HTML, a screenshot, a PDF, or your script's return value - then close the session.

    `text · json · png · pdf`
  </Step>
</Steps>

<Check>
  **This is the whole surface.** Everything else in this reference - locations, profiles, page actions - exists to support these four steps: proxy/location endpoints feed step 2, profiles let step 2 remember a setup across sessions, and page actions (click/type/scroll) are the fine-grained half of step 3.
</Check>

## Authentication

One token, one header. Your token is shown in the dashboard - copy it and send it as a Bearer token on every request.

<CardGroup cols={2}>
  <Card title="Where to get it">
    The **Scraping Browser** page in the NodeMaven dashboard displays your API token. Copy it from there - there's nothing to generate or exchange.
  </Card>

  <Card title="How to send it">
    `Authorization: Bearer <token>` on every Scraping Browser API request. The token is valid for **7 days**; when it expires, open the dashboard and copy the current one.
  </Card>
</CardGroup>

```bash theme={null}
# Every request uses the token from your dashboard

curl https://api.browser.nodemaven.com/api/v2/browser/sessions \
  -H "Authorization: Bearer YOUR_BROWSER_TOKEN"
```

<Warning>
  **Keep it secret.** This token authorizes browser sessions on your account and proxy traffic billed to it. Treat it like a password: keep it server-side, out of client-side code and version control.
</Warning>

## Errors and status codes

Every error response is a flat JSON object with a single `error` string. A few endpoints attach extra machine-readable fields - noted below.

```json theme={null}
{ "error": "proxy_password is required" }
```

| Status | Meaning | Notes |
| - | - | - |
| 400 | Bad request | Malformed JSON, or a value outside what's supported (unknown protocol, out-of-range limit, ...). |
| 401 | Unauthorized | Missing or invalid `Authorization` header. |
| 404 | Not found | Also returned for a session/profile you don't own - ownership never leaks as a distinct error. |
| 429 | Too many requests | Concurrency limit hit. Body adds `limit_type`, `current_usage`, `limit`, `retry_after`; header `Retry-After` is also set. |
| 502 | Bad gateway | The browser/proxy upstream failed or was unreachable for this call. |
| 503 | Service unavailable | A feature is temporarily disabled. Body adds `reason`, `retry_after`. |

## Limits

Defaults below - configurable per account; ask support if your workload needs more.

| Limit | Default |
| - | - |
| Browser profiles | **10** |
| Concurrent active sessions | **50** |
| Maximum session duration | **30 minutes** |
| Idle timeout | **10 minutes** |
| Session recording retention | **3 days** |

## Proxy and location configuration

Everything a session's `country`/`region`/`city`/`isp`/`zip` fields accept, and a way to check a combination before you spend a session on it.

### `GET` /api/v2/browser/proxy/options

The static vocabulary a session's proxy targeting understands - connection types, session types, protocols, and the drill-down order for the location endpoints below.

```json 200 Response theme={null}
{
  "data": {
    "connection_types": [
      { "value": "residential", "label": "Residential", "default": true },
      { "value": "mobile", "label": "Mobile" }
    ],
    "session_types": [
      { "value": "sticky", "label": "Sticky (keep the same IP)", "default": true },
      { "value": "rotating", "label": "Rotating (new IP each connection)" },
      { "value": "no_rotating", "label": "No rotating (pin IP, never rotate)" }
    ],
    "protocols": [
      { "value": "http", "label": "HTTP", "default": true },
      { "value": "socks5", "label": "SOCKS5 (recommended for anti-detection)" }
    ],
    "filter_modes": [
      { "value": "quality", "label": "Quality (default) - highest quality IP, any speed", "default": true },
      { "value": "quality_speed", "label": "Quality + Speed - best quality and fast IPs" },
      { "value": "speed", "label": "Speed - fastest IPs, any quality" },
      { "value": "none", "label": "Max pool size - no filters applied" }
    ],
    "filter_levels": { "quality": "medium", "speed": "fast" },
    "quality_filter": {
      "description": "DEPRECATED - use filter_mode. true is equivalent to filter_mode \"quality\", false to \"none\".",
      "default": true, "deprecated": true
    },
    "location_levels": ["countries", "regions", "cities", "isps", "zip-codes"]
  }
}
```

<Note>
  **Build your IP-filter dropdown from `filter_modes`** rather than hardcoding it - these are the same four modes, in the same order, with the same default as the **IP filter mode** selector on the main proxy dashboard. `filter_levels` shows what the quality/speed tokens currently resolve to; those values are platform config, not something a request chooses.
</Note>

### `GET` /api/v2/browser/locations/\{countries|regions|cities|isps|zip-codes}

Drill down through real, currently-available targeting data - the same reference geo-data the main NodeMaven proxy dashboard uses. Filter each level by the one above it.

| Query param | | Description |
| - | - | - |
| `connection_type` | optional | `residential` (default), `mobile`, or `isp`. |
| `country` | optional | Required by `regions`/`cities`/`isps`/`zip-codes`. |
| `region` | optional | Required by `cities`; narrows `zip-codes`. |
| `city` | optional | Narrows `zip-codes`. |
| `search` | optional | `countries` only - filter by code or name. |
| `ipv4_only, limit, offset` | optional | Standard filtering/pagination. |

**Request:**

### `GET /api/v2/browser/locations/cities?country=us&region=california`

```json 200 Response theme={null}
{
  "data": [
    {
      "code": "los-angeles",
      "name": "Los Angeles",
      "availability": "high",
      "country_code": "us",
      "region_code": "california"
    }
  ]
}
```

<Warning>
  503 location data not configured for this deployment
</Warning>

### `POST /api/v2/browser/configurations/validate`

Checks a targeting config before you spend a session creating it, and previews the resulting proxy username - using the exact same logic session-create uses, so a config that validates here will create identically.

<CodeGroup>
  ```json Request body theme={null}
  {
    "connection_type": "residential",
    "session_type": "sticky",
    "protocol": "http",
    "country": "us",
    "region": "california",
    "filter_mode": "quality_speed"
  }
  ```

  ```json 200 Response theme={null}
  {
    "data": {
      "valid": true,
      "normalized": {
        "country": "us", "region": "california",
        "protocol": "http", "connection_type": "residential",
        "session_type": "sticky", "filter_mode": "quality_speed",
        "quality_filter": true, "ipv4_only": false
      },
      "issues": null,
      "proxy_username_preview":
        "user123-country-us-region-california-sid-8f3a2b-filter-medium-speed-fast-source-browser"
    }
  }
  ```
</CodeGroup>

An invalid config still returns `200` with `valid: false` and an `issues` array of `{code, field, message, suggestion}` - this endpoint reports problems, it doesn't error on them. A bad `filter_mode`, for example, comes back as `{"code": "unsupported_filter_mode", "field": "filter_mode", ...}` with the four valid values in `suggestion`.

<Warning>
  **Check `valid`, not `issues.length`.** When a config is clean, `issues` is `null` rather than an empty array - iterating it without a null check will throw.
</Warning>

### What each filter mode puts in the proxy username

Use this endpoint to see it for your own config - the preview is generated by the same code that creates sessions, so what you see here is exactly what a session will use.

| filter\_mode | Tokens added |
| - | - |
| `quality` | `-filter-medium` |
| `quality_speed` | `-filter-medium-speed-fast` |
| `speed` | `-speed-fast` |
| `none` | none - no filter tokens at all |

<Note>
  `medium`/`fast` above are the current `filter_levels` from proxy/options; they're platform config and can change, so read them from there rather than assuming.
</Note>

## Sessions

A session is one live, disposable Chrome browser, already routed through your proxy. Everything under **Automation and results** operates on a session's `id`.

### `POST` /api/v2/browser/sessions

Launches a browser and returns its connection URL immediately. This is step 3 of the quickstart flow.

| Field | | Description |
| - | - | - |
| `proxy_password` | **required** | Your NodeMaven proxy password. A session can't be created without an active proxy attached. |
| `protocol` | optional | `http` (default) or `socks5`. |
| `country, region, city, zip, isp` | optional | From the locations endpoints. Omit for a broad, unrestricted exit. |
| `connection_type` | optional | `residential` (default) or `mobile`. |
| `session_type` | optional | `sticky` (default), `rotating`, or `no_rotating`. |
| `filter_mode` | optional | Which IP filter to apply: `quality` (default), `quality_speed`, `speed`, or `none`. Same four modes as the proxy dashboard - see proxy/options. An unrecognised value is a `400`, never a silent downgrade. |
| `quality_filter_enabled` | deprecated | Superseded by `filter_mode`. `true` = `quality`, `false` = `none`. Omit both fields to get the default (`quality`) - note that omitting is **not** the same as sending `false`. |
| `ipv4_only` | optional | Pin the session to IPv4 exit IPs. Defaults to off. |
| `extra_stealth` | optional | Anti-detection hardening (masks automation tells, spoofs a real browser fingerprint). |
| `captcha_solver, cloudflare_web_bot_auth, ad_blocker, popup_blocker, headless` | optional | Booleans, self-describing. |
| `max_duration_minutes, idle_timeout_minutes` | optional | 0 (default) uses the account limit - see Limits. |
| `profile_id` | optional | Reuse a saved profile - its saved-cookies/cache and (if enabled) pinned exit IP. |

<CodeGroup>
  ```json Request body theme={null}
  {
    "proxy_password": "YOUR_PROXY_PASSWORD",
    "country": "us",
    "region": "california",
    "session_type": "sticky",
    "extra_stealth": true
  }
  ```

  ```json 200 Response theme={null}
  {
    "data": {
      "id": "ses_8f2a41c9",
      "cdp_url":
        "wss://browser.nodemaven.com/sessions/ses_8f2a41c9?token=...",
      "status": "running"
    }
  }
  ```
</CodeGroup>

| Status | |
| - | - |
| `200` | running |
| `400` | missing proxy\_password / bad protocol |
| `429` | concurrent-session limit |
| `503` | temporarily unavailable |

### `GET` /api/v2/browser/sessions

Lists your sessions. Filter with `?status=running|ended|all` (default `all`) and cap the page with `?limit=`.

```json 200 Response theme={null}
{
  "data": [
    {
      "id": "ses_8f2a41c9", "status": "running",
      "created_at": "2026-08-07T09:14:02Z",
      "config": { "country": "us", "region": "california", "protocol": "http", "...": "..." }
    }
  ]
}
```

<Note>
  The list omits `cdp_url` on purpose - fetch a single session or its connection info when you're ready to connect to one.
</Note>

### `GET` /api/v2/browser/sessions/\{id}

Full detail on one session, including its `cdp_url` while it's still running.

```json 200 Response theme={null}
{
  "data": {
    "id": "ses_8f2a41c9", "status": "running",
    "created_at": "2026-08-07T09:14:02Z", "ended_at": null,
    "config": {
      "country": "us", "region": "california",
      "protocol": "http", "connection_type": "residential", "session_type": "sticky",
      "filter_mode": "quality_speed", "quality_filter_enabled": true,
      "ipv4_only": false,
      "profile_name": "checkout-flow", "profile_id": "prof_a12f"
    },
    "cdp_url": "wss://browser.nodemaven.com/sessions/ses_8f2a41c9?token=..."
  }
}
```

<Note>
  `config` is the **resolved** targeting the session actually used, with server defaults already applied - so it's how you confirm after the fact what a session ran with, including which `filter_mode` was in effect. It never contains your proxy password or the raw proxy username. Location fields are omitted when empty; `quality_filter_enabled` is the deprecated boolean view of `filter_mode` (`true` for the quality-bearing modes).
</Note>

| Status | |
| - | - |
| `404` | unknown, not yours, or past its retention window |

### `GET` /api/v2/browser/sessions/\{id}/connection

Everything needed to connect a script or a browser tab to this session - see Connecting to a session for how each field is used.

```json 200 Response theme={null}
{
  "data": {
    "id": "ses_8f2a41c9", "status": "running",
    "cdp_url": "wss://browser.nodemaven.com/sessions/ses_8f2a41c9?token=...",
    "debugger_address": "7f3a9c....browser.nodemaven.com",
    "live_view_url": "https://browser.nodemaven.com/live/7f3a9c...",
    "config": { "...": "..." }
  }
}
```

### `GET` /api/v2/browser/sessions/\{id}/pages

Lists the tabs/pages currently open in the session.

```json 200 Response theme={null}
{ "data": [ { "id": "9A3F...", "title": "Example Domain", "type": "page", "url": "https://example.com/" } ] }
```

### `GET` /api/v2/browser/sessions/\{id}/recordings

Video replay of the session. Empty while the session is still running - recordings are only published once it ends.

```json 200 Response theme={null}
{
  "data": [
    {
      "id": "rec_1", "is_primary": true,
      "duration_seconds": 42.6, "size_bytes": 1889302,
      "video_url": "https://...mp4?Expires=...&Signature=...",
      "video_url_expires_at": "2026-08-07T09:24:11Z"
    }
  ]
}
```

<Note>
  `video_url` is short-lived (\~10 minutes) - re-fetch this endpoint at play time rather than caching the URL.
</Note>

### `DELETE` /api/v2/browser/sessions/\{id}

Ends the session immediately. Sessions also auto-end on idle timeout or max lifetime, so this is for when you're done early.

```json 200 Response theme={null}
{ "data": { "status": "success" } }
```

<Warning>
  **Creating many sessions at once?** `POST /api/v2/browser/sessions-async` queues a create and returns a `request_id` immediately; poll `GET /api/v2/browser/sessions-async/{request_id}` for the result. Same fields as the synchronous create above - use it when you're launching a batch and don't want to hold a connection open per session.
</Warning>

## Profiles

A profile is a saved browser identity - cookies and cache, and optionally a pinned exit IP - that a new session can reattach to instead of starting cold every time.

### `POST` /api/v2/browser/profiles

| Field | | Description |
| - | - | - |
| name | required | Unique to your account. |
| description | optional | Free text. |
| store\_cache | optional | Persist cookies/local storage/cache across sessions using this profile. |
| pin\_ip | optional | Lock the exit IP a session using this profile gets, from its first use onward - useful for sites that re-challenge on IP change. |

```json 200 Response theme={null}
{
  "data": {
    "id": "prof_a12f", "name": "checkout-flow", "description": "",
    "created_at": "2026-08-07T09:14:02Z", "pin_ip": true
  }
}
```

Once a session has used this profile, `GET`/`LIST` also return `pinned_country`, `pinned_region`, `pinned_city`, `pinned_isp`, `pinned_zip`, `pinned_connection_type` - where it's actually pinned to.

| Status | |
| - | - |
| `429` | you've hit your profile limit (10) |

### `GET` /api/v2/browser/profiles

Lists every profile on your account. Same shape as a single profile, in a `data` array.

### `GET` /api/v2/browser/profiles/\{id}

Fetches one profile by id.

### `PATCH` /api/v2/browser/profiles/\{id}

Renames a profile / updates its description. Body: `{"name", "description"}`.

### `DELETE` /api/v2/browser/profiles/\{id}

Deletes a profile. Sessions already using it are unaffected.

## Automation and results

Server-side actions on a running session - no client library required, just POST a JSON body. Every result comes back inline in the response.

### `POST` /api/v2/browser/tools/navigate

Loads a URL in the session's active page.

<CodeGroup>
  ```json Request theme={null}
  { "session_id": "ses_8f2a41c9", "url": "https://example.com/search?q=nike" }
  ```

  ```json 200 Response theme={null}
  { "data": { "status": "ok" } }
  ```
</CodeGroup>

### `POST` /api/v2/browser/tools/content

Returns the current page's full rendered HTML.

<CodeGroup>
  ```json Request theme={null}
  { "session_id": "ses_8f2a41c9" }
  ```

  ```json 200 Response theme={null}
  { "data": { "content": "<html>...</html>" } }
  ```
</CodeGroup>

### `POST` /api/v2/browser/tools/screenshot

Captures the current page as a PNG.

<CodeGroup>
  ```json Request theme={null}
  { "session_id": "ses_8f2a41c9" }
  ```

  ```json 200 Response theme={null}
  { "data": { "screenshot": "iVBORw0KGgo...", "format": "png" } }
  ```
</CodeGroup>

`screenshot` is base64-encoded PNG bytes - decode and write to a file, or drop straight into an `<img src="data:image/png;base64,...">`.

### `POST` /api/v2/browser/tools/execute-code

Runs JavaScript in the page and returns its value - this is "pass automation as a script."

<CodeGroup>
  ```json Request theme={null}
  {
    "session_id": "ses_8f2a41c9",
    "code": "document.querySelectorAll('.price').length"
  }
  ```

  ```json 200 Response theme={null}
  { "data": { "result": 48 } }
  ```
</CodeGroup>

`result` is whatever your script returns - a number, string, array, or object - passed through as native JSON.

### `POST` /api/v2/browser/tools/pdf

Renders the current page to a PDF.

<CodeGroup>
  ```json Request theme={null}
  { "session_id": "ses_8f2a41c9" }
  ```

  ```json 200 Response theme={null}
  { "data": { "pdf": "JVBERi0xLjQK...", "format": "pdf" } }
  ```
</CodeGroup>

### `POST` /api/v2/browser/sessions/\{id}/\{click|type|scroll}

Fine-grained page actions - the session id is in the path here, not the body, since each hangs off one specific session.

| Route | Body |
| - | - |
| `…/click` | `{"selector": "#add-to-cart"}` |
| `…/type` | `{"selector": "#search", "text": "nike air max 95"}` |
| `…/scroll` | `{"x": 0, "y": 1200}` |

All three return `{"data": {"status": "ok"}}` on success.

| Status | |
| - | - |
| `404` | unknown/not-yours session\_id |
| `400` | missing required field |
| `502` | the browser/page didn't respond |

## Connecting to a session

The `/tools/*` endpoints cover most automation without any client library. For full control, connect directly using whatever's already in your stack.

### Playwright / Puppeteer

Use `cdp_url` as-is with `connectOverCDP` - full CDP control over the exact same browser.

```javascript theme={null}
// playwright
const browser = await chromium.connectOverCDP(cdpUrl);
```

### Selenium

Set `debugger_address` as Chrome's remote-debugging address - Selenium discovers and attaches automatically.

```python theme={null}
# selenium
opts.debugger_address = debugger_address
```

### Live view

Open `live_view_url` in any browser tab (or embed it in an `<iframe>`) to watch the session render in real time - handy while developing a script.

### Recording playback

Once a session ends, its recordings give you a video replay - useful for auditing what an automated run actually did.

## Full walkthrough

Every step above, chained into one script: launch a session in California, load a page, read back the price data, screenshot it, then close it down.

```bash theme={null}
#!/bin/bash
# Your token, copied from the dashboard's Scraping Browser page.
TOKEN="$NM_BROWSER_TOKEN"

# 1. create a session in California, over HTTP proxy, extra stealth on
SESSION=$(curl -s https://api.browser.nodemaven.com/api/v2/browser/sessions \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"proxy_password":"'"$NM_PROXY_PASSWORD"'","country":"us","region":"california","extra_stealth":true}')
SESSION_ID=$(echo $SESSION | jq -r .data.id)

# 2. navigate
curl -s https://api.browser.nodemaven.com/api/v2/browser/tools/navigate \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"session_id":"'"$SESSION_ID"'","url":"https://example-shop.com/search?q=nike+air+max+95"}'

# 3. read results - extracted data as JSON, plus a screenshot
curl -s https://api.browser.nodemaven.com/api/v2/browser/tools/execute-code \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"session_id":"'"$SESSION_ID"'","code":"[...document.querySelectorAll(\".price\")].map(e=>e.textContent)"}'

curl -s https://api.browser.nodemaven.com/api/v2/browser/tools/screenshot \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"session_id":"'"$SESSION_ID"'"}' | jq -r .data.screenshot | base64 -d > result.png

# 4. done
curl -s -X DELETE https://api.browser.nodemaven.com/api/v2/browser/sessions/$SESSION_ID \
  -H "Authorization: Bearer $TOKEN"
```

***

For any questions contact [support@nodemaven.com](mailto:support@nodemaven.com).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.