---
title: "Cookies & sessions"
description: "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."
canonical: "https://scalebrowser.net/docs/sessions"
---

> ## Documentation Index
> Fetch the complete documentation index at: https://scalebrowser.net/llms.txt
> Use this file to discover all available pages before exploring further.

# 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.

<Note>

**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.

</Note>

## The one plaintext exit
`POST /v1/profiles/:id/cookies/reveal` returns values, and it needs the [vault password](/docs/credentials#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.

```bash
$ 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":"…"}'
```

```json
{ "bundle": "…", "kinds": ["cookies", "local_storage"], "degraded": false, "harvested": true }
```

<Warning>

**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.

</Warning>

### `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](/docs/credentials): getting signed in in the first place.
- [Passkeys](/docs/passkeys): the credential that has no password.
- [Profile sync](/docs/sync): moving a whole profile, not just its session, between your machines.
- [Secrets](/docs/secrets): why a value in a transcript cannot be taken back.
