Support blank browser profile creation (#6835)

Co-authored-by: Suchintan Singh <suchintan@skyvern.com>
This commit is contained in:
Suchintan 2026-06-26 00:09:29 -04:00 committed by GitHub
parent 791ef8738a
commit 15a24f0247
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 763 additions and 72 deletions

View file

@ -12,16 +12,32 @@ Browser Profiles capture the full browser state (cookies, storage, session files
- Want to fan out multiple workflows that all reuse the same authenticated browser state.
- Need an audit-friendly way to persist state separate from long-lived browser sessions.
Whereas a **browser session** is a temporary, real-time browser, a **browser profile** is a reusable snapshot created from that session (or from a workflow run that persisted its session). Profiles are scoped to your organization and can be reused as often as you need.
Whereas a **browser session** is a temporary, real-time browser, a **browser profile** is a reusable profile archive. You can create one blank, from a browser session, or from a workflow run that persisted its session. Profiles are scoped to your organization and can be reused as often as you need.
## How Browser Profiles Work
1. Run a workflow with `persist_browser_session: true` **or** open a persistent browser session.
2. Close the workflow run or browser session so Skyvern can upload the archived state.
1. Create a blank profile with only `name`, or run a workflow with `persist_browser_session: true` **or** open a persistent browser session.
2. For workflow and browser-session sources, close the workflow run or browser session so Skyvern can upload the archived state.
3. Create a browser profile from that source once the upload finishes.
4. Pass `browser_profile_id` to subsequent workflow runs to restore the saved state instantly.
4. Pass `browser_profile_id` to subsequent workflow runs to start from the saved profile archive.
## Option A — Create a Profile from a Workflow Run
## Option A — Create a Blank Profile
Use this approach when you want a reusable profile ID before any browsing has happened. Skyvern seeds the profile from the configured default browser profile directory when available, with a minimal loadable profile skeleton as a fallback.
```python
from skyvern import Skyvern
skyvern = Skyvern(api_key="YOUR_API_KEY")
browser_profile = await skyvern.browser_profiles.create_browser_profile(
name="fresh-profile",
description="Blank profile for future runs",
)
print(browser_profile.browser_profile_id)
```
## Option B — Create a Profile from a Workflow Run
Use this approach when you already ran a workflow with `persist_browser_session: true`. Always poll the run (e.g., `GET /v1/runs/{run_id}`) until it reaches `status = "completed"` before attempting to create the profile—Skyvern only begins uploading the archived browser state once the run finishes.
@ -67,7 +83,7 @@ async def create_profile_with_retry(
raise RuntimeError("Session never finished uploading a profile archive")
```
## Option B — Create a Profile from a Browser Session
## Option C — Create a Profile from a Browser Session
If you opened a persistent browser session directly (without a workflow), close it and then create a profile using the session ID:
@ -100,4 +116,3 @@ print(workflow_run.run_id)
```
If the workflow also sets `persist_browser_session: true`, you can capture a fresh profile again at the end and keep the cycle going.

View file

@ -2241,7 +2241,7 @@
"Browser Profiles"
],
"summary": "Create a browser profile",
"description": "Create a browser profile from a persistent browser session or workflow run.",
"description": "Create a blank browser profile, or create one from a persistent browser session or workflow run.",
"operationId": "create_browser_profile_v1_browser_profiles_post",
"parameters": [
{
@ -2285,7 +2285,7 @@
}
},
"400": {
"description": "Invalid request - missing source or source not found"
"description": "Invalid request - source not found or source archive unavailable"
},
"409": {
"description": "Browser profile name already exists"
@ -2307,11 +2307,11 @@
"code-samples": [
{
"sdk": "python",
"code": "from skyvern import Skyvern\n\nskyvern = Skyvern(api_key=\"YOUR_API_KEY\")\n# Create a browser profile from a persistent browser session\nbrowser_profile = await skyvern.browser_profiles.create_browser_profile(\n name=\"My Profile\",\n browser_session_id=\"pbs_123\",\n)\nprint(browser_profile)\n\n# Or create from a workflow run with persist_browser_session=True\nbrowser_profile = await skyvern.browser_profiles.create_browser_profile(\n name=\"My Profile\",\n workflow_run_id=\"wr_123\",\n)\nprint(browser_profile)\n"
"code": "from skyvern import Skyvern\n\nskyvern = Skyvern(api_key=\"YOUR_API_KEY\")\n# Create a blank browser profile for future runs\nblank_profile = await skyvern.browser_profiles.create_browser_profile(\n name=\"Fresh Profile\",\n)\nprint(blank_profile)\n\n# Create a browser profile from a persistent browser session\nbrowser_profile = await skyvern.browser_profiles.create_browser_profile(\n name=\"My Profile\",\n browser_session_id=\"pbs_123\",\n)\nprint(browser_profile)\n\n# Or create from a workflow run with persist_browser_session=True\nbrowser_profile = await skyvern.browser_profiles.create_browser_profile(\n name=\"My Profile\",\n workflow_run_id=\"wr_123\",\n)\nprint(browser_profile)\n"
},
{
"sdk": "typescript",
"code": "import { SkyvernClient } from \"@skyvern/client\";\n\nconst skyvern = new SkyvernClient({ apiKey: \"YOUR_API_KEY\" });\n// Create a browser profile from a persistent browser session\nconst browserProfile = await skyvern.browserProfiles.createBrowserProfile({\n name: \"My Profile\",\n browser_session_id: \"pbs_123\",\n});\nconsole.log(browserProfile);\n\n// Or create from a workflow run with persist_browser_session=True\nconst browserProfile2 = await skyvern.browserProfiles.createBrowserProfile({\n name: \"My Profile\",\n workflow_run_id: \"wr_123\",\n});\nconsole.log(browserProfile2);\n"
"code": "import { SkyvernClient } from \"@skyvern/client\";\n\nconst skyvern = new SkyvernClient({ apiKey: \"YOUR_API_KEY\" });\n// Create a blank browser profile for future runs\nconst blankProfile = await skyvern.browserProfiles.createBrowserProfile({\n name: \"Fresh Profile\",\n});\nconsole.log(blankProfile);\n\n// Create a browser profile from a persistent browser session\nconst browserProfile = await skyvern.browserProfiles.createBrowserProfile({\n name: \"My Profile\",\n browser_session_id: \"pbs_123\",\n});\nconsole.log(browserProfile);\n\n// Or create from a workflow run with persist_browser_session=True\nconst browserProfile2 = await skyvern.browserProfiles.createBrowserProfile({\n name: \"My Profile\",\n workflow_run_id: \"wr_123\",\n});\nconsole.log(browserProfile2);\n"
}
]
}
@ -9233,26 +9233,28 @@
"browser_session_id": {
"anyOf": [
{
"type": "string"
"type": "string",
"minLength": 1
},
{
"type": "null"
}
],
"title": "Browser Session Id",
"description": "Persistent browser session to convert into a profile"
"description": "Persistent browser session to convert into a profile. Omit for a blank profile."
},
"workflow_run_id": {
"anyOf": [
{
"type": "string"
"type": "string",
"minLength": 1
},
{
"type": "null"
}
],
"title": "Workflow Run Id",
"description": "Workflow run whose persisted session should be captured"
"description": "Workflow run whose persisted session should be captured. Omit for a blank profile."
}
},
"type": "object",