Cookies & sessions
Being signed in, and staying that way: what an agent may see of a cookie jar, why a value never reaches it, and how a whole session moves between profiles as an encrypted bundle.
Signing in is one problem; staying signed in is another. This page is the second one.
A cookie value is stronger than the password beside it
A session cookie skips the password and the second factor. Anyone holding one is signed in, with no challenge left to pass.
So the rule is simple and has no exception: an agent never receives a cookie value. Not through the cookie tools, not in a page map, not in a report.
cookie_list gives an agent the shape of the jar:
- without a domain: one line per site with a count, so nothing gets cut off
- with a domain: that site's cookies, with expiry, flags and the size of each value
cookie_delete removes one cookie, or every cookie of one site if you leave the name out. It names the domain the way the list shows it, and answers with how many were really removed, counted before and after, because the browser reports nothing itself.
Both are in the opt-in extended set.
Reading the jar is a browser-level call, so no page notices it. It does not run inside the document, and nothing about it is observable from a site the profile is signed in to.
The one plaintext exit
POST /v1/profiles/:id/cookies/reveal returns values, and it needs the vault password, not just the API token.
The reason is the same one the vault exists for: an agent permitted to call any tool already holds the bearer token for this whole API, so a flag it could reach would be no gate at all. A second secret that lives with the operator is the only thing that makes the difference real.
Two details, both deliberate: it is a POST and it answers Cache-Control: no-store, because a secret does not belong in a URL that lands in a history file or an access log. And the browser has to be running, because the jar lives in the browser process. The daemon does not pry open Chromium's on-disk cookie file: it is sealed per operating-system user, and opening it would be a second implementation of the same truth.
Moving a session
A session is more than cookies. POST /v1/profiles/:id/session/export seals four kinds into one password-encrypted bundle:
| Kind | What it holds |
|---|---|
cookies | The jar. |
local_storage | Per-origin key/value storage. |
indexed_db | The structured store many apps keep a session in. |
service_worker | Registered workers and their state. |
POST /v1/profiles/:id/session/import unseals one into a target profile.
$ curl -X POST http://127.0.0.1:8787/v1/profiles/pr_9c21e4/session/export \
-H "Authorization: Bearer $SCALEBROWSER_BEARER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"password":"…"}'{ "bundle": "…", "kinds": ["cookies", "local_storage"], "degraded": false, "harvested": true }A cookie-only export is flagged degraded. A login backed only by cookies usually is not a login: modern sites keep the real token in local storage or IndexedDB, and importing such a bundle produces a profile that looks signed in and is not.
Read the flag rather than assuming an export is complete.
harvested is the field that matters
An export of a running profile harvests the live jar out of the browser first. harvested: false means it could not, so what you have is whatever was last written to disk.
That distinction is the whole feature. An export that does not touch a browser is not a transfer; it is a snapshot of an unknown moment. Fixing one direction alone would only move the false success somewhere else, which is why the import applies at once when the profile is running, and otherwise at the next start, exactly once.
From an agent
session.export and session.import are in the management set, addressed by profile id.
The export is read-only; the import is destructive, because it overwrites the target profile's session.
Next
- Credentials & logins: getting signed in in the first place.
- Passkeys: the credential that has no password.
- Profile sync: moving a whole profile, not just its session, between your machines.
- Secrets: why a value in a transcript cannot be taken back.