Sessions

A Session is a running browser instance. Each Session has a unique CDP WebSocket URL that can be connected to and controlled by tools like Puppeteer and Playwright.

Create a Session

POST /v1/sessions
X-API-Key: <api_key>

# Optional parameters
{
  "contextId": "ctx_xxx",
  "useProxy": true,
  "proxyGeolocation": { "country": "US", "city": "newyork" },
  // or BYOP: "proxyId": "prx_xxx"  /  "proxy": { "type":"http", "host":"...", "port":8080 }
  "url": "https://example.com"
}

# Returns
{
  "id": "ses_xxxx",
  "cdpUrl": "wss://browserforest.com/ws/session/ses_xxxx",
  "status": "active",
  "proxy": null,
  "proxyProvider": "brightdata",
  "proxyGeolocation": { "country": "US", "city": "newyork" },
  "contextId": "ctx_xxx",
  "createdAt": "2024-01-01T00:00:00Z"
}
Note: Session creation is synchronous — when the response returns, the browser is ready and you can immediately connect via CDP.

Managed residential proxy (useProxy)

Set useProxy: true to route traffic through platform Bright Data residential proxies. Requires Credits balance > 0. Mutually exclusive with proxy / proxyId. Proxy bandwidth is billed separately in Credits (default ~$10/GB). Response includes proxyProvider / proxyGeolocation and never returns upstream credentials.

List Sessions

GET /v1/sessions
X-API-Key: <api_key>

# Returns
[
  {
    "id": "ses_xxxx",
    "cdpUrl": "wss://browserforest.com/ws/session/ses_xxxx",
    "status": "active",
    "contextId": "ctx_xxx",
    "createdAt": "2024-01-01T00:00:00Z"
  }
]

Get a Session

GET /v1/sessions/:id
X-API-Key: <api_key>

# Returns same as above, single Session object

Stop a Session

DELETE /v1/sessions/:id
X-API-Key: <api_key>

# Returns 204 No Content

When a Session is stopped, if it is associated with a Context, the browser state (cookies, localStorage, etc.) is automatically saved to a Context snapshot, and cookies are synced to the database. The next Session using the same Context will automatically restore the previous state.

Session Cookies (Export / Inject)

No need to hand-write CDP — read and write cookies directly from active Sessions. Requires sessions:read permission (export) / sessions:write permission (inject).

Export Cookies

GET /v1/sessions/:id/cookies?domain=.example.com
X-API-Key: <api_key>

# Returns
{
  "sessionId": "ses_xxxx",
  "exportedAt": "2026-06-05T10:00:00Z",
  "count": 2,
  "cookies": [
    {
      "name": "session_token",
      "value": "...",
      "domain": ".example.com",
      "path": "/",
      "secure": true,
      "httpOnly": true
    }
  ]
}

Inject Cookies

PUT /v1/sessions/:id/cookies
X-API-Key: <api_key>
Content-Type: application/json

{
  "cookies": [
    { "name": "token", "value": "...", "domain": ".example.com", "path": "/", "secure": true }
  ],
  "mode": "merge"
}

# mode: merge (default) | replace
# Returns { "sessionId": "ses_xxxx", "count": 1, "mode": "merge" }
Note: The Session must be in active status. HttpOnly cookies can only be read through this API or CDP — document.cookie cannot see them.

Controlling the Browser via CDP

Puppeteer

import puppeteer from 'puppeteer-core';

// Append your API key — the CDP endpoint requires auth
const browser = await puppeteer.connect({
  browserWSEndpoint: `${session.cdpUrl}?key=${API_KEY}`,
});
const page = await browser.newPage();
await page.goto('https://example.com');
await browser.disconnect(); // use disconnect(), not close() — won't close remote browser

Playwright

import { chromium } from 'playwright';

const browser = await chromium.connectOverCDP(`${session.cdpUrl}?key=${API_KEY}`);
const context = browser.contexts()[0];
const page = context.pages()[0];
await page.goto('https://example.com');
await browser.close();

Recording CDP Traffic (Debugging)

While recording, every CDP message on the Session is stored in order, in both directions: dir: "in" is a command sent by your client, dir: "out" is a response or event coming back from the browser. For "did my command go out", "did the browser answer", and "how long did it take", this one log answers all three — no proxy or packet capture needed.

# 1. Start recording — the Session must already be active
POST /v1/sessions/:id/recording/start
X-API-Key: <api_key>

# → { "recordingId": "rec_xxxx", "status": "recording" }

# 2. ...connect over CDP and do your work...

# 3. Stop
POST /v1/sessions/:id/recording/stop
X-API-Key: <api_key>

# → { "recordingId": "rec_xxxx", "eventCount": 250, "durationMs": 36537 }

# 4. Fetch the log
GET /v1/recordings/rec_xxxx?includeEvents=true
X-API-Key: <api_key>

# → { "events": [
#     { "ts": 28,  "dir": "in",  "data": "{\"id\":1,\"method\":\"Page.enable\"}" },
#     { "ts": 100, "dir": "out", "data": "{\"id\":1,\"result\":{}}" }
#   ] }

1. Call start right after creating the Session — recording cannot be turned on retroactively

2. Connect over CDP and work as usual

3. Call stop, then fetch the details with includeEvents=true

Note: The Session must be active when you start. Until you call stop the data sits in Redis with a 2-hour TTL. Only 5 screencast methods are skipped; everything else is recorded. Each event's ts is milliseconds since start.

Session Status

StatusDescription
activeBrowser is running, CDP is available
stoppingStopping, saving Context snapshot
stoppedStopped

Parameters

ParameterTypeDescription
contextIdstringOptional. Associated Context ID for persisting browser state
useProxybooleanOptional. true = platform-managed Bright Data residential proxy
proxyGeolocationobjectOptional. Only with useProxy: { country: ISO-2, city? }
proxyIdstringOptional. Saved BYOP proxy ID (mutually exclusive with useProxy / proxy)
proxyobjectOptional. Inline BYOP proxy (mutually exclusive with useProxy / proxyId)
urlstringOptional. Auto-navigate to this URL after launch