> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anchorbrowser.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Async Session

> Create browser sessions without blocking and poll until they are ready

<Note>
  Not sure which approach to use? See [Browser Sessions](/quickstart/browser-sessions#how-to-create) for sync vs async vs batch.
</Note>

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

<Steps>
  <Step title="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"`.
  </Step>

  <Step title="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`.
  </Step>

  <Step title="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.
  </Step>
</Steps>

## Create an Async Session

<CodeGroup>
  ```javascript node.js theme={null}
  import AnchorBrowser from 'anchorbrowser';

  const anchorClient = new AnchorBrowser({ apiKey: process.env.ANCHOR_API_KEY });

  const browserConfiguration = {
    browser: {
      headless: { active: false },
      adblock: { active: true },
      captcha_solver: { active: true },
    },
    session: {
      proxy: { active: true, free_roam: false },
      recording: { active: true },
    },
  };

  const { data } = await anchorClient.post('/v1/sessions/async', {
    body: browserConfiguration,
  });

  console.log('request_id:', data.request_id, 'status:', data.status);
  ```

  ```python python theme={null}
  import os
  from anchorbrowser import Anchorbrowser

  anchor_client = Anchorbrowser(api_key=os.getenv('ANCHOR_API_KEY'))

  browser_configuration = {
      'browser': {
          'headless': {'active': False},
          'adblock': {'active': True},
          'captcha_solver': {'active': True},
      },
      'session': {
          'proxy': {'active': True, 'free_roam': False},
          'recording': {'active': True},
      },
  }

  response = anchor_client.post('/v1/sessions/async', body=browser_configuration)
  data = response['data']

  print('request_id:', data['request_id'], 'status:', data['status'])
  ```
</CodeGroup>

The request body is identical to the standard [Start Browser Session](/api-reference) request,
so any configuration you can pass to `POST /v1/sessions` is also accepted here.

A successful response is returned immediately:

```json theme={null}
{
  "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`.

<CodeGroup>
  ```javascript node.js theme={null}
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

  async function pollUntilReady(requestId) {
    while (true) {
      const { data } = await anchorClient.get(`/v1/sessions/async/${requestId}/status`);

      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);
    }
  }
  ```

  ```python python theme={null}
  import time

  def poll_until_ready(request_id):
      while True:
          response = anchor_client.get(f'/v1/sessions/async/{request_id}/status')
          data = response['data']

          if data['status'] == 'ready':
              return data
          if data['status'] in ('failed', 'cancelled'):
              raise RuntimeError(f"Async request reached terminal status: {data['status']}")

          time.sleep(3)
  ```
</CodeGroup>

A response while provisioning looks like:

```json theme={null}
{
  "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:

```json theme={null}
{
  "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.

<CodeGroup>
  ```javascript node.js theme={null}
  import AnchorBrowser from 'anchorbrowser';

  const anchorClient = new AnchorBrowser({ apiKey: process.env.ANCHOR_API_KEY });

  const SESSION_COUNT = 2;
  const POLL_INTERVAL_MS = 3_000;

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

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

  async function createAsyncSession(label) {
    const { data } = await anchorClient.post('/v1/sessions/async', {
      body: browserConfiguration,
    });
    console.log(`[${label}] create response:`, data);
    return data;
  }

  async function pollUntilReady(requestId, label) {
    while (true) {
      const { data } = await anchorClient.get(`/v1/sessions/async/${requestId}/status`);
      console.log(`[${label}] poll response:`, data);

      if (data.status === 'ready') return data;
      if (data.status === 'failed' || data.status === 'cancelled') {
        throw new Error(`[${label}] async request reached terminal status: ${data.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}`);
  }

  (async () => {
    const labels = Array.from({ length: SESSION_COUNT }, (_, i) => `s${i + 1}`);
    console.log(`Spawning ${SESSION_COUNT} async session(s)\n`);
    await Promise.all(labels.map(runOne));
  })().catch(console.error);
  ```

  ```python python theme={null}
  import os
  import time
  from anchorbrowser import Anchorbrowser

  anchor_client = Anchorbrowser(api_key=os.getenv('ANCHOR_API_KEY'))

  SESSION_COUNT = 2
  POLL_INTERVAL_SEC = 3

  browser_configuration = {
      'session': {
          'proxy': {'active': True},
          'timeout': {'idle_timeout': 5, 'max_duration': 25},
          'recording': {'active': True},
      },
  }

  def create_async_session(label):
      response = anchor_client.post('/v1/sessions/async', body=browser_configuration)
      data = response['data']
      print(f'[{label}] create response:', data)
      return data

  def poll_until_ready(request_id, label):
      while True:
          response = anchor_client.get(f'/v1/sessions/async/{request_id}/status')
          data = response['data']
          print(f'[{label}] poll response:', data)

          if data['status'] == 'ready':
              return data
          if data['status'] in ('failed', 'cancelled'):
              raise RuntimeError(f"[{label}] async request reached terminal status: {data['status']}")

          time.sleep(POLL_INTERVAL_SEC)

  def run_one(label):
      created = create_async_session(label)
      status = poll_until_ready(created['request_id'], label)
      session = status['session']

      print(f'\n[{label}] READY — session info:')
      print(f"  request_id    : {created['request_id']}")
      print(f"  session_id    : {session['session_id']}")
      print(f"  cdp_url       : {session['cdp_url']}")
      print(f"  live_view_url : {session['live_view_url']}")
      print(f"  status        : {session['status']}")

  if __name__ == '__main__':
      labels = [f's{i + 1}' for i in range(SESSION_COUNT)]
      print(f'Spawning {SESSION_COUNT} async session(s)\n')
      for label in labels:
          run_one(label)
  ```
</CodeGroup>

<Note>
  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.
</Note>
