> ## 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.

# Sessions

> Understand session isolation and persistence in Agent Browser

## 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:

1. **Session Isolation** (`--session`): Run multiple concurrent browser instances
2. **Session Persistence** (`--session-name`, `--profile`): Save and restore state

## Session Isolation

### Multiple Concurrent Sessions

Run multiple isolated browser instances with different session names:

```bash theme={null}
# 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:

```typescript theme={null}
// 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"`:

```bash theme={null}
# These are equivalent:
agent-browser open example.com
agent-browser --session default open example.com
```

You can also set the session via environment variable:

```bash theme={null}
export AGENT_BROWSER_SESSION=agent1
agent-browser open example.com  # Uses agent1 session
```

### Listing Active Sessions

See which sessions are currently running:

```bash theme={null}
agent-browser session list
```

<CodeGroup>
  ```text Output theme={null}
  Active sessions:
  → default
    agent1
    agent2
  ```
</CodeGroup>

The arrow (`→`) indicates the current session (from `--session` flag or `AGENT_BROWSER_SESSION` env var).

In JSON mode:

```bash theme={null}
agent-browser session list --json
```

<CodeGroup>
  ```json Output theme={null}
  {
    "success": true,
    "data": {
      "sessions": ["default", "agent1", "agent2"]
    }
  }
  ```
</CodeGroup>

### 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:

```typescript theme={null}
// From state-utils.ts
export function isValidSessionName(name: string): boolean {
  return /^[a-zA-Z0-9_-]+$/.test(name);
}
```

Invalid examples:

```bash theme={null}
# 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:

```bash theme={null}
agent-browser --session agent1 close
```

This:

1. Closes the browser for `agent1`
2. Shuts down the daemon for `agent1`
3. 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:

```bash theme={null}
# 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:

```bash theme={null}
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 File Format

State files contain cookies and localStorage in Playwright's storage state format:

```json theme={null}
{
  "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:

```bash theme={null}
# 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:

```json theme={null}
{
  "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:

```typescript theme={null}
// 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:

```bash theme={null}
# 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:

```typescript theme={null}
// From daemon.ts:338-339
runCleanupExpiredStates();
```

You can also manually clean up old states:

```bash theme={null}
agent-browser state clean --older-than 7
```

### Persistent Profiles (`--profile`)

The `--profile` flag uses Playwright's persistent context, which stores **all** browser data:

```bash theme={null}
# 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:

```bash theme={null}
# 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:

```bash theme={null}
# 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:

```bash theme={null}
# 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:

```bash theme={null}
# 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:

```bash theme={null}
# 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:

```bash theme={null}
# 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):

```typescript theme={null}
// 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):

```typescript theme={null}
// 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:

```bash theme={null}
# 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.

## Performance

### 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

* [Architecture](/concepts/architecture) - Understand the Rust CLI + Node.js daemon design
* [Snapshot Refs](/concepts/snapshot-refs) - Learn about accessibility tree snapshots
* [Selectors](/concepts/selectors) - Master element selection strategies
