Multi-Session Browser Automation: Running Parallel Workflows

Technical Dive
Jul 18
by Idan Raman
Parallel Sessions

A single browser session is easy to reason about: create it, drive it, close it. The moment a workflow needs to check a hundred vendor portals, price pages, or account dashboards on a schedule, that model breaks—not because the automation logic changes, but because running one browser at a time turns a five-minute job into a five-hour one. Parallelism is the fix, but "just run more sessions" hides a real orchestration problem: how many to run at once, how to provision them without your own process blocking on each one, and how to keep a fleet of browsers from turning into a fleet of zombie Chromium processes eating memory nobody is tracking.

Why More Sessions Isn't Automatically Faster

Self-hosting Chromium for concurrency means every session is a process consuming real CPU and a few hundred megabytes of RAM, so scaling from ten sessions to a hundred is an infrastructure problem before it's an automation problem. Handing session lifecycle to a cloud browser provider removes the capacity-planning work, but the orchestration question doesn't disappear—it just moves into your code: are you creating sessions one at a time in a loop, or actually running the create calls concurrently?

Running Sessions Concurrently

Anchor's sessions.create() call is a normal async request, which means fanning it out is just standard concurrency in whatever language you're already using—no special "parallel mode" to opt into:

import Anchorbrowser from 'anchorbrowser';
import { chromium } from 'playwright-core';

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

async function checkPortal(url) {
  const session = await anchorClient.sessions.create();
  const browser = await chromium.connectOverCDP(session.data.cdp_url);
  const page = browser.contexts()[0].pages()[0] ?? (await browser.newPage());
  await page.goto(url);
  const title = await page.title();
  await browser.close();
  return { url, title };
}

const targets = ['https://vendor-a.example.com', 'https://vendor-b.example.com', 'https://vendor-c.example.com'];
const results = await Promise.all(targets.map(checkPortal));

This scales cleanly for tens of concurrent sessions. Past that, blocking on each create() call to finish provisioning before moving on becomes the bottleneck, not your automation logic.

Provisioning Without Blocking

For workloads that need to kick off many sessions without holding open a long HTTP request per session, Anchor's async session endpoint returns a request_id immediately and provisions in the background, so you can fire off a batch of requests and poll each one for readiness instead of waiting in line:

const { data } = await anchorClient.post('/v1/sessions/async', {
  body: { browser: { headless: { active: true } } },
});
// data.request_id, data.status === 'pending'
// poll GET /v1/sessions/async/{request_id}/status until status === 'ready'

Going Beyond Ad Hoc Concurrency

When the job is genuinely large—checking thousands of listings, running a load test, sweeping a portal catalog—creating sessions one request at a time, even concurrently, adds overhead you don't need. Anchor's Batch Sessions API takes a single count and one shared configuration, and provisions all of them as one asynchronous job you poll for progress:

const response = await fetch('https://api.anchorbrowser.io/v1/batch-sessions', {
  method: 'POST',
  headers: {
    'anchor-api-key': process.env.ANCHOR_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    count: 200,
    configuration: {
      browser: { headless: { active: true }, viewport: { width: 1440, height: 900 } },
      session: { timeout: { idle_timeout: 10, max_duration: 300 } },
    },
    metadata: { project: 'vendor-portal-sweep' },
  }),
});
const { data } = await response.json();
// poll GET /v1/batch-sessions/{data.batch_id} until status === 'completed',
// then connect to each session's cdp_url from the sessions array

A single batch request supports up to 1,000 sessions with shared configuration, which covers the vast majority of scraping sweeps and load tests without hand-rolling a queue.

Picking the Right Layer

The three approaches aren't competing—they're different altitudes of the same problem. Concurrent sessions.create() calls work fine for dozens of parallel jobs with per-session logic. Async session creation removes head-of-line blocking when provisioning takes a while. Batch sessions remove the loop entirely when every session shares the same configuration and you just need many of them, fast.

If you're running parallel workflows today with a hand-built pool of self-hosted browsers, Anchor handles session provisioning, isolation, and scaling so your code focuses on the automation logic instead of process management. Check out the Batch Sessions docs to get a fleet running in a single call.

Stay ahead in browser automation

We respect your inbox. Privacy policy

Welcome aboard! Thanks for signing up
Oops! Something went wrong while submitting the form.