Documentation Index
Fetch the complete documentation index at: https://mintlify.com/vercel-labs/agent-browser/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Agent Browser supports isolated browser sessions that allow you to:
- Run multiple browser instances concurrently
- Keep each instance’s state (cookies, localStorage) separate
- Persist state across browser restarts
- Test different user flows in parallel
There are two types of session features:
- Session Isolation (
--session): Run multiple concurrent browser instances
- Session Persistence (
--session-name, --profile): Save and restore state
Session Isolation
Multiple Concurrent Sessions
Run multiple isolated browser instances with different session names:
# Terminal 1: Agent controlling site A
agent-browser --session agent1 open site-a.com
agent-browser --session agent1 snapshot
agent-browser --session agent1 click @e1
# Terminal 2: Agent controlling site B (concurrent)
agent-browser --session agent2 open site-b.com
agent-browser --session agent2 snapshot
agent-browser --session agent2 fill @e2 "test"
Each session gets its own:
- Daemon process (separate PID)
- Browser instance (separate Chromium process)
- Cookies and storage (isolated state)
- Navigation history
- Socket/port (for IPC)
Session Architecture
Sessions are isolated at the OS process level:
~/.agent-browser/
├── default.pid # PID for default session
├── default.sock # Socket for default session
├── agent1.pid # PID for agent1 session
├── agent1.sock # Socket for agent1 session
├── agent2.pid # PID for agent2 session
└── agent2.sock # Socket for agent2 session
On Windows, port files replace .sock files:
~/.agent-browser/
├── agent1.port # Port number for agent1
└── agent2.port # Port number for agent2
Ports are deterministically derived from session names:
// From daemon.ts:188-196
function getPortForSession(session: string): number {
let hash = 0;
for (let i = 0; i < session.length; i++) {
hash = (hash << 5) - hash + session.charCodeAt(i);
}
// Port range 49152-65535 (dynamic/private ports)
return 49152 + (Math.abs(hash) % 16383);
}
This ensures the same session name always gets the same port.
Default Session
If you don’t specify --session, the session name defaults to "default":
# These are equivalent:
agent-browser open example.com
agent-browser --session default open example.com
You can also set the session via environment variable:
export AGENT_BROWSER_SESSION=agent1
agent-browser open example.com # Uses agent1 session
Listing Active Sessions
See which sessions are currently running:
agent-browser session list
Active sessions:
→ default
agent1
agent2
The arrow (→) indicates the current session (from --session flag or AGENT_BROWSER_SESSION env var).
In JSON mode:
agent-browser session list --json
{
"success": true,
"data": {
"sessions": ["default", "agent1", "agent2"]
}
}
Session Naming Rules
Session names must be:
- Alphanumeric, hyphens, or underscores only:
/^[a-zA-Z0-9_-]+$/
- No path separators (
/, \\)
- No special characters
This prevents path traversal attacks:
// From state-utils.ts
export function isValidSessionName(name: string): boolean {
return /^[a-zA-Z0-9_-]+$/.test(name);
}
Invalid examples:
# Bad - path traversal
agent-browser --session ../../../etc/passwd open example.com
# Error: Invalid session name
# Bad - special characters
agent-browser --session "user@domain" open example.com
# Error: Invalid session name
Closing Sessions
Close a specific session:
agent-browser --session agent1 close
This:
- Closes the browser for
agent1
- Shuts down the daemon for
agent1
- Removes
agent1.sock and agent1.pid files
Other sessions continue running unaffected.
Session Persistence
Auto-Persist with --session-name
The --session-name flag automatically saves and restores cookies and localStorage:
# First run: login and save state
agent-browser --session-name twitter open twitter.com
agent-browser fill @e1 "username"
agent-browser fill @e2 "password"
agent-browser click @e3 # Login
agent-browser close # Auto-saves state
# Later: state is restored automatically
agent-browser --session-name twitter open twitter.com
# Already logged in!
State files are stored at:
~/.agent-browser/sessions/{session_name}-{session_id}.json
Where:
{session_name} is the value of --session-name
{session_id} is the value of --session (or "default")
Example:
agent-browser --session agent1 --session-name twitter open twitter.com
# Saves to: ~/.agent-browser/sessions/twitter-agent1.json
agent-browser --session agent2 --session-name twitter open twitter.com
# Saves to: ~/.agent-browser/sessions/twitter-agent2.json
This allows different sessions to have separate Twitter logins.
State files contain cookies and localStorage in Playwright’s storage state format:
{
"cookies": [
{
"name": "session_id",
"value": "abc123...",
"domain": ".twitter.com",
"path": "/",
"expires": 1735689600,
"httpOnly": true,
"secure": true,
"sameSite": "Lax"
}
],
"origins": [
{
"origin": "https://twitter.com",
"localStorage": [
{ "name": "theme", "value": "dark" }
]
}
]
}
State Encryption
Encrypt state files at rest with AES-256-GCM:
# Generate a random 256-bit key (64 hex characters)
openssl rand -hex 32
# Set the key
export AGENT_BROWSER_ENCRYPTION_KEY="your-64-char-hex-key"
# State is now encrypted automatically
agent-browser --session-name secure open example.com
Encrypted state files look like:
{
"encrypted": true,
"version": 1,
"iv": "base64-encoded-iv",
"authTag": "base64-encoded-auth-tag",
"ciphertext": "base64-encoded-encrypted-data"
}
The daemon automatically detects encrypted files and decrypts them:
// From browser.ts:1424-1445
if (isEncryptedPayload(parsed)) {
const key = getEncryptionKey();
if (key) {
const decrypted = decryptData(parsed, key);
storageState = JSON.parse(decrypted);
} else {
// Warn: encrypted but no key set
}
}
If the key is wrong or missing, the daemon starts with a fresh session and warns:
[WARN] State file is encrypted but AGENT_BROWSER_ENCRYPTION_KEY not set - starting fresh
State Expiration
Old state files are automatically deleted:
# Default: delete states older than 30 days
agent-browser close # Cleanup runs on shutdown
# Custom expiration
export AGENT_BROWSER_STATE_EXPIRE_DAYS=7
agent-browser close # Cleanup runs on shutdown
Cleanup runs on daemon startup:
// From daemon.ts:338-339
runCleanupExpiredStates();
You can also manually clean up old states:
agent-browser state clean --older-than 7
Persistent Profiles (--profile)
The --profile flag uses Playwright’s persistent context, which stores all browser data:
# Use a persistent profile directory
agent-browser --profile ~/.myapp-profile open myapp.com
# Login once
agent-browser --profile ~/.myapp-profile fill @e1 "user"
agent-browser --profile ~/.myapp-profile fill @e2 "pass"
agent-browser --profile ~/.myapp-profile click @e3
# Later: reuse the authenticated session
agent-browser --profile ~/.myapp-profile open myapp.com/dashboard
Profiles store:
- Cookies and localStorage
- IndexedDB databases
- Service workers
- Browser cache
- Extension state (if using
--extension)
--profile vs --session-name
| Feature | --profile | --session-name |
|---|
| Cookies | ✓ | ✓ |
| localStorage | ✓ | ✓ |
| IndexedDB | ✓ | ✗ |
| Service workers | ✓ | ✗ |
| Browser cache | ✓ | ✗ |
| Extensions | ✓ | ✗ |
| Encryption | ✗ | ✓ (optional) |
| Auto-save | Always | On close |
| Use case | Full browser state | Lightweight auth |
When to use --profile:
- You need full browser state (cache, IndexedDB, etc.)
- You’re using extensions
- You want persistence across commands without explicit save
When to use --session-name:
- You only need cookies and localStorage
- You want encrypted state files
- You want explicit control over when state is saved
Manual State Save/Load
You can also manually save and load state:
# Save state to a file
agent-browser state save ~/my-state.json
# Load state from a file
agent-browser state load ~/my-state.json
# Or use --state flag on any command
agent-browser --state ~/my-state.json open example.com
The state command provides additional features:
# List saved states
agent-browser state list
# Show state summary (without exposing secrets)
agent-browser state show my-state.json
# Rename a state file
agent-browser state rename old.json new.json
# Clear states for current session
agent-browser state clear
# Clear all states
agent-browser state clear --all
Use Cases
Parallel Testing
Test different user flows concurrently:
# Test A: Free user flow
agent-browser --session test-a --session-name free-user open app.com &
# Test B: Premium user flow
agent-browser --session test-b --session-name premium-user open app.com &
# Tests run in parallel without interfering
Multi-Account Management
Manage multiple accounts on the same site:
# Work account
agent-browser --session work --session-name gmail-work open gmail.com
# Personal account
agent-browser --session personal --session-name gmail-personal open gmail.com
Agent Swarms
Run multiple AI agents simultaneously:
# Agent 1: Research competitor A
AGENT_BROWSER_SESSION=agent1 agent-browser open competitor-a.com
# Agent 2: Research competitor B
AGENT_BROWSER_SESSION=agent2 agent-browser open competitor-b.com
# Agent 3: Research competitor C
AGENT_BROWSER_SESSION=agent3 agent-browser open competitor-c.com
Each agent has its own browser and doesn’t interfere with others.
State Isolation in CI/CD
Use session names to isolate test runs:
# In CI pipeline
export AGENT_BROWSER_SESSION_NAME="ci-run-${CI_BUILD_ID}"
agent-browser open myapp.com
# State saved to: ~/.agent-browser/sessions/ci-run-12345-default.json
This prevents state pollution between CI runs.
Security Considerations
Socket Permissions
Socket files are created with 0o700 permissions (owner-only):
// From daemon.ts:330-333
if (!fs.existsSync(socketDir)) {
fs.mkdirSync(socketDir, { recursive: true, mode: 0o700 });
}
This prevents other users from:
- Connecting to your session
- Reading your traffic
- Injecting commands
State File Permissions
State files are created with 0o600 permissions (owner read/write only):
// From daemon.ts:518
fs.chmodSync(savePath, 0o600);
This prevents other users from reading cookies and localStorage.
Encryption Key Security
If using encryption, protect your key:
# Bad - key in shell history
export AGENT_BROWSER_ENCRYPTION_KEY="my-secret-key"
# Good - read from secure vault
export AGENT_BROWSER_ENCRYPTION_KEY=$(vault read -field=key secret/agent-browser)
# Good - read from file
export AGENT_BROWSER_ENCRYPTION_KEY=$(cat ~/.agent-browser/.encryption-key)
The authentication vault feature auto-generates a key at ~/.agent-browser/.encryption-key if AGENT_BROWSER_ENCRYPTION_KEY is not set.
Session Overhead
Each session has minimal overhead:
- Daemon process: ~50-100 MB RAM
- Browser instance: ~200-500 MB RAM (depends on page)
- Disk: ~10-50 MB per profile (if using
--profile)
You can run 10-20 concurrent sessions on a typical development machine without issues.
State File Size
State files are typically small:
- Minimal state (few cookies): ~1-5 KB
- Typical app (10-20 cookies + localStorage): ~10-50 KB
- Complex app (many cookies + large localStorage): ~100-500 KB
Encryption adds minimal overhead (~5% size increase for the IV and auth tag).
Next Steps