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

Browser profiles

10

Concurrent active sessions

50

Maximum session duration

30 minutes

Idle timeout

10 minutes

Session recording retention

3 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?