---
title: "Playwright Browser Contexts: Isolated Sessions for Multi-Account AI Agents"
description: "Learn how to use Playwright browser contexts to create isolated sessions with separate cookies, storage, and authentication state for multi-account AI agents with proxy rotation."
canonical: https://callsphere.ai/blog/playwright-browser-contexts-isolated-sessions-multi-account-ai-agents
category: "Learn Agentic AI"
tags: ["Playwright", "Browser Contexts", "Session Isolation", "Multi-Account", "AI Agents"]
author: "CallSphere Team"
published: 2026-03-18T00:00:00.000Z
updated: 2026-05-06T01:02:46.208Z
---

# Playwright Browser Contexts: Isolated Sessions for Multi-Account AI Agents

> Learn how to use Playwright browser contexts to create isolated sessions with separate cookies, storage, and authentication state for multi-account AI agents with proxy rotation.

## What Are Browser Contexts and Why Do AI Agents Need Them?

A browser context in Playwright is equivalent to an incognito browser profile. Each context has its own cookies, local storage, session storage, and cache — completely isolated from other contexts. Critically, multiple contexts can run simultaneously within a single browser instance, sharing the browser process but maintaining complete session isolation.

For AI agents, contexts solve a fundamental problem: running multiple independent sessions without launching separate browser processes. An agent can manage five different user accounts, each authenticated separately, all within one browser. This is more memory-efficient than launching five separate browsers and faster than sequentially logging in and out of a single session.

## Creating and Using Browser Contexts

The basic pattern for creating isolated contexts:

```mermaid
flowchart LR
    AGENT(["Agent wants
to run code"])
    POLICY{"Policy check
allow list"}
    SANDBOX[("Ephemeral sandbox
Firecracker or gVisor")]
    NETPOL["Egress firewall
deny by default"]
    LIMIT["Resource limits
CPU, mem, time"]
    EXEC["Run untrusted code"]
    LOG[("Audit log")]
    OUT(["Captured stdout
or error"])
    DENY(["Refuse"])
    AGENT --> POLICY
    POLICY -->|Allow| SANDBOX
    POLICY -->|Block| DENY
    SANDBOX --> NETPOL --> LIMIT --> EXEC --> LOG --> OUT
    style POLICY fill:#f59e0b,stroke:#d97706,color:#1f2937
    style SANDBOX fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
    style EXEC fill:#4f46e5,stroke:#4338ca,color:#fff
    style OUT fill:#059669,stroke:#047857,color:#fff
    style DENY fill:#dc2626,stroke:#b91c1c,color:#fff
```

```python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()

    # Create two isolated contexts
    context_a = browser.new_context()
    context_b = browser.new_context()

    # Each context has its own page(s)
    page_a = context_a.new_page()
    page_b = context_b.new_page()

    # Navigate independently
    page_a.goto("https://example.com")
    page_b.goto("https://example.com")

    # Actions in context_a do not affect context_b
    # Cookies set in page_a are invisible to page_b

    context_a.close()
    context_b.close()
    browser.close()
```

## Configuring Contexts with Different Identities

Each context can have its own viewport, user agent, locale, timezone, and geolocation:

```python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()

    # Desktop user in New York
    desktop_context = browser.new_context(
        viewport={"width": 1920, "height": 1080},
        user_agent=(
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36"
        ),
        locale="en-US",
        timezone_id="America/New_York",
        geolocation={"latitude": 40.7128, "longitude": -74.0060},
        permissions=["geolocation"],
    )

    # Mobile user in London
    mobile_context = browser.new_context(
        viewport={"width": 375, "height": 812},
        user_agent=(
            "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) "
            "AppleWebKit/605.1.15 Mobile/15E148"
        ),
        locale="en-GB",
        timezone_id="Europe/London",
        geolocation={"latitude": 51.5074, "longitude": -0.1278},
        permissions=["geolocation"],
        is_mobile=True,
        has_touch=True,
    )

    desktop_page = desktop_context.new_page()
    mobile_page = mobile_context.new_page()

    # Same URL, different experiences
    desktop_page.goto("https://example.com")
    mobile_page.goto("https://example.com")

    desktop_page.screenshot(path="desktop_view.png")
    mobile_page.screenshot(path="mobile_view.png")

    desktop_context.close()
    mobile_context.close()
    browser.close()
```

## Saving and Restoring Authentication State

One of the most powerful context features is persisting and restoring session state:

```python
from playwright.sync_api import sync_playwright

# Step 1: Login and save the authentication state
def save_auth_state(login_url, username, password, state_file):
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        context = browser.new_context()
        page = context.new_page()

        page.goto(login_url)
        page.get_by_label("Username").fill(username)
        page.get_by_label("Password").fill(password)
        page.get_by_role("button", name="Sign In").click()
        page.wait_for_url("**/dashboard**")

        # Save cookies, local storage, session storage
        context.storage_state(path=state_file)
        print(f"Auth state saved to {state_file}")

        context.close()
        browser.close()

# Step 2: Use saved state in future sessions
def use_saved_auth(state_file):
    with sync_playwright() as p:
        browser = p.chromium.launch()

        # Load the saved authentication state
        context = browser.new_context(storage_state=state_file)
        page = context.new_page()

        # Navigate directly to authenticated pages
        page.goto("https://example.com/dashboard")
        print(f"Logged in as: {page.locator('.user-name').text_content()}")

        context.close()
        browser.close()

# Save once
save_auth_state(
    "https://example.com/login",
    "ai_agent", "password123",
    "auth_state.json"
)

# Reuse many times
use_saved_auth("auth_state.json")
```

## Managing Cookies Directly

For fine-grained cookie control:

```python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    context = browser.new_context()

    # Add cookies before navigation
    context.add_cookies([
        {
            "name": "session_id",
            "value": "abc123",
            "domain": "example.com",
            "path": "/",
            "httpOnly": True,
            "secure": True,
        },
        {
            "name": "preferences",
            "value": "dark_mode=true",
            "domain": "example.com",
            "path": "/",
        },
    ])

    page = context.new_page()
    page.goto("https://example.com")

    # Read current cookies
    cookies = context.cookies()
    for cookie in cookies:
        print(f"{cookie['name']}: {cookie['value']}")

    # Clear all cookies
    context.clear_cookies()

    context.close()
    browser.close()
```

## Proxy Rotation with Contexts

Each context can use a different proxy, enabling IP rotation for scraping agents:

```python
from playwright.sync_api import sync_playwright

PROXIES = [
    {"server": "http://proxy1.example.com:8080"},
    {"server": "http://proxy2.example.com:8080"},
    {"server": "http://proxy3.example.com:8080",
     "username": "user", "password": "pass"},
]

def scrape_with_proxy_rotation(urls: list[str]):
    with sync_playwright() as p:
        browser = p.chromium.launch()
        results = []

        for i, url in enumerate(urls):
            proxy = PROXIES[i % len(PROXIES)]

            context = browser.new_context(proxy=proxy)
            page = context.new_page()

            try:
                page.goto(url, wait_until="networkidle", timeout=15000)
                results.append({
                    "url": url,
                    "title": page.title(),
                    "proxy": proxy["server"],
                })
            except Exception as e:
                print(f"Failed {url} via {proxy['server']}: {e}")
            finally:
                context.close()

        browser.close()
        return results
```

## Multi-Account Agent Pattern

Here is a complete pattern for an AI agent managing multiple accounts simultaneously:

```python
from dataclasses import dataclass
from playwright.sync_api import sync_playwright, BrowserContext

@dataclass
class AccountSession:
    username: str
    context: BrowserContext
    page: object  # Page type

class MultiAccountAgent:
    def __init__(self):
        self.sessions: dict[str, AccountSession] = {}

    def add_account(self, browser, username: str, state_file: str):
        context = browser.new_context(storage_state=state_file)
        page = context.new_page()
        self.sessions[username] = AccountSession(
            username=username,
            context=context,
            page=page,
        )
        print(f"Loaded session for {username}")

    def perform_action(self, username: str, action_fn):
        session = self.sessions[username]
        return action_fn(session.page)

    def close_all(self):
        for session in self.sessions.values():
            session.context.close()
        self.sessions.clear()

# Usage
with sync_playwright() as p:
    browser = p.chromium.launch()
    agent = MultiAccountAgent()

    # Load saved authentication states
    agent.add_account(browser, "user_alice", "auth_alice.json")
    agent.add_account(browser, "user_bob", "auth_bob.json")

    # Perform actions on different accounts
    alice_data = agent.perform_action(
        "user_alice",
        lambda page: (
            page.goto("https://example.com/dashboard"),
            page.locator(".balance").text_content(),
        )
    )

    bob_data = agent.perform_action(
        "user_bob",
        lambda page: (
            page.goto("https://example.com/dashboard"),
            page.locator(".balance").text_content(),
        )
    )

    agent.close_all()
    browser.close()
```

## FAQ

### How many browser contexts can run simultaneously in one browser?

There is no hard-coded limit in Playwright. The practical limit depends on available memory. Each context uses approximately 10-30 MB of RAM depending on the pages loaded. On a machine with 8 GB of RAM, you can comfortably run 50-100 lightweight contexts. For memory-constrained environments, create contexts on demand and close them after use rather than keeping all of them open.

### Do browser contexts share the browser cache?

No. Each context has its own isolated cache, cookies, and storage. This means the same resource (JavaScript file, image, CSS) may be downloaded separately for each context. If you need shared caching to reduce bandwidth, use a caching proxy between Playwright and the internet rather than relying on browser-level caching.

### Can I transfer cookies or storage from one context to another?

Yes. Export the state from one context with `context_a.storage_state()` (returns a dictionary) and pass it to another context with `browser.new_context(storage_state=state_dict)`. You can also selectively read cookies from one context and add them to another using `context.cookies()` and `context.add_cookies()`.

---

#BrowserContexts #SessionIsolation #MultiAccount #Playwright #ProxyRotation #AIAgents #WebAutomation

---

Source: https://callsphere.ai/blog/playwright-browser-contexts-isolated-sessions-multi-account-ai-agents
