Skip to main content

Scraping Browser API reference

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

Written by NodeMaven

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 & 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.

1. Copy your token

2. Configure & launch

Open the Scraping Browser page in the NodeMaven dashboard and copy the API token shown there. Every call below is authenticated with it.

Pick a country/city, stealth options, and proxy protocol, then create a session.

dashboard → Scraping Browser

POST /sessions

3. Automate it

4. Read the results

Navigate, click, type, or run a script - or connect your own Playwright/Selenium/Puppeteer script directly.

Pull back the page's HTML, a screenshot, a PDF, or your script's return value - then close the session.

/tools/*, CDP, Selenium

text · json · png · pdf

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.

Authentication

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

Where to get it

How to send it

The Scraping Browser page in the NodeMaven dashboard displays your API token. Copy it from there - there's nothing to generate or exchange.

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.

# Every request uses the token from your dashboard

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

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.

Errors & 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.

{ "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

Max session lifetime

30 minutes

Idle timeout

10 minutes

Concurrent sessions per account

10

Saved profiles per account

10

API token lifetime

7 days

Proxy & 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

200 Response


{
"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"]
}
}

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.

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

200 Response

{
"data": [
{
"code": "los-angeles",
"name": "Los Angeles",
"availability": "high",
"country_code": "us",
"region_code": "california"
}
]
}

503 location data not configured for this deployment

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.

Request body

{
"connection_type": "residential",
"session_type": "sticky",
"protocol": "http",
"country": "us",
"region": "california",
"filter_mode": "quality_speed"
}

200 Response

{
"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"
}
}

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.

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.

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

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.

Sessions

A session is one live, disposable Chrome browser, already routed through your proxy. Everything under Automation & 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.

Request body

{
"proxy_password": "YOUR_PROXY_PASSWORD",
"country": "us",
"region": "california",
"session_type": "sticky",
"extra_stealth": true
}

200 Response

{
"data": {
"id": "ses_8f2a41c9",
"cdp_url":
"wss://browser.nodemaven.com/sessions/ses_8f2a41c9?token=...",
"status": "running"
}
}

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=.

200 Response

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

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

GET /api/v2/browser/sessions/{id}

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

200 Response

{
"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=..."
}
}

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).

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.

200 Response

{
"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.

200 Response

{ "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.

200 Response

{
"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"
}
]
}

video_url is short-lived (~10 minutes) - re-fetch this endpoint at play time rather than caching the URL.

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.

200 Response

{ "data": { "status": "success" } }

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.

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.

200 Response

{
"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.

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 & 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.

Request

{ "session_id": "ses_8f2a41c9", "url": "https://example.com/search?q=nike" }

200 Response

{ "data": { "status": "ok" } }

POST /api/v2/browser/tools/content

Returns the current page's full rendered HTML.

Request

{ "session_id": "ses_8f2a41c9" }

200 Response

{ "data": { "content": "<html>...</html>" } }

POST /api/v2/browser/tools/screenshot

Captures the current page as a PNG.

Request

{ "session_id": "ses_8f2a41c9" }

200 Response

{ "data": { "screenshot": "iVBORw0KGgo...", "format": "png" } }

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."

Request

{
"session_id": "ses_8f2a41c9",
"code": "document.querySelectorAll('.price').length"
}

200 Response

{ "data": { "result": 48 } }

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.

Request

{ "session_id": "ses_8f2a41c9" }

200 Response

{ "data": { "pdf": "JVBERi0xLjQK...", "format": "pdf" } }

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.

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.

// playwright
const browser = await chromium.connectOverCDP(cdpUrl);

Selenium

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

# 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.

#!/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: [email protected]

Did this answer your question?