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
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".
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.
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
| Status | Description |
|---|
pending | Request accepted, not yet picked up for provisioning. |
processing | The browser pod is being provisioned and configured. |
ready | The session is connectable. session.session_id, cdp_url and live_view_url are available. |
completed | The session has finished its lifecycle. |
failed | Provisioning failed. No session was produced. |
cancelled | The 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:
| Phase | Description |
|---|
queued | Waiting for capacity. |
provisioning | The browser pod is starting up. |
configuring | Applying your browser and session configuration. |
ready | The 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.
#!/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.