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:
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:
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:
See AI Voice Agents Handle Real Calls
Book a free demo or calculate how much you can save with AI voice automation.
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:
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:
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:
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
CallSphere Team
Expert insights on AI voice agents and customer communication automation.
Try CallSphere AI Voice Agents
See how AI voice agents work for your industry. Live demo available -- no signup required.