← Blog

BLOG

Selenium Playwright Headless Browser Resource Usage Multi Session

Selenium Playwright headless browser resource usage multi session: why local Chromium fails at scale and how hosted browsers fix it.

September 7, 202610 min readRemote Browser

# Selenium Playwright Headless Browser Resource Usage Multi Session

If you are running Selenium or Playwright headless browser automation across multiple concurrent sessions, you have likely hit the wall: memory exhaustion, CPU spikes, and sessions that die when a cloud worker restarts. The core problem is that Selenium Playwright headless browser resource usage multi session workloads are fundamentally different from running a single test locally. Each Chromium instance can consume 300–500 MB of RAM, and when you multiply that by dozens of sessions, the math breaks quickly.

This guide explains why local headless browsers fail under multi-session load, what the real resource bottlenecks are, and how a hosted browser runtime like Remote Browser solves the concurrency problem without forcing you to rewrite your Playwright or Selenium code.

The Real Cost of Headless Browser Sessions

Before optimizing, you need to understand what actually consumes resources in a headless Chromium session. It is not just the page content. The browser process tree includes:

  • Browser process: The main process, typically 100–200 MB baseline.
  • Renderer processes: One or more per tab, each consuming 50–150 MB depending on page complexity.
  • GPU process: Even headless, Chromium may spawn a GPU process for compositing.
  • Network service: Handles all HTTP traffic, adds overhead per active connection.
  • DevTools protocol (CDP): If you attach debugging clients, this adds memory for protocol buffers and event queues.

For a single session, this is manageable. For ten concurrent sessions on one machine, you are looking at 3–5 GB of RAM just for browsers. For fifty sessions, you need a dedicated server.

Why Local Multi-Session Fails

The common approach is to run Playwright or Selenium on a single VM and spawn multiple browser contexts. This works for a handful of sessions but degrades quickly:

  1. Memory contention: Chromium does not share memory across browser instances. Each chromium.launch() creates a new process tree.
  2. CPU throttling: When renderers compete for CPU, JavaScript timers slow down, causing timeouts and flaky tests.
  3. Garbage collection pauses: Under memory pressure, V8's garbage collector runs more frequently, stalling page execution.
  4. No isolation: A crash in one session can take down the entire worker process.

The typical workaround is to use browser contexts within a single browser instance. Playwright supports multiple contexts per browser, which shares the browser process but isolates storage. This reduces memory to roughly 50–80 MB per context. However, this approach has its own limits: context creation is not free, and you still have a single point of failure.

The Multi-Session Scaling Problem

When you move from testing to production automation—AI agents, web scraping, or monitoring—the session count grows. You need to answer three questions:

  1. How many concurrent sessions do you need? This determines your baseline resource requirements.
  2. How long does each session live? Long-lived sessions (minutes to hours) change the math versus short-lived test runs.
  3. What happens when a worker dies? If your cloud provider restarts a VM, you lose all in-memory browser state.

This is where the "how to keep browser sessions alive across multiple cloud workers" question becomes critical. Local browser processes are tied to the worker's lifecycle. If the worker dies, the session dies. There is no way around this without externalizing the browser process.

The Context Limit Trap

Some teams try to maximize session count by using Playwright's browser.newContext() heavily. While this is more efficient than launching new browsers, it has practical limits:

  • Each context still has its own JavaScript engine and storage.
  • Contexts share the browser process, so a memory leak in one context affects all.
  • You cannot scale beyond a single machine's RAM.

The Playwright documentation acknowledges this: chromiumSandbox: false is often required when running as root in containers, but that disables OS-level sandboxing, which is a security trade-off. The Playwright Chromium sandbox documentation explains the default behavior and why you might need to disable it in CI environments.

Hosted Browsers: The Production Answer

Remote Browser solves the multi-session resource problem by moving the browser process off your worker entirely. Instead of launching Chromium on your application server, you connect to a hosted Chromium session over CDP.

The architecture is straightforward:

  1. Your application code (Python, Node.js, or any language) makes an API call to Remote Browser.
  2. Remote Browser provisions an isolated Chromium session in its infrastructure.
  3. Your code connects via CDP using Playwright's connectOverCDP or Selenium's WebDriver protocol.
  4. The session persists independently of your worker's lifecycle.

This changes the resource equation completely. Your worker only needs enough memory for your application logic, not for browser processes. The browser sessions run on dedicated infrastructure optimized for Chromium.

Resource Usage Comparison

ApproachMemory per SessionCPU per SessionSession IsolationWorker Failure Impact
Local Playwright launch300–500 MBHigh (full renderer)None (shared process)Session lost
Local browser contexts50–80 MBMedium (shared process)Partial (storage isolated)Session lost
Selenium Grid (local)300–500 MB per nodeHighGood (separate nodes)Session lost on node failure
Hosted browser (Remote Browser)0 MB on your worker0% on your workerFull (dedicated session)Session survives

The table above shows the fundamental advantage: hosted browsers move resource consumption off your infrastructure. This is not about optimization; it is about architectural relocation.

Keeping Sessions Alive Across Cloud Workers

The "how to keep browser sessions alive across multiple cloud workers" problem disappears when the browser is not on the worker. With Remote Browser, each session has a stable session ID. Your worker can disconnect and reconnect to the same session without losing state.

Here is a TypeScript example using Playwright's connectOverCDP to attach to a persistent Remote Browser session:

import { chromium } from 'playwright-core';

// Connect to an existing Remote Browser session
// The session ID is stable across worker restarts
const browser = await chromium.connectOverCDP(
  'wss://remote-browser.dev/cdp/session_abc123'
);

// Get the default context from the existing session
const context = browser.contexts()[0];
const page = await context.newPage();

// Perform actions - the page state persists
await page.goto('https://example.com');
await page.fill('#search', 'selenium playwright resource usage');
await page.click('#submit');

// Disconnect - the session stays alive
await browser.close();

// Later, from a different worker:
const browser2 = await chromium.connectOverCDP(
  'wss://remote-browser.dev/cdp/session_abc123'
);
const context2 = browser2.contexts()[0];
// The page is still there with the search results
const url = context2.pages()[0].url();
console.log(`Session preserved: ${url}`);

This pattern enables stateless workers. You can scale horizontally without worrying about which worker owns which browser session. If a worker crashes, another worker can pick up the session ID and continue where the previous one left off.

Selenium Compatibility and Multi-Session

Selenium users face the same resource constraints, but the solution path is slightly different. Selenium's WebDriver protocol is HTTP-based, not CDP-based. Remote Browser supports Selenium by exposing a WebDriver-compatible endpoint that maps to hosted Chromium sessions.

For Selenium multi-session workloads, the key benefit is the same: sessions are not tied to your worker's lifecycle. You can run a Selenium Grid on your side that routes to Remote Browser instead of local Chrome nodes. This gives you:

  • Elastic scaling: Add or remove sessions without provisioning new VMs.
  • Resource isolation: Each session runs in its own hosted browser.
  • Geographic distribution: Sessions can run in different regions to reduce latency.

The trade-off is network latency. Each Selenium command travels over HTTP to the hosted browser. For most automation workloads, this is negligible (10–50 ms per command). For high-frequency interactions, you may need to batch commands or use CDP directly.

Scaling Playwright Browser Workloads Reliably

The question "how to scale playwright browser workloads reliably" has a practical answer: separate browser lifecycle from worker lifecycle. Here is a production checklist:

  1. Use `connectOverCDP` instead of `launch()`: This decouples your code from the browser process.
  2. Design for session reuse: Keep sessions alive for multiple tasks instead of creating and destroying them per task.
  3. Implement reconnection logic: Your worker should handle disconnects gracefully and reconnect to the same session ID.
  4. Monitor session health: Track memory and CPU usage of hosted sessions to detect leaks early.
  5. Set explicit timeouts: Do not rely on default timeouts; configure them based on your workload.

Remote Browser provides usage controls that let you set session timeouts, memory limits, and concurrent session caps. This prevents a runaway agent from consuming excessive resources.

What Is a Browser Agent and Why It Needs a Runtime

A browser agent is an AI system that uses a browser as its interface to the web. Unlike traditional automation scripts, browser agents make decisions based on page content, fill forms, navigate multi-step flows, and adapt to unexpected page states.

Browser agents have different resource patterns than test suites:

  • Longer sessions: Agents may work on a task for minutes or hours.
  • Unpredictable navigation: Agents follow links based on content, not predefined paths.
  • Higher memory variability: Pages visited by agents vary widely in complexity.
  • Need for persistence: Agents must maintain state across API calls to the LLM.

This is why the "agent browser" concept emerged: AI agents need a browser runtime designed for their workload, not a testing tool bolted onto a local Chrome instance. The runtime must handle session persistence, resource isolation, and reconnection—features that local browser launches do not provide.

Production Criteria for Multi-Session Browser Infrastructure

When evaluating your browser infrastructure for multi-session workloads, use these criteria:

Session Isolation

Can one session's crash affect another? In local setups, a browser crash can take down the entire worker. Hosted browsers provide process-level isolation.

Persistence

If your worker restarts, does the session survive? For AI agents and long-running automation, session persistence is non-negotiable.

Resource Governance

Can you set limits on memory, CPU, and session duration? Without governance, a single agent can consume all available resources.

Observability

Can you see what the browser is doing in real time? Remote Browser provides a live viewer for debugging sessions.

Protocol Compatibility

Does the runtime support your existing code? If you use Playwright, you need CDP support. If you use Selenium, you need WebDriver support.

Implementation Patterns for Multi-Session Workloads

Pattern 1: Session Pool

For high-throughput workloads, maintain a pool of pre-warmed sessions. Each session is assigned to a task, then returned to the pool after completion.

# Pseudocode for session pooling with Remote Browser
import asyncio
from playwright.async_api import async_playwright

async def get_session(pool):
    # Pop a session ID from the pool
    session_id = await pool.acquire()
    return session_id

async def release_session(pool, session_id):
    # Return session to the pool
    await pool.release(session_id)

async def main():
    async with async_playwright() as p:
        # Pool of 10 sessions
        pool = await create_session_pool(10)
        
        # Process tasks concurrently
        tasks = [process_task(get_session(pool)) for _ in range(50)]
        await asyncio.gather(*tasks)

Pattern 2: Long-Lived Agent Sessions

For AI agents, create a session at the start of a task and keep it alive until the task completes. The session persists across LLM API calls and any intermediate processing.

Pattern 3: Sharded Workers

Run multiple workers, each handling a subset of sessions. If a worker dies, its sessions are reassigned to other workers using the session ID.

The Bottom Line

Selenium Playwright headless browser resource usage multi session workloads require an architecture that separates browser processes from application workers. Local browser launches consume too much memory and CPU to scale beyond a handful of sessions. Browser contexts are more efficient but still tied to a single machine's resources.

Hosted browser runtimes like Remote Browser solve this by running Chromium in dedicated infrastructure. Your code connects over CDP or WebDriver, sessions persist across worker restarts, and resource usage on your side drops to near zero.

For production automation—whether you are running Selenium tests, Playwright scripts, or AI browser agents—the question is not how to optimize local browser resource usage. The question is whether you should be running browsers locally at all.

To evaluate whether hosted browsers fit your workload, review the Remote Browser documentation or check current pricing and limits. If you are building AI agents that need persistent browser access, read about the production runtime for AI web agents or how remote browsers work as infrastructure.