Browser session persistence for Claude Code. Login once to any website, reuse cookies everywhere — across Claude Code, Playwright, and even across machines and servers. You login in one place, you don't have to login again on another machine or server you own.
Many websites gate content behind authentication but don't offer API access. browser-cookie-jar is a Claude Code plugin that captures browser login state and replays it in automated scrapes, so Claude can access authenticated content without API keys.
Install as a Claude Code plugin:
/plugin marketplace add zzzhouzhenzz/browser-cookie-jar
/plugin install browser-cookie-jar
That's it. Claude will auto-detect available sessions at the start of every conversation.
Just talk to Claude:
- "Import my Facebook session from Chrome" — Claude grabs cookies from your existing Chrome login. No re-login needed. Chrome must be closed.
- "Import my X session and push to user@server" — Import + push in one shot
- "Login to X for me" — Fresh login flow if you're not logged in on Chrome. Opens a real Chrome window, you authenticate manually (2FA, OAuth, passkeys).
- "Check my sessions" — Claude tells you which site sessions are saved
- "Push my X session to user@server" — Claude transfers the session to a remote machine via scp
- "Clear my X session" — Claude deletes the saved session
- "Scrape x.com/someone" — Claude uses the saved session automatically for authenticated access
Login requires a display (Mac, Linux desktop). Headless servers receive sessions via push. Claude handles the full flow in one shot:
If you're already logged in on Chrome (preferred):
- Ask Claude: "Import my Facebook session and push to user@server:2222"
- Claude runs
browser-cookie-jar import facebook --push user@server:2222 - Python reads Chrome's cookie database directly — no browser window opens
- On macOS, allow the "Python wants to access Chrome Safe Storage" Keychain prompt
- Cookies are extracted, saved locally, and pushed to the remote
- Done — no manual login, no browser window
If you need a fresh login:
- Ask Claude: "Login to X and push to user@server:2222"
- Claude runs
browser-cookie-jar login x --push user@server:2222 - A real Chrome window opens — you authenticate manually
- Browser closes, session saves locally, then auto-pushes to the remote via scp
On the remote machine, Claude automatically uses the session for scraping.
The plugin reports available sessions to Claude:
[browser-cookie-jar] 1 browser session(s) available for authenticated scraping:
- x (5088 bytes)
Claude has access to these tools:
| Tool | What it does |
|---|---|
list_sessions |
List all saved browser sessions |
session_status |
Check if a specific site has a session |
session_path |
Get the state file path for a site |
clear_session |
Delete a saved session |
Two-layer design, extensible to any website:
browser-cookie-jar/
├── src/browser_cookie_jar/
│ ├── store.py # Layer 1: SessionStore (generic infra)
│ ├── handlers/
│ │ ├── x.py # Layer 2: X/Twitter handler
│ │ └── facebook.py # Layer 2: Facebook handler
│ ├── server.py # MCP server (tools for Claude)
│ ├── hook_session_start.py # Reports sessions at conversation start
│ └── cli.py # CLI (used by Claude, not humans)
Layer 1 — SessionStore (infra):
- Saves/loads Playwright
context.storage_state()as JSON - Per-site namespacing:
~/.browser-cookie-jar/<site>/state.json - Injects saved state into
browser.new_context()kwargs - Generic
login_flow()— opens a URL, waits for a condition, saves state - Chrome cookie import — reads cookies directly from Chrome's database
- Cross-machine transfer via scp (push/pull)
Layer 2 — Handlers (site-specific):
- Each handler knows one website's login URL and success detection
- Ships with
XHandlerandFacebookHandler - Adding a new site = one class with a login URL + success test
- Claude runs
browser-cookie-jar login x— opensx.com/loginin a visible Chromium window - You log in manually — any auth method works
- Once the handler detects success (URL leaves the login flow), Playwright captures
context.storage_state() - State is saved to
~/.browser-cookie-jar/x/state.json - Any scraper using
browser-cookie-jarloads the session automatically intobrowser.new_context(storage_state=...)
~/.browser-cookie-jar/
├── x/
│ └── state.json # X/Twitter cookies + localStorage
├── facebook/
│ └── state.json # Facebook cookies + localStorage
└── .venv/ # Plugin's isolated Python environment
Sessions are plain JSON files. They typically last weeks before sites require re-authentication.
from browser_cookie_jar.store import SessionStore
class RedditHandler:
SESSION_NAME = "reddit"
def __init__(self, store=None):
self.store = store or SessionStore(self.SESSION_NAME)
def login(self, timeout=300000):
return self.store.login_flow(
login_url="https://www.reddit.com/login",
success_test=lambda url: "reddit.com" in url and "/login" not in url,
timeout=timeout,
)
def has_session(self):
return self.store.exists()
def apply(self, context_kwargs):
return self.store.apply(context_kwargs)| Site | CLI names | Handler | Login URL | Notes |
|---|---|---|---|---|
| X/Twitter | x, twitter |
XHandler |
x.com/login |
Handles Google OAuth, 2FA |
facebook, fb |
FacebookHandler |
facebook.com/login |
Handles 2FA, checkpoint challenges |
- Google (YouTube, Gmail, etc.)
Adding a new site is one file — see "Adding a new site handler" above. PRs welcome.
pip install -e ".[dev]"
pytest -v