Skip to main content

Overview

POST /v1/sessions/async is the non-blocking variant of POST /v1/sessions. Instead of waiting for the underlying browser pod to provision, it returns a request_id immediately and provisions the session in the background. You then poll GET /v1/sessions/async/{request_id}/status until the request reaches the ready status, at which point the response includes the resolved session_id, cdp_url and live_view_url. This pattern is useful when you want to:
  • Kick off many sessions in parallel without holding open long-lived HTTP requests.
  • Avoid request timeouts while large or proxied sessions are being provisioned.
  • Decouple session creation from session consumption (for example, queue the work and connect later).

How It Works

1

Create the async request

Send a POST to /v1/sessions/async with your browser configuration. The response returns immediately with a request_id and status: "pending".
2

Poll for readiness

Call GET /v1/sessions/async/{request_id}/status on an interval. The request moves through the provisioning phases until status becomes ready.
3

Connect to the session

Once ready, read session_id, cdp_url and live_view_url from the embedded session object and connect over CDP as you would for a standard session.

Create an Async Session

const API_BASE = 'https://api.anchorbrowser.io';

const headers = {
  'anchor-api-key': process.env.ANCHOR_API_KEY,
  'Content-Type': 'application/json',
};

const browserConfiguration = {
  session: {
    proxy: { active: true },
    timeout: { idle_timeout: 5, max_duration: 25 },
    recording: { active: true },
  },
};

const response = await fetch(`${API_BASE}/v1/sessions/async`, {
  method: 'POST',
  headers,
  body: JSON.stringify(browserConfiguration),
});

const { data } = await response.json();
console.log('request_id:', data.request_id, 'status:', data.status);
The request body is identical to the standard Start Browser Session request, so any configuration you can pass to POST /v1/sessions is also accepted here. A successful response is returned immediately:
{
  "data": {
    "request_id": "b1f9e0a2-7c3d-4f5a-9b2e-1d6c8a4f0e21",
    "status": "pending",
    "session_id": null
  }
}

Poll for Readiness

Poll the status endpoint using the request_id until status becomes ready.
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

async function pollUntilReady(requestId) {
  while (true) {
    const response = await fetch(`${API_BASE}/v1/sessions/async/${requestId}/status`, { headers });
    const { data } = await response.json();

    if (data.status === 'ready') return data;
    if (data.status === 'failed' || data.status === 'cancelled') {
      throw new Error(`Async request reached terminal status: ${data.status}`);
    }

    await sleep(3_000);
  }
}
A response while provisioning looks like:
{
  "data": {
    "request_id": "b1f9e0a2-7c3d-4f5a-9b2e-1d6c8a4f0e21",
    "status": "processing",
    "created_at": "2026-06-04T11:00:00.000Z",
    "progress": { "current_phase": "provisioning" }
  }
}
Once ready, the embedded session object is populated:
{
  "data": {
    "request_id": "b1f9e0a2-7c3d-4f5a-9b2e-1d6c8a4f0e21",
    "status": "ready",
    "created_at": "2026-06-04T11:00:00.000Z",
    "progress": { "current_phase": "ready" },
    "session": {
      "session_id": "9c0d1e2f-3a4b-5c6d-7e8f-9a0b1c2d3e4f",
      "status": "running",
      "cdp_url": "wss://connect.anchorbrowser.io?...",
      "live_view_url": "https://live.anchorbrowser.io/..."
    }
  }
}

Request Statuses

StatusDescription
pendingRequest accepted, not yet picked up for provisioning.
processingThe browser pod is being provisioned and configured.
readyThe session is connectable. session.session_id, cdp_url and live_view_url are available.
completedThe session has finished its lifecycle.
failedProvisioning failed. No session was produced.
cancelledThe request was cancelled before a session was produced.

Provisioning Phases

The progress.current_phase field reports finer-grained progress while status is pending or processing:
PhaseDescription
queuedWaiting for capacity.
provisioningThe browser pod is starting up.
configuringApplying your browser and session configuration.
readyThe session is up and connectable.

Complete Example

The following script spawns multiple async sessions in parallel, polls each one until it is ready, and prints the connection details. Set ANCHOR_API_KEY in your environment before running.
node.js
#!/usr/bin/env node

const ANCHOR_API_KEY = process.env.ANCHOR_API_KEY;

const SESSION_COUNT = 2;
const POLL_INTERVAL_MS = 3_000;

const API_BASE = 'https://api.anchorbrowser.io';

const browserConfiguration = {
  session: {
    proxy: { active: true },
    timeout: { idle_timeout: 5, max_duration: 25 },
    recording: { active: true },
  },
};

const headers = {
  'anchor-api-key': ANCHOR_API_KEY,
  'Content-Type': 'application/json',
};

const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

async function createAsyncSession(label) {
  const response = await fetch(`${API_BASE}/v1/sessions/async`, {
    method: 'POST',
    headers,
    body: JSON.stringify(browserConfiguration),
  });
  const json = await response.json();
  console.log(`[${label}] create response:`, JSON.stringify(json, null, 2));
  return json.data;
}

async function pollUntilReady(requestId, label) {
  while (true) {
    const response = await fetch(`${API_BASE}/v1/sessions/async/${requestId}/status`, { headers });
    const json = await response.json();
    console.log(`[${label}] poll response:`, JSON.stringify(json, null, 2));

    const status = json.data ?? {};
    if (status.status === 'ready') return status;
    if (status.status === 'failed' || status.status === 'cancelled') {
      throw new Error(`[${label}] async request reached terminal status: ${status.status}`);
    }

    await sleep(POLL_INTERVAL_MS);
  }
}

async function runOne(label) {
  const created = await createAsyncSession(label);
  const status = await pollUntilReady(created.request_id, label);
  const session = status.session;

  console.log(`\n[${label}] READY — session info:`);
  console.log(`  request_id    : ${created.request_id}`);
  console.log(`  session_id    : ${session.session_id}`);
  console.log(`  cdp_url       : ${session.cdp_url}`);
  console.log(`  live_view_url : ${session.live_view_url}`);
  console.log(`  status        : ${session.status}`);
  console.log(`  full session  :`, JSON.stringify(session, null, 2));
}

(async () => {
  const labels = Array.from({ length: SESSION_COUNT }, (_, i) => `s${i + 1}`);
  console.log(`Spawning ${SESSION_COUNT} async session(s) on ${API_BASE}\n`);
  await Promise.all(labels.map(runOne));
})();
Once a session is ready, connect to it over CDP using the returned cdp_url, exactly as you would for a standard session. The session honors the same idle_timeout and max_duration settings you passed in the configuration, so make sure to connect before the idle timeout elapses.