# Auth profiles

Some pages only show their content to a visitor who has logged in. An auth profile is that visitor: the cookies and storage a browser holds after signing in, uploaded once and named on any request after that. Nothing logs in again, and the password never reaches us.

## Uploading one

Sign in to the site in a browser you drive, save its state, and upload it. With Playwright that is one call, `context.storage_state(path="state.json")`; any tool that writes the same shape will do.

POST /auth\_profiles

```
{
  "name": "Shop admin",
  "storage_state": {
    "cookies": [
      { "name": "session", "value": "…", "domain": ".shop.example", "path": "/",
        "expires": -1, "httpOnly": true, "secure": true, "sameSite": "Lax" }
    ],
    "origins": [
      { "origin": "https://shop.example", "localStorage": [ { "name": "token", "value": "…" } ] }
    ]
  }
}
```

201 Created

```
{
  "id": "ap_7Qm2sX9kLw4RtB1nYc8vDf3H",
  "name": "Shop admin",
  "domains": ["shop.example"],
  "signed_out_at": null,
  "last_used_at": null,
  "state_updated_at": "2026-10-25T09:12:44Z",
  "created_at": "2026-10-25T09:12:44Z"
}
```

`storage_state` can also be sent as the file's contents, a string. `domains` are the hosts the profile may be used for, each with the hosts under it. Left out, they are the one site the state holds cookies for. A state exported from a browser often holds other sites' cookies too (analytics, a sign-in provider), and then the upload asks you to name `domains`, so a profile is only ever used for the sites you chose.

## Using one

Name the profile's id as `auth_profile` on any endpoint but `/lighthouse`, [/scrape](https://urlpipe.dev/docs/scrape) included. The page is loaded as that visitor, and everything else about the request stays the same.

POST /markdown

```
{
  "url": "https://shop.example/orders",
  "auth_profile": "ap_7Qm2sX9kLw4RtB1nYc8vDf3H",
  "sync": true
}
```

A URL on none of the profile's domains is refused with `invalid_auth_profile` before anything is fetched, so a profile is never used anywhere but where you meant it to be. It costs nothing extra: the same credits as the request without it.

## Staying signed in

Each request starts a fresh browser from the profile's state, so there is no login to repeat and no wait for one: the session is in place before the first byte is requested. Requests made as the same profile run in parallel.

- **What the site renews is kept.** Most sites refresh their session cookie as it is used. Whatever a visit is handed back is written to the profile, so a session the site keeps rolling stays alive for as long as you use it.
- **It is used from one place.** Sites tie a session to where it is used from, and end one that moves. Every visit made as a profile goes out from the same exit — the one its first visit used — and if that exit is busy, the request fails rather than move the session: retry in a moment.
- **A session that ends is reported.** When a site answers with a sign-in form instead of the page, the request fails with `The page asked us to sign in before it would show its content.` and the profile's `signed_out_at` says when. Sign in again and upload the new state.

PUT /auth\_profiles/{id}

```
{ "storage_state": { "cookies": [ … ], "origins": [ … ] } }
```

A new state is a new session: results stored under the old one are deleted, since they may not even be the same account's. `name` and `domains` can be changed on their own, which keeps them. `GET /auth_profiles` lists a project's profiles, `GET /auth_profiles/{id}` reads one, and `DELETE /auth_profiles/{id}` removes it along with the results stored for it.

The same can be done from the dashboard: each project's Auth profiles page lists its profiles, shows which ones a site has signed out, and lets an organization admin upload, replace and delete them.

## How the state is kept

A signed-in browser's cookies are as good as its password to whoever holds them, and they are treated that way:

- Encrypted at rest, and decrypted only to load a page you asked for.
- Write-only. No response — not the profile's, not a result's, not a webhook — ever carries the state back.
- Used only for the profile's domains, and only by the project it belongs to.
- Kept out of our logs, and gone with the profile when you delete it.

A project API key can make requests as every profile in that project. Keep profiles in a project of their own if the key will live somewhere you trust less than the account.

## Results are the visitor's own

A page somebody is signed in to is theirs, so a result fetched as a profile is [stored](https://urlpipe.dev/docs/caching) under that profile alone. A request made as nobody is never handed it, nor is one made as another profile. Repeat the same request as the same profile inside your `max_age` window and it is a free cache hit like any other; send `max_age: 0` when the page must be current.

[See every error code](https://urlpipe.dev/docs/errors)

Source: https://urlpipe.dev/docs/auth-profiles
