Extract and display cookies from macOS browsers.
Decrypts Chrome's macOS Keychain entries, parses Safari's binary cookie store,
and captures fresh sessions from a throwaway Chrome sign-in.
Get Started
Run without installing:
uvx cookietuner
Or install permanently:
uv tool install cookietuner
What is cookietuner?
A command-line tool that reads cookies straight from your local macOS browser stores. It decrypts Chrome's encrypted cookie database via the macOS Keychain (Chrome 130+ format) and parses Safari's binary Cookies.binarycookies file directly, with no extensions involved.
When a store can't give you what you need, cookietuner capture opens a clean Chrome window instead, waits while you sign in yourself, and keeps the cookies that session set.
Features
- Chrome support — decrypts cookies using macOS Keychain, Chrome 130+ format.
- Safari support — parses the binary cookies format with SameSite detection.
- Throwaway sign-in capture — a fresh Chrome profile, deleted afterwards, for session and HttpOnly cookies that never reach disk.
- Flexible completion conditions — finish on cookie names or globs, on a cookie's value, on the page URL, or on your own predicate, with a settle window for cookies that arrive late.
- Chunked cookies — matches a cookie split into
name.0,name.1, … and reassembles it on request. - The browser with the cookies — optionally returns the user agent, client hints and language of the browser that signed in, so the session can be replayed as it.
- Sign in from the Passwords app — optionally loads Apple's iCloud Passwords extension, so nothing is typed.
- Multiple output formats — table, short, line, and JSON.
- Domain filtering — filter by exact domain (
x.commatches.x.com, notapi.x.comordropbox.com), several at once when capturing. - Profile selection — choose which browser profile to read from.
- Cookie metadata — expiration, Secure, HttpOnly, and SameSite flags.
- Python API —
capture,capture_sessionand their async twins, with an exception and exit code per failure.
Usage
List cookies
# Chrome cookies (browser flag is required)
cookietuner cookies -b chrome
# Safari cookies
cookietuner cookies -b safari
# Filter by domain
cookietuner cookies -b chrome -d google.com
# Pick a Chrome profile
cookietuner cookies -b chrome -p "Profile 1"
Output formats
| Format | Flag | Use case |
|---|---|---|
| Full table (default) | -o table |
Browsing all cookie details |
| Short table | -o short |
Just domain, name, value |
| Line | -o line |
Space-separated, for shell scripting |
| JSON | -o json |
Piping into jq or another tool |
Capture a fresh session
Opens Chrome on a temporary profile with none of your history or logins. You sign in by hand; cookietuner never types, fills or sees your credentials. The profile is deleted when the capture ends, including on timeout, Ctrl-C or error.
# Wait for specific cookies, then print them and close the browser
cookietuner capture --url https://example.com/login \
-d example.com --until session_id --until csrf_token -o json
# Without any condition, the capture ends when you close the browser
cookietuner capture --url https://example.com/login -d example.com
# Sign in from the Passwords app instead of typing
cookietuner capture --url https://example.com/login \
-d example.com --until session_id --passwords
# Route the session through a proxy
cookietuner capture --url https://example.com/login \
-d example.com --proxy socks5://127.0.0.1:1080
# Keep the browser's identity too, so the session can be replayed as it
cookietuner capture --url https://example.com/login \
-d example.com --until session_id -o json --identity
Deciding when it's done
A capture finishes once every condition you gave holds at the same time. Without any, it ends when you close the browser.
| Option | Waits for |
|---|---|
--until name |
A cookie name, a glob (--until 'sb-*-auth-token'), or a complete chunk set (name.0, name.1, …). Repeatable |
--until-value 'uid!=anon_*' |
A cookie to exist and its value to match, or with != to stop matching. Repeatable. This is what tells a signed-in session from an anonymous one that reuses the name |
--until-url '*/dashboard*' |
An open page's URL to match; with a leading !, for no page to match, so you can wait to leave /login |
--settle 2 |
Keeps polling for 2 more seconds once everything holds, so late cookies, trailing chunks and post-login redirects land |
--timeout 120 |
Caps the whole wait (300 seconds by default) |
-d repeats too, for a sign-in that spans domains:
cookietuner capture --url https://example.com/login \
-d example.com -d auth.example.com \
--until 'sb-*-auth-token' --until-value 'uid!=anon_*' \
--until-url '*/dashboard*' --settle 2 -o json
Closing the window, quitting Chrome with Cmd+Q and Chrome exiting on its own all mean the same thing: the capture keeps the last snapshot taken before the end. If conditions were given and that snapshot doesn't satisfy them, it fails and names what was missing rather than returning a half-signed-in session. What it's still waiting for is printed to stderr as it goes, and values and live URLs never are.
Cookie values go to stdout on their own and progress goes to stderr, so the output pipes straight into a secret store:
cookietuner capture --url https://example.com/login \
-d example.com --until session_id -o json | my-secret-store put example-session
This reaches cookies a store reader can't: session cookies, cookies kept only in memory, and HttpOnly cookies on a macOS version that denies access to Chrome's own store.
Note
--passwordsis the only option that reads your Chrome profile folder, to copy the extension out of it. macOS withholds that folder until the program running cookietuner has Full Disk Access (System Settings > Privacy & Security), and without it the capture fails withProfileAccessDenied. Capturing without--passwordsneeds no access at all.
Use from Python
The same capture, as a function, with the same conditions behind both:
from cookietuner import CaptureTimeout, capture, join_chunks
cookies = capture(
url="https://example.com/login",
domains={"example.com", "auth.example.com"},
until={"sb-*-auth-token"},
until_values=["uid!=anon_*"],
until_url="*/dashboard*",
settle=2,
on_progress=lambda pending: print("waiting for", pending),
)
for cookie in cookies: # each a Cookie model
print(cookie.domain, cookie.name, cookie.is_httponly)
token = join_chunks(cookies, "sb-abcdef-auth-token")
Sites bind a session to the browser that signed in, so cookies alone can read as
stolen somewhere else. capture_session returns the browser with them:
import requests
from cookietuner import capture_session
session = capture_session(
url="https://example.com/login",
domains={"example.com"},
until={"session_id"},
)
reuse = requests.Session()
reuse.headers.update(session.headers()) # user agent, language, sec-ch-ua*
for cookie in session.cookies:
reuse.cookies.set(cookie.name, cookie.value, domain=cookie.domain, path=cookie.path)
reuse.get("https://example.com/api/me")
until also takes a predicate (until=lambda cs: ...), called on each poll with the cookies that would be returned, for anything the flags can't express. capture_async is the same function for an async application.
Failures raise CaptureTimeout, CaptureIncomplete, ChromeNotFound, ProfileAccessDenied or PasswordsExtensionMissing, all subclasses of CaptureError, each carrying the CLI's exit code as exc.exit_code. Full signatures, condition semantics and exit codes are in the API reference.
List browser profiles
# All profiles
cookietuner profiles
# Filter by browser
cookietuner profiles -b chrome
Requirements
- macOS (the tool reads macOS-specific cookie stores).
- Python 3.11+.
- Chrome and/or Safari.
Development
git clone https://github.com/alltuner/cookietuner.git
cd cookietuner
uv sync
uv run pytest
uv run cookietuner
The tests marked browser drive a real Chrome. Locally they run it headless, so
the suite doesn't steal focus; CI runs them with a real window, which is what a
capture actually opens. To watch one happen:
COOKIETUNER_TEST_HEADLESS=0 uv run pytest -m browser
# Or skip them entirely, where there's no desktop session
uv run pytest -m "not browser"
License
Support the project
cookietuner is an open source project built by David Poblador i Garcia through All Tuner Labs.
If this project was useful to you, consider supporting its development.
Built by David Poblador i Garcia with the support of All Tuner Labs.
Made with ❤️ in Poblenou, Barcelona.
Metadata
Release files for cookietuner 0.3.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cookietuner-0.3.2.tar.gz | 30.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cookietuner-0.3.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 63.6 kB