Cookie Sync
BrowserbaseOfficialPublished by Browserbase
- Skill
- Tool integration
- Automation and integrations
- MIT
- Low risk
- Has scripts
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
Cookie Sync enables users to export authentication cookies from a local Chromium-based browser into a Browserbase persistent context. This allows developers to perform automated browsing tasks in the cloud while maintaining the authenticated state of their local browser sessions. It supports domain-specific filtering, context refreshing, and integration with Browserbase features like verified browser mode and residential proxies to help manage site access.
What it does
- Exports cookies from a local Chrome or Chromium instance to a Browserbase persistent context
- Allows filtering of synced cookies by specific domains and subdomains
- Refreshes cookies within an existing Browserbase context to extend session validity
- Supports integration with Browserbase Identity and residential proxies for improved site access
- Facilitates authenticated browsing sessions in the cloud using the browse CLI
When to use it
- When you need to access authenticated websites via Browserbase using your local credentials
- When you want to maintain persistent sessions for scheduled or recurring cloud-based tasks
- When you need to bypass site-specific restrictions by matching your local IP geolocation
- When you need to refresh expired cookies in an existing cloud context
Advantages
- Enables seamless transition from local browser authentication to cloud-based automation
- Supports persistent contexts that survive across multiple sessions
- Provides granular control over which cookies are synced to the cloud
- Helps mitigate authentication rejection through proxy and verified browser options
Usage examples
- “Sync my GitHub cookies to a new Browserbase context.”
- The tool extracts GitHub-related cookies from the local browser and returns a new context ID for use with the browse CLI.
- “Refresh the cookies in my existing context ctx_abc123.”
- The tool re-injects current local cookies into the specified context, updating it for continued use.
- “Sync cookies for twitter.com using a San Francisco residential proxy.”
- The tool syncs the specified cookies and configures the context to route traffic through a San Francisco-based residential proxy.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/browserbase/cookie-sync/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip cookie-sync.zip -d .agents/skills
Documentation by Browserbase
Cookie Sync — Local Chrome → Browserbase Context
Exports cookies from your local Chrome and saves them into a Browserbase persistent context. After syncing, use the browse CLI to open authenticated sessions with that context.
Supports domain filtering (only sync cookies you need) and context reuse (refresh cookies without creating a new context).
Prerequisites
Chrome (or Chromium, Brave, Edge) with remote debugging enabled
If your browser build exposes
chrome://flags/#allow-remote-debugging, enable it and restart the browserOtherwise, launch with
--remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debugand setCDP_URL=ws://127.0.0.1:9222At least one tab open in Chrome
Node.js 22+
Environment variable:
BROWSERBASE_API_KEY
Setup
Install dependencies before first use:
cd .claude/skills/cookie-sync && npm installUsage
Basic — sync all cookies
node .claude/skills/cookie-sync/scripts/cookie-sync.mjsCreates a persistent context with all your Chrome cookies. Outputs a context ID.
Filter by domain — only sync specific sites
node .claude/skills/cookie-sync/scripts/cookie-sync.mjs --domains google.com,github.comMatches the domain and all subdomains (e.g. google.com matches accounts.google.com, mail.google.com, etc.)
Refresh cookies in an existing context
node .claude/skills/cookie-sync/scripts/cookie-sync.mjs --context ctx_abc123Re-injects fresh cookies into a previously created context. Use this when cookies have expired.
Verified browser mode
node .claude/skills/cookie-sync/scripts/cookie-sync.mjs --verifiedEnables Browserbase Identity with a Verified browser to improve access on protected sites. Recommended for sites like Google that fingerprint browsers.
Residential proxy with geolocation
node .claude/skills/cookie-sync/scripts/cookie-sync.mjs --proxy "San Francisco,CA,US"Routes through a residential proxy in the specified location. Format: "City,ST,Country" (state is 2-letter code). Helps match your local IP's geolocation so auth cookies aren't rejected.
Combine flags
node .claude/skills/cookie-sync/scripts/cookie-sync.mjs --domains github.com,google.com --verified --proxy "San Francisco,CA,US"Browsing Authenticated Sites
After syncing, use the browse CLI with the context ID:
SESSION_JSON="$(browse cloud sessions create --context-id <ctx-id> --persist --keep-alive)"
SESSION_ID="$(echo "$SESSION_JSON" | jq -r .id)"
CONNECT_URL="$(echo "$SESSION_JSON" | jq -r .connectUrl)"
browse open https://mail.google.com --cdp "$CONNECT_URL"The --persist flag on browse cloud sessions create saves any new cookies or state changes back to the context when the cloud session is released, keeping the session fresh for next time.
Full workflow example:
# Step 1: Sync cookies for Twitter
node .claude/skills/cookie-sync/scripts/cookie-sync.mjs --domains x.com,twitter.com
# Output: Context ID: ctx_abc123
# Step 2: Browse authenticated Twitter
SESSION_JSON="$(browse cloud sessions create --context-id ctx_abc123 --persist --keep-alive)"
SESSION_ID="$(echo "$SESSION_JSON" | jq -r .id)"
CONNECT_URL="$(echo "$SESSION_JSON" | jq -r .connectUrl)"
browse open https://x.com/messages --cdp "$CONNECT_URL"
browse snapshot
browse screenshot
browse stop
browse cloud sessions update "$SESSION_ID" --status REQUEST_RELEASEReusing Contexts for Scheduled Jobs
Contexts persist across sessions, making them ideal for scheduled/recurring tasks:
Once (laptop open): Run cookie-sync → get a context ID
Scheduled jobs: Create a Browserbase session with
browse cloud sessions create --context-id <ctx-id> --persist --keep-alive, then attach withbrowse open <url> --cdp <connectUrl>— no local Chrome neededRe-sync as needed: When cookies expire, run cookie-sync again with
--context <ctx-id>to refresh
Troubleshooting
"No DevToolsActivePort found" → Enable
chrome://flags/#allow-remote-debuggingif your browser build exposes it, or launch with--remote-debugging-port=9222and setCDP_URL=ws://127.0.0.1:9222"No open page targets found" → Open at least one tab in Chrome
"WebSocket error" → Chrome may be hung; force quit and reopen it
Cookies expired in context → Re-run cookie-sync with
--context <id>to refreshAuth rejected by site → Try adding
--verifiedand/or--proxywith a location near you
Files
- ATTRIBUTION.mdAdded by AutoGineer866 B
- EXAMPLES.md3.5 KiB
- LICENSE.txt1.0 KiB
- REFERENCE.md5.1 KiB
- SKILL.md4.9 KiB
- package-lock.json147.1 KiB
- package.json191 B
- scripts/cookie-sync.mjsScript11.2 KiB
scripts/cookie-sync.mjs
#!/usr/bin/env node
// cookie-sync — Export cookies from local Chrome into a Browserbase persistent context.
// Uses Stagehand for browser connections and @browserbasehq/sdk for API calls.
//
// Setup:
// cd skills/cookie-sync && npm install
//
// Usage:
// node scripts/cookie-sync.mjs # sync all cookies into a new context
// node scripts/cookie-sync.mjs --domains google.com,github.com # only sync cookies for these domains
// node scripts/cookie-sync.mjs --context ctx_abc123 # refresh cookies in an existing context
// node scripts/cookie-sync.mjs --verified # enable Browserbase Verified browser mode
// node scripts/cookie-sync.mjs --proxy "San Francisco,CA,US" # use residential proxy with geolocation
//
// After syncing, use the browse CLI to open an authenticated session:
// SESSION_JSON="$(browse cloud sessions create --context-id <ctx-id> --persist --keep-alive)"
// CONNECT_URL="$(echo "$SESSION_JSON" | jq -r .connectUrl)"
// browse open https://example.com --cdp "$CONNECT_URL"
//
// Env vars:
// BROWSERBASE_API_KEY — required
// BROWSERBASE_CONTEXT_ID — optional, reuse an existing context
// CDP_URL — optional, Chrome debugging endpoint or browser WS URL
// CDP_PORT_FILE — optional, path to DevToolsActivePort if non-standard
// CDP_HOST — optional, host for DevToolsActivePort-based connections
import { Stagehand } from '@browserbasehq/stagehand';
import Browserbase from '@browserbasehq/sdk';
import { readFileSync, existsSync } from 'fs';
import { execSync } from 'child_process';
import { homedir } from 'os';
import { resolve } from 'path';
// ---------------------------------------------------------------------------
// CLI args
// ---------------------------------------------------------------------------
function parseArgs() {
const args = process.argv.slice(2);
const result = { domains: [], contextId: null, verified: false, proxy: null };
for (let i = 0; i < args.length; i++) {
if (args[i] === '--domains' && args[i + 1]) {
result.domains = args[++i].split(',').map(d => d.trim().toLowerCase()).filter(Boolean);
} else if (args[i] === '--context' && args[i + 1]) {
result.contextId = args[++i];
} else if (args[i] === '--verified') {
result.verified = true;
} else if (args[i] === '--proxy' && args[i + 1]) {
const parts = args[++i].split(',').map(s => s.trim());
if (!parts[0] || !parts[1]) {
console.error('Error: --proxy requires "City,State,Country" (e.g. "San Francisco,CA,US")');
process.exit(1);
}
result.proxy = { city: parts[0], state: parts[1], country: parts[2] || 'US' };
}
}
return result;
}
const CLI = parseArgs();
// ---------------------------------------------------------------------------
// Env validation
// ---------------------------------------------------------------------------
const API_KEY = process.env.BROWSERBASE_API_KEY;
if (!API_KEY) {
console.error('Error: BROWSERBASE_API_KEY is required');
process.exit(1);
}
// ---------------------------------------------------------------------------
// Find local Chrome DevTools WebSocket URL
// ---------------------------------------------------------------------------
async function resolveCdpUrl(cdpUrl) {
if (/^wss?:\/\/.+\/devtools\/browser\//.test(cdpUrl)) {
return cdpUrl;
}
const base = cdpUrl.replace(/^wss?/i, m => m.length === 3 ? 'https' : 'http').replace(/\/+$/, '');
const versionUrl = base.endsWith('/json/version') ? base : `${base}/json/version`;
const res = await fetch(versionUrl);
if (!res.ok) {
throw new Error(`Could not resolve CDP_URL via ${versionUrl} (${res.status})`);
}
const info = await res.json();
if (!info.webSocketDebuggerUrl) {
throw new Error(`CDP_URL did not expose webSocketDebuggerUrl at ${versionUrl}`);
}
return info.webSocketDebuggerUrl;
}
async function getLocalCdpUrl() {
if (process.env.CDP_URL) {
return resolveCdpUrl(process.env.CDP_URL);
}
const home = homedir();
const IS_WINDOWS = process.platform === 'win32';
const macBrowsers = [
'Google/Chrome', 'Google/Chrome Beta', 'Google/Chrome for Testing',
'Chromium', 'BraveSoftware/Brave-Browser', 'Microsoft Edge',
];
const linuxBrowsers = [
'google-chrome', 'google-chrome-beta', 'chromium',
'vivaldi', 'vivaldi-snapshot',
'BraveSoftware/Brave-Browser', 'microsoft-edge',
];
const candidates = [
process.env.CDP_PORT_FILE,
...macBrowsers.flatMap(b => [
resolve(home, 'Library/Application Support', b, 'DevToolsActivePort'),
resolve(home, 'Library/Application Support', b, 'Default/DevToolsActivePort'),
]),
...linuxBrowsers.flatMap(b => [
resolve(home, '.config', b, 'DevToolsActivePort'),
resolve(home, '.config', b, 'Default/DevToolsActivePort'),
]),
...(IS_WINDOWS ? ['Google/Chrome', 'BraveSoftware/Brave-Browser', 'Microsoft/Edge'].flatMap(b => {
const base = process.env.LOCALAPPDATA || resolve(home, 'AppData/Local');
return [
resolve(base, b, 'User Data/DevToolsActivePort'),
resolve(base, b, 'User Data/Default/DevToolsActivePort'),
];
}) : []),
].filter(Boolean);
const portFile = candidates.find(p => existsSync(p));
if (!portFile) {
throw new Error(
'No DevToolsActivePort found.\n' +
'Enable remote debugging: chrome://flags/#allow-remote-debugging (Chrome 146+)\n' +
'Or launch Chrome with --remote-debugging-port=9222 and set CDP_URL=ws://127.0.0.1:9222'
);
}
const lines = readFileSync(portFile, 'utf8').trim().split(/\r?\n/);
if (lines.length < 2 || !lines[0] || !lines[1]) {
throw new Error(`Invalid DevToolsActivePort file: ${portFile}`);
}
const host = process.env.CDP_HOST || '127.0.0.1';
return `ws://${host}:${lines[0]}${lines[1]}`;
}
// ---------------------------------------------------------------------------
// Chrome version check
// ---------------------------------------------------------------------------
function checkChromeVersion() {
if (process.env.CDP_URL || process.env.CDP_PORT_FILE) return;
const chromePaths = [
// macOS
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
'/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta',
'/Applications/Chromium.app/Contents/MacOS/Chromium',
// Linux (resolved via PATH)
'google-chrome',
'google-chrome-stable',
'chromium-browser',
'chromium',
];
for (const p of chromePaths) {
try {
const out = execSync(`"${p}" --version`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
const match = out.match(/(\d+)\./);
if (match) {
const major = parseInt(match[1], 10);
if (major < 146) {
console.warn(`Chrome ${major} detected. Chrome 146+ supports the allow-remote-debugging flag.`);
console.warn('For older Chrome, launch with --remote-debugging-port=9222 and set CDP_URL=ws://127.0.0.1:9222.');
return;
}
console.log(`Chrome ${major} detected`);
return;
}
} catch { /* try next */ }
}
}
// ---------------------------------------------------------------------------
// Cookie helpers
// ---------------------------------------------------------------------------
function filterCookies(cookies, domains) {
if (domains.length === 0) return cookies;
return cookies.filter(cookie => {
const cookieDomain = cookie.domain.replace(/^\./, '').toLowerCase();
return domains.some(d => cookieDomain === d || cookieDomain.endsWith('.' + d));
});
}
function toCookieParams(cookies) {
return cookies.map(c => {
const param = {
name: c.name,
value: c.value,
domain: c.domain,
path: c.path,
httpOnly: c.httpOnly,
secure: c.secure,
};
if (c.expires > 0) param.expires = c.expires;
if (c.sameSite === 'Strict' || c.sameSite === 'Lax') {
param.sameSite = c.sameSite;
} else if (c.sameSite === 'None' && c.secure) {
param.sameSite = 'None';
}
return param;
});
}
// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------
async function main() {
checkChromeVersion();
// Step 1: Connect to local Chrome via Stagehand and export cookies
const cdpUrl = await getLocalCdpUrl();
const local = new Stagehand({
env: 'LOCAL',
localBrowserLaunchOptions: { cdpUrl },
verbose: 0,
disablePino: true,
});
await local.init();
console.log('Connected to local Chrome');
const allCookies = await local.context.cookies();
console.log(`Exported ${allCookies.length} cookies from local Chrome`);
await local.close();
// Step 2: Filter cookies by domain if requested
const cookies = filterCookies(allCookies, CLI.domains);
if (CLI.domains.length > 0) {
console.log(`Filtered to ${cookies.length} cookies matching: ${CLI.domains.join(', ')}`);
}
if (cookies.length === 0) {
console.warn('Warning: No cookies to sync. Check your domain filters or Chrome login state.');
process.exit(0);
}
// Step 3: Set up context (create new or reuse existing)
const bb = new Browserbase({ apiKey: API_KEY });
let contextId = CLI.contextId || process.env.BROWSERBASE_CONTEXT_ID;
if (!contextId) {
const ctx = await bb.contexts.create({});
contextId = ctx.id;
console.log(`Created context: ${contextId}`);
} else {
console.log(`Using existing context: ${contextId}`);
}
// Step 4: Create a temporary Browserbase session to inject cookies
const browserSettings = { context: { id: contextId, persist: true } };
if (CLI.verified) browserSettings.verified = true;
const cloud = new Stagehand({
env: 'BROWSERBASE',
apiKey: API_KEY,
disableAPI: true,
browserbaseSessionCreateParams: {
browserSettings,
...(CLI.proxy && {
proxies: [{ type: 'browserbase', geolocation: CLI.proxy }],
}),
},
verbose: 0,
disablePino: true,
});
await cloud.init();
console.log(`Injecting cookies via session: ${cloud.browserbaseSessionID}`);
// Step 5: Inject cookies and close the session (context persists independently)
const cookieParams = toCookieParams(cookies);
await cloud.context.addCookies(cookieParams);
console.log(`Injected ${cookies.length} cookies into context`);
await cloud.close();
// Step 6: Summary
console.log('');
console.log('Cookies synced to context.');
console.log(`Context ID: ${contextId}`);
console.log('');
console.log('Browse authenticated sites with:');
console.log(` SESSION_JSON="$(browse cloud sessions create --context-id ${contextId} --persist --keep-alive)"`);
console.log(' SESSION_ID="$(echo "$SESSION_JSON" | jq -r .id)"');
console.log(' CONNECT_URL="$(echo "$SESSION_JSON" | jq -r .connectUrl)"');
console.log(' browse open <url> --cdp "$CONNECT_URL"');
console.log(' # when done: browse stop && browse cloud sessions update "$SESSION_ID" --status REQUEST_RELEASE');
console.log('');
console.log('To refresh cookies later:');
console.log(` node cookie-sync.mjs --context ${contextId}`);
process.exit(0);
}
main().catch(e => {
console.error(`Error: ${e.message}`);
process.exit(1);
});
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Declares allowed tools, Needs an API key, Needs Node.js
The author says: Requires Node.js 22+, a local Chromium-based browser (Chrome, Brave, Edge) with remote debugging enabled, and BROWSERBASE_API_KEY. Run `npm install` in the skill directory before first use.
Security
What our scanner noticed· Low risk
- Scripts that your agent may run
This skill includes scripts that your agent may run. Read them before you use it.
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- Browserbase
- Publisher
- Browserbase (Official)
- Source
- browserbase/skills · skills/cookie-sync · commit 6811ca3
- Licence
- MIT License (redistribution allowed)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Browserbase.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download cookie-sync.zip