A profile holds a browser's cookies and storage under a name, so an agent can start signed in. Scrapes, browser sessions and render jobs load profiles by ID or name. Profiles are encrypted in the node's vault, decrypted only inside the browser that loads them, never logged and never sent to a model. They never leave your organization.

Create one from Playwright

A profile's state is Playwright's storageState JSON, uploaded as is. Sign in once with Playwright, export the state, and upload it:

bash
# state.json comes from Playwright: await context.storageState({ path: "state.json", indexedDB: true })curl -s https://beta-api.b3os.org/v1/vision/profiles \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d "{\"name\": \"acme-staging\", \"state\": $(cat state.json)}"

Every cookie domain and storage origin must belong to the profile's domains. Leave domains out and B3OS derives it from the state; a state that strays outside the listed domains fails with profile_domain_mismatch. Names are unique per project. The API returns the domains and counts of cookies, origins and bytes, never the values.

Use a profile

WhereField
Scrape, batch, crawlprofile (implies the browser tier)
Browser sessionprofile, with persist_profile to save back on close
Screenshot, videoprofile, or source.profile for videos

Save from a session

Sign in inside a session (an agent, or a person through the CDP socket), then save its current cookies and storage:

bash
curl -s "https://beta-api.b3os.org/v1/vision/sessions/$SESSION_ID/profile" \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "acme-staging"}'

This creates the profile if the name is new, or writes a new revision if it exists. A session created with profile and persist_profile: true does the same automatically when it closes.

Revisions and conflicts

Every save increments the profile's revision. Two sessions can load the same revision; if one saves first, the other's save would throw away newer state, so it fails with profile_conflict. Save with overwrite (or create the session with overwrite_profile) to replace it anyway, or load the profile again in a new session. While a session with persist_profile holds a profile, its status is locked; other loads still see the last saved revision.

Change, export or delete

  • PATCH /v1/vision/profiles/{profile_id} renames it, changes its domains, expiry or metadata, or replaces its state with a new revision.
  • GET /v1/vision/profiles/{profile_id}/state exports the current state in the same storageState shape, so you can load it into your own browser. It contains live session cookies: treat the response like a password. It needs vision:write, the scope that can replace the state.
  • DELETE /v1/vision/profiles/{profile_id} deletes the profile and every revision. Sessions that already loaded it keep their cookies until they close.

A profile can carry an expires_at, after which it is deleted.

Ask a question... ⌘I