Skip to main content

Overview

Browser Profiles allow you to capture and reuse browser state (cookies, local storage, session data) across multiple workflow runs. Unlike browser sessions which are temporary, profiles are persistent snapshots that can be reused indefinitely.

Key Concepts

Browser Session vs Browser Profile:
  • Browser Session (browser_session_id): Temporary, active browser instance. Used for maintaining state during a single run or between related tasks.
  • Browser Profile (browser_profile_id): Persistent snapshot of browser state. Can be reused across multiple independent runs.

When to Use Browser Profiles

  • Reusable Authentication: Save logged-in state for multiple workflow runs
  • Pre-configured Environments: Start workflows with pre-filled forms or settings
  • Testing Different States: Create profiles for different user scenarios
  • Login-Free Workflows: Skip authentication steps entirely by starting from an authenticated profile

Creating Browser Profiles

From a Browser Session

Capture a browser session’s state as a profile:
from skyvern import Skyvern

skyvern = Skyvern(api_key="your-api-key")

# 1. Create a browser session and log in
browser = await skyvern.launch_cloud_browser()
page = await browser.get_working_page()

await page.goto("https://example.com")
await page.agent.login(
    credential_type="skyvern",
    credential_id="cred_123"
)

session_id = browser.browser_session_id

# 2. Create a profile from the session
profile = await skyvern.create_browser_profile(
    name="Example.com Authenticated",
    description="Logged in user profile for example.com",
    browser_session_id=session_id
)

print(f"Created profile: {profile.browser_profile_id}")

From a Workflow Run

Capture the final state of a workflow run:
# 1. Run a workflow that performs login
workflow_run = await skyvern.run_workflow(
    workflow_id="wpid_login_workflow",
    parameters={"username": "user@example.com"}
)

# 2. Create profile from the workflow's final state
profile = await skyvern.create_browser_profile(
    name="Post-login Profile",
    description="Profile after completing login workflow",
    workflow_run_id=workflow_run.run_id
)

Via API

curl -X POST https://api.skyvern.com/api/v1/browser-profiles \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Authenticated Profile",
    "description": "Logged in state for production environment",
    "browser_session_id": "pbs_123456789"
  }'
You must provide either browser_session_id OR workflow_run_id, but not both.

Using Browser Profiles

In Task Runs

# Run task with existing profile - no login needed!
task = await skyvern.run_task(
    prompt="Navigate to dashboard and extract metrics",
    url="https://example.com/dashboard",
    browser_profile_id="bp_123456789"  # Start with saved profile
)

In Workflow Runs

workflow_run = await skyvern.run_workflow(
    workflow_id="wpid_data_extraction",
    browser_profile_id="bp_123456789",  # Use saved profile
    parameters={
        "start_date": "2024-01-01",
        "end_date": "2024-12-31"
    }
)

Via API

curl -X POST https://api.skyvern.com/api/v1/workflows/wpid_123/run \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "browser_profile_id": "bp_123456789",
    "parameters": {
      "query": "laptop"
    }
  }'
You cannot specify both browser_session_id and browser_profile_id in the same request. They are mutually exclusive.

Managing Profiles

List All Profiles

# Get all browser profiles for your organization
profiles = await skyvern.list_browser_profiles()

for profile in profiles:
    print(f"Profile: {profile.browser_profile_id}")
    print(f"Name: {profile.name}")
    print(f"Created: {profile.created_at}")
    print(f"Description: {profile.description}")

Get Profile Details

profile = await skyvern.get_browser_profile("bp_123456789")

print(f"Profile ID: {profile.browser_profile_id}")
print(f"Organization: {profile.organization_id}")
print(f"Name: {profile.name}")
print(f"Created: {profile.created_at}")
print(f"Modified: {profile.modified_at}")

Update Profile

# Update profile name or description
updated_profile = await skyvern.update_browser_profile(
    browser_profile_id="bp_123456789",
    name="Updated Profile Name",
    description="New description for this profile"
)

Delete Profile

# Delete a profile when no longer needed
await skyvern.delete_browser_profile("bp_123456789")

Profile Schema

class BrowserProfile(BaseModel):
    browser_profile_id: str          # e.g., "bp_123456789"
    organization_id: str             # Your organization ID
    name: str                        # Profile name
    description: str | None          # Optional description
    created_at: datetime             # When profile was created
    modified_at: datetime            # Last modification time
    deleted_at: datetime | None      # Soft delete timestamp

Use Cases

1. Login-Free Workflow Testing

# Setup: Create authenticated profile once
browser = await skyvern.launch_cloud_browser()
page = await browser.get_working_page()
await page.goto("https://app.example.com")
await page.agent.login("skyvern", "cred_test_user")

test_profile = await skyvern.create_browser_profile(
    name="Test User Profile",
    browser_session_id=browser.browser_session_id
)

# Run: Execute tests without login step
for test_case in test_cases:
    result = await skyvern.run_workflow(
        workflow_id=test_case.workflow_id,
        browser_profile_id=test_profile.browser_profile_id,
        parameters=test_case.params
    )

2. Multi-Account Management

# Create profiles for different accounts
profiles = {
    "admin": await create_profile_for_user("admin@example.com"),
    "user": await create_profile_for_user("user@example.com"),
    "guest": await create_profile_for_user("guest@example.com"),
}

# Run workflows as different users
for role, profile_id in profiles.items():
    await skyvern.run_workflow(
        workflow_id="wpid_data_export",
        browser_profile_id=profile_id,
        parameters={"role": role}
    )

3. Pre-configured Environments

# Create profile with specific settings
browser = await skyvern.launch_cloud_browser()
page = await browser.get_working_page()

# Configure browser state
await page.goto("https://example.com/settings")
await page.click(prompt="Enable dark mode")
await page.click(prompt="Set language to Spanish")
await page.fill(prompt="Notification email", value="alerts@company.com")

# Save configuration as profile
config_profile = await skyvern.create_browser_profile(
    name="Production Configuration",
    description="Dark mode, Spanish, email notifications enabled",
    browser_session_id=browser.browser_session_id
)

# All future runs start with this configuration
await skyvern.run_workflow(
    workflow_id="wpid_monitoring",
    browser_profile_id=config_profile.browser_profile_id
)

Best Practices

Profile Naming Conventions

# Use descriptive names that indicate purpose and environment
profiles = [
    "Production - Admin User - 2024-01",
    "Staging - Test User 1 - Latest",
    "Dev - Guest Access - No Auth",
    "Customer Service - Support Rep - Full Access",
]

Profile Versioning

# Create versioned profiles for different states
profile_v1 = await skyvern.create_browser_profile(
    name="User Profile v1.0",
    description="Initial authenticated state",
    browser_session_id=session_id
)

# Later, create updated version
profile_v2 = await skyvern.create_browser_profile(
    name="User Profile v2.0",
    description="With premium features enabled",
    browser_session_id=new_session_id
)

Regular Profile Updates

import asyncio
from datetime import datetime, timedelta

async def refresh_profile_if_stale(profile_id: str, max_age_days: int = 30):
    """Refresh profile if older than max_age_days"""
    profile = await skyvern.get_browser_profile(profile_id)
    
    age = datetime.now() - profile.modified_at
    if age > timedelta(days=max_age_days):
        # Create new session and update profile
        browser = await skyvern.launch_cloud_browser()
        await perform_login(browser)  # Your login logic
        
        new_profile = await skyvern.create_browser_profile(
            name=profile.name,
            description=f"Refreshed on {datetime.now().date()}",
            browser_session_id=browser.browser_session_id
        )
        
        # Delete old profile
        await skyvern.delete_browser_profile(profile_id)
        
        return new_profile.browser_profile_id
    
    return profile_id

Troubleshooting

Profile State Not Persisting

Ensure the browser session was fully established before creating the profile:
# Wait for login to complete
await page.agent.login("skyvern", "cred_123")
await page.wait_for_load_state("networkidle")

# Now create profile
profile = await skyvern.create_browser_profile(
    name="Fully Loaded Profile",
    browser_session_id=browser.browser_session_id
)

Profile Contains Sensitive Data

Profiles capture all browser state including cookies and local storage. Be cautious:
# Clear sensitive data before creating profile
await page.evaluate("""
    // Clear sensitive local storage items
    localStorage.removeItem('credit_card');
    localStorage.removeItem('ssn');
""")

profile = await skyvern.create_browser_profile(
    name="Sanitized Profile",
    browser_session_id=browser.browser_session_id
)

Build docs developers (and LLMs) love