Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 66 additions & 69 deletions skills/cookie-sync/EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,106 +5,103 @@
**User request**: "Sync my Chrome cookies to a cloud browser"

```bash
export BROWSERBASE_API_KEY="bb_live_xxx"
node .claude/skills/cookie-sync/scripts/cookie-sync.mjs
bb sync
```

After syncing, navigate to a site:
Output:
```json
{
"contextId": "5d780360-7c8d-445c-ab22-509225a694b6",
"cookiesSynced": 6154
}
```

Then browse an authenticated site:

```bash
node -e "
const WS_URL = 'wss://connect.browserbase.com?apiKey=' + process.env.BROWSERBASE_API_KEY + '&sessionId=SESSION_ID';
const ws = new WebSocket(WS_URL);
let id = 0;
const send = (method, params = {}, sid) => {
const msg = { id: ++id, method, params };
if (sid) msg.sessionId = sid;
ws.send(JSON.stringify(msg));
};
ws.onopen = () => send('Target.getTargets');
ws.onmessage = (ev) => {
const msg = JSON.parse(ev.data);
if (msg.id === 1) {
const page = msg.result.targetInfos.find(t => t.type === 'page');
send('Target.attachToTarget', { targetId: page.targetId, flatten: true });
}
if (msg.id === 2) {
send('Page.navigate', { url: 'https://mail.google.com' }, msg.result.sessionId);
}
if (msg.id === 3) {
console.log('Navigated to Gmail');
setTimeout(() => process.exit(0), 1000);
}
};
"
browse open https://mail.google.com --context-id 5d780360-7c8d-445c-ab22-509225a694b6 --persist
```

## Example 2: Reuse Context Across Sessions
## Example 2: Sync Specific Domains

**User request**: "Sync my GitHub and Google cookies"

```bash
bb sync --domains google.com,github.com
```

Output:
```json
{
"contextId": "ctx_abc123",
"cookiesSynced": 119,
"domains": ["google.com", "github.com"]
}
```

## Example 3: Reuse Context Across Sessions

**User request**: "I already synced my cookies earlier, start a new session with them"

```bash
export BROWSERBASE_CONTEXT_ID="ctx_abc123"
node .claude/skills/cookie-sync/scripts/cookie-sync.mjs
bb sync --context-id ctx_abc123
```

This creates a new session using the saved context — no need to re-export cookies from Chrome (though the script still does to ensure freshness).
This re-exports fresh cookies from local Chrome into the existing context — keeping it up to date without creating a new one.

## Example 3: Take a Screenshot of an Authenticated Page
## Example 4: Take a Screenshot of an Authenticated Page

**User request**: "Go to my GitHub notifications and screenshot them"

After cookie sync, navigate and screenshot:
```bash
# Step 1: Sync cookies
bb sync --domains github.com
# Note the contextId from the output

# Step 2: Browse and screenshot
browse open https://github.com/notifications --context-id <ctx-id> --persist
browse screenshot --output /tmp/notifications.png
browse stop
```

## Example 5: Stealth Mode with Proxy

**User request**: "Sync my Google cookies but avoid bot detection"

```bash
node -e "
const fs = require('fs');
const WS_URL = 'wss://connect.browserbase.com?apiKey=' + process.env.BROWSERBASE_API_KEY + '&sessionId=SESSION_ID';
const ws = new WebSocket(WS_URL);
let id = 0, sid;
const send = (method, params = {}) => {
const msg = { id: ++id, method, params };
if (sid) msg.sessionId = sid;
ws.send(JSON.stringify(msg));
};
ws.onopen = () => send('Target.getTargets');
ws.onmessage = (ev) => {
const msg = JSON.parse(ev.data);
if (msg.id === 1) {
const page = msg.result.targetInfos.find(t => t.type === 'page');
send('Target.attachToTarget', { targetId: page.targetId, flatten: true });
}
if (msg.id === 2) {
sid = msg.result.sessionId;
send('Page.navigate', { url: 'https://github.com/notifications' });
}
if (msg.id === 3) {
setTimeout(() => send('Page.captureScreenshot', { format: 'png' }), 3000);
}
if (msg.id === 4) {
fs.writeFileSync('/tmp/screenshot.png', Buffer.from(msg.result.data, 'base64'));
console.log('Screenshot saved to /tmp/screenshot.png');
process.exit(0);
}
};
"
bb sync --domains google.com --stealth --proxy "San Francisco,CA,US"
```

## Example 4: Using with a Custom Browser
The `--stealth` flag enables advanced bot detection evasion, and `--proxy` routes through a residential IP near your location so Google doesn't flag the session as suspicious.

## Example 6: Using with a Custom Browser

**User request**: "Sync cookies from Brave instead of Chrome"

Brave is auto-detected. If your browser stores DevToolsActivePort in a non-standard location:

```bash
export CDP_PORT_FILE="$HOME/Library/Application Support/MyBrowser/DevToolsActivePort"
node .claude/skills/cookie-sync/scripts/cookie-sync.mjs
bb sync
```

## Example 7: Scripting with JSON Output

**User request**: "Sync cookies and use the context ID in a script"

```bash
# Capture the context ID from bb sync's JSON output
CONTEXT_ID=$(bb sync --domains github.com 2>/dev/null | jq -r '.contextId')

# Use it downstream
browse open https://github.com --context-id "$CONTEXT_ID" --persist
```

The JSON output goes to stdout and progress messages go to stderr, so `2>/dev/null` suppresses progress while preserving the parseable output.

## Tips

- **First time?** Enable remote debugging in `chrome://flags/#allow-remote-debugging` and restart Chrome before running
- **Save your context ID** after the first sync to skip context creation in future sessions
- **One context per identity** — don't mix personal and work browser cookies in the same context
- **Close sessions when done** — keepAlive sessions persist until explicitly closed and consume resources
- **Watch the live view** — open the viewer URL to see the cloud browser in real time
- **Pipe-friendly** — JSON on stdout, progress on stderr. Use `jq` to extract fields.
65 changes: 40 additions & 25 deletions skills/cookie-sync/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,74 @@

## Table of Contents

- [Architecture](#architecture)
- [Command Reference](#command-reference)
- [Environment Variables](#environment-variables)
- [How It Works](#how-it-works)
- [Browserbase Context Integration](#browserbase-context-integration)
- [Browser Compatibility](#browser-compatibility)
- [Security Considerations](#security-considerations)

## Architecture

Cookie sync is a Node.js script that uses:

- **[Stagehand](https://github.com/browserbase/stagehand)** (`@browserbasehq/stagehand`) for CDP connections to both local Chrome and the cloud browser, including cookie get/set operations
- **[Browserbase SDK](https://github.com/browserbase/sdk-node)** (`@browserbasehq/sdk`) for API calls (context creation)
## Command Reference

```
Local Chrome (Stagehand) → cookie-sync.mjs → Stagehand (Browserbase) → Cloud Browser
↓ ↓ ↓
context.cookies() init() creates session context.addCookies()
bb sync [options]
```

| Flag | Description |
|------|-------------|
| `--domains <domains>` | Comma-separated list of domains to filter cookies. Matches subdomains. |
| `--context-id <id>` | Reuse an existing Browserbase context instead of creating a new one. |
| `--stealth` | Enable advanced stealth mode on the cloud session. |
| `--proxy <geo>` | Residential proxy geolocation: `"City,State,Country"`. |
| `--api-key <key>` | Override the Browserbase API key. |
| `--base-url <url>` | Override the Browserbase API base URL. |

### Output

`bb sync` outputs JSON to stdout with the sync result:

```json
{
"contextId": "5d780360-7c8d-445c-ab22-509225a694b6",
"cookiesSynced": 119,
"domains": ["google.com", "github.com"]
}
```

Progress messages are written to stderr.

## Environment Variables

| Variable | Required | Description |
|----------|----------|-------------|
| `BROWSERBASE_API_KEY` | Yes | API key from https://browserbase.com/settings |
| `BROWSERBASE_CONTEXT_ID` | No | Reuse an existing context instead of creating a new one |
| `CDP_URL` | No | Direct WebSocket URL to Chrome (e.g. `ws://127.0.0.1:9222`). Use when Chrome is launched with `--remote-debugging-port` and no `DevToolsActivePort` file exists |
| `BROWSERBASE_CONTEXT_ID` | No | Reuse an existing context (alternative to `--context-id` flag) |
| `CDP_URL` | No | Direct WebSocket URL to Chrome (e.g. `ws://127.0.0.1:9222`). Use when Chrome is launched with `--remote-debugging-port` |
| `CDP_PORT_FILE` | No | Custom path to DevToolsActivePort file |
| `CDP_HOST` | No | Custom host for local Chrome connection (default: `127.0.0.1`) |

## How It Works

### Step 1: Connect to Local Chrome

The script finds Chrome's DevTools WebSocket URL in one of two ways:
`bb sync` finds Chrome's DevTools WebSocket URL in one of two ways:

- If `CDP_URL` is set, it resolves the browser WebSocket endpoint from that debugging endpoint (or uses the full browser WebSocket URL directly)
- Otherwise, it reads the `DevToolsActivePort` file created by browsers that expose remote debugging through their normal profile

### Step 2: Export Cookies

Calls `context.cookies()` via Stagehand's Understudy layer (which uses `Storage.getCookies` over CDP). This returns all cookies from all domains stored in the browser — not just the active tab.
Connects to local Chrome via Stagehand and calls `context.cookies()` to export all cookies from all domains — not just the active tab.

### Step 3: Create Context and Session

Creates a Browserbase Context via the SDK (persistent state container) and a Stagehand session attached to that context with `persist: true`. This means:
Creates a Browserbase Context (persistent state container) and a session attached to that context with `persist: true`. This means:
- Cookies injected during this session are saved to the context
- Future sessions using the same context ID start with those cookies
- The session uses `keepAlive: true` so it stays open until explicitly closed

### Step 4: Inject Cookies

Calls `context.addCookies()` via Stagehand's Understudy layer (which uses `Storage.setCookies` over CDP) to inject all exported cookies into the cloud browser.
Calls `context.addCookies()` to inject all exported cookies into the cloud browser. Once complete, the session is released and the context persists independently.

## Browserbase Context Integration

Expand All @@ -63,14 +78,14 @@ Contexts persist browser state (cookies, localStorage, IndexedDB) across session
### First sync (creates context)

```bash
node cookie-sync.mjs
# Output includes: Context ID: ctx_abc123
bb sync
# Output includes: "contextId": "ctx_abc123"
```

### Subsequent sessions (reuses context)
### Subsequent syncs (refreshes context)

```bash
BROWSERBASE_CONTEXT_ID=ctx_abc123 node cookie-sync.mjs
bb sync --context-id ctx_abc123
```

### Context lifecycle
Expand Down Expand Up @@ -101,7 +116,7 @@ BROWSERBASE_CONTEXT_ID=ctx_abc123 node cookie-sync.mjs
2. Set to "Enabled"
3. Restart Chrome

**Any Chrome version** (requires `--user-data-dir` and `CDP_URL`):
**Any Chrome version** (requires `CDP_URL`):
```bash
# macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug
Expand All @@ -120,7 +135,7 @@ Note: `--user-data-dir` is required because Chrome won't open the debugging port

## Security Considerations

- **Cookies are sensitive credentials.** The script transfers your authenticated sessions to a cloud browser. Only use with your own Browserbase account.
- **Cookies are sensitive credentials.** The command transfers your authenticated sessions to a cloud browser. Only use with your own Browserbase account.
- Cookies are transmitted over secure WebSocket (`wss://`) to Browserbase.
- The script does not log, store, or transmit cookies anywhere other than the target Browserbase session.
- Sessions created with `keepAlive: true` persist until explicitly closed — remember to close sessions when done.
- The command does not log, store, or transmit cookies anywhere other than the target Browserbase session.
- Sessions are automatically released after cookie injection — no lingering sessions consuming resources.
Loading