Ask an agent to pull last quarter's invoices from your billing portal and it stops at the same place every time: a login form. The data is right there, the task is trivial for a human, and there's no API. The agent can't proceed without an account, and handing over an account has always meant handing over a password.

That trade is bad enough that most people just leave this work manual. It's also unnecessary. There's a third option: let the human log in, and let the agent inherit the session.

The three ways to give an agent access, ranked

1. Use the API. If the service has one, use it. OAuth in your own browser, a refresh token stored server-side, a scoped short-lived access token for the agent. Nothing below beats this. The problem is that most of the web has no API, and the parts that do often exclude exactly the thing you want.

2. Store the credential and let something type it. This is what credential injection and password-manager integrations do: the secret lives in a vault, and a driver types it into the page so the model never sees the string. It works, and it's strictly better than pasting a password into a chat. But you now own a credential store, and its blast radius is every account in it.

3. Hand over the browser after logging in yourself. The human does the login — password, 2FA, CAPTCHA, whatever the site demands — in a real browser. The agent picks up the authenticated profile afterwards. No credential is stored anywhere, because none was ever collected.

The third option is the one almost nobody offers — and it needs no vault.

How browser handoff actually works

The mechanism is simple: separate login from automation in time, on one browser profile.

A real Chrome starts inside the machine with nothing but a profile directory. The human drives it — over a remote view in the browser they already have open — and signs in normally. Chrome writes its cookies to that profile directory, the way it always does. Then Chrome exits.

Afterwards, automation opens the same profile directory. Playwright's launchPersistentContext points at it and gets a browser that's already signed in. No conversion, no export, no credential.

There's a second path worth knowing about: Playwright can export the session to its own portable format, a storageState JSON containing cookies and per-origin local storage. That file can seed a fresh browser context elsewhere. Both work — the profile directory keeps more fidelity, the JSON travels better.

The detail that breaks naive implementations: headless

If you inherit a perfectly valid session and then drive it with a headless browser, sites reject you anyway. We tested this against a real logged-in session: same profile, same cookies, two browsers. Headless returned 403. Headful, on a virtual display, returned 200 and the account's own data.

The session was never the problem. The fingerprint was. Anti-bot systems detect headless Chrome, automation flags, and the CDP debugging surface independently of whether your cookies are good.

This has two consequences:

  • The login browser can't carry any automation flags at all. No --enable-automation, no --remote-debugging-port, no headless. If it does, the login itself fails before any session exists.
  • The agent browser has to be headful too, on a virtual display. An inherited session driven headlessly is worth nothing on sites that check.

It also means using real Google Chrome rather than the bundled Chromium build, which fingerprints differently.

What this makes possible

The jobs that open up are unglamorous and very common:

  • Pull statements, invoices or usage reports from a portal whose only export is a web download
  • Read a vendor dashboard that has no API and summarize what changed this week
  • Check order or shipment status across suppliers who each have their own login
  • Run a scheduled routine against a service you can only reach signed in
  • File a recurring form that was never worth building an integration for

None of these need a credential store. They need one human login, once, and a session that persists afterwards.

Be honest about the security boundary

This is where most write-ups get vague, so let's be precise.

What handoff genuinely protects: your password never enters the model's context, never reaches the service running the agent, and never lands in a log. There's no stored credential to leak, because none was collected. That's a real reduction in exposure, and it's the main point.

What it doesn't protect: the agent receives the session that password created, and on most sites a session can do everything you can do. Anyone claiming "the AI never gets access to your account" is selling you something. The honest claim is narrower: the AI never gets your password.

So treat the session as the credential it is:

  • Scope it. One profile per site. A leak should reach one service, not all of them.
  • Pick the account deliberately. Give agents accounts you'd give a contractor. Not your bank, not your primary email, not anything with payment methods saved.
  • Prefer a separate login where the service supports one, so you can revoke it without disturbing your own access.
  • Expect prompt injection. An agent with a logged-in browser is a confused deputy: any page it reads can try to instruct it, and it holds a real session. Domain allowlists and human approval for state-changing actions are the mitigations that actually hold. Secrecy isn't one.
  • Know how to revoke. Sessions should be killable from the service's own device list, independently of whatever your tooling thinks.

Passkeys can't be delegated at all. WebAuthn is bound to an origin and a device, and the cross-device flow expects proximity between your phone and the browser. A browser in a datacenter can't complete it. If a service is passkey-only, this approach doesn't apply — and that's the correct outcome, not a bug.

One more practical note: logging in from a datacenter IP with a brand-new profile triggers device verification on some large providers. Where an API and OAuth exist, use them; browser handoff is for the long tail that has neither.

The shape to aim for

If you're building this yourself, the checklist is short:

  1. Separate login from automation in time, on one profile directory.
  2. No automation flags on the login browser. Real Chrome, real display.
  3. Keep the agent headful too, or the inherited session is useless.
  4. Make the login view private and short-lived. A remote view into a browser someone's typing a password into isn't something to leave open.
  5. Store nothing. If you find yourself adding a vault, you've rebuilt option two.

Browser handoff isn't a replacement for APIs. It's what you reach for when there isn't one — and for most of the work people actually want automated, there isn't.