| title | Profiles |
|---|---|
| description | The primitive to persist and reuse browser session state (cookies, local storage) across browsers |
Profiles let you capture browser state created during a session (cookies and local storage) and reuse it in later sessions. This is the primitive to instantiate authenticated browsers.
When you create a Managed Auth connection, it is attached to a profile. A single profile can hold multiple auth connections — one per domain — so a browser launched with that profile is logged in to all of them at once.
You can also use profiles without Managed Auth. The first step in using profiles is to create one, optionally giving it a meaningful name that is unique within your project.
const kernel = new Kernel();
try { await kernel.profiles.create({ name: 'profiles-demo' }); } catch (err) { if (err instanceof ConflictError) { // Profile already exists } else { throw err; } }
```python Python
from kernel import Kernel, ConflictError
kernel = Kernel()
try:
await kernel.profiles.create(name="profiles-demo")
except ConflictError:
pass
package main
import (
"context"
"errors"
"net/http"
"github.com/kernel/kernel-go-sdk"
)
func main() {
ctx := context.Background()
client := kernel.NewClient()
_, err := client.Profiles.New(ctx, kernel.ProfileNewParams{
Name: kernel.String("profiles-demo"),
})
if err != nil {
var apiErr *kernel.Error
if errors.As(err, &apiErr) && apiErr.StatusCode == http.StatusConflict {
// Profile already exists
return
}
panic(err)
}
}After creating the profile, reference it by its name or id when creating a browser.
Set save_changes to true to persist any state created during this session back into the profile when the browser is closed.
kernel_browser = await kernel.browsers.create(
profile={
"name": "profiles-demo",
"save_changes": True,
}
)kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
Profile: shared.BrowserProfileParam{
Name: kernel.String("profiles-demo"),
SaveChanges: kernel.Bool(true),
},
})
if err != nil {
panic(err)
}
_ = kernelBrowserAfter using a browser with save_changes: true, closing the browser will save cookies and local storage into the profile.
// Navigate and create login state...
await kernel.browsers.deleteByID(kernelBrowser.session_id);
```python Python
print("Live view:", kernel_browser.browser_live_view_url)
# Navigate and create login state...
await kernel.browsers.delete_by_id(kernel_browser.session_id)
fmt.Println("Live view:", kernelBrowser.BrowserLiveViewURL)
// Navigate and create login state...
if err := client.Browsers.DeleteByID(ctx, kernelBrowser.SessionID); err != nil {
panic(err)
}Create another browser using the same profile name. Omitting save_changes leaves the stored profile untouched.
console.log('Live view:', kernelBrowser2.browser_live_view_url);
```python Python
kernel_browser2 = await kernel.browsers.create(
profile={"name": "profiles-demo"}
)
print("Live view:", kernel_browser2.browser_live_view_url)
kernelBrowser2, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
Profile: shared.BrowserProfileParam{
Name: kernel.String("profiles-demo"),
},
})
if err != nil {
panic(err)
}
fmt.Println("Live view:", kernelBrowser2.BrowserLiveViewURL)By default, Profiles restore existing tabs saved in the profile. Pass start_url with the profile to clear those restored tabs and open a specific page when the new browser starts.
Don't depend on previous tabs or windows remaining in a Managed Auth profile. Set start_url when you create a browser if your automation requires a specific first page.
browser = await kernel.browsers.create(
profile={"name": "profiles-demo"},
start_url="https://example.com/dashboard",
)browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
Profile: shared.BrowserProfileParam{
Name: kernel.String("profiles-demo"),
},
StartURL: kernel.String("https://example.com/dashboard"),
})
if err != nil {
panic(err)
}
_ = browserThe same behavior applies to browser pools configured with both a profile and start url.
You can load a profile into a browser after it has been created using the update browser endpoint.
```typescript Typescript/Javascript // Create a browser without a profile const kernelBrowser = await kernel.browsers.create();// Later, load a profile into the browser await kernel.browsers.update(kernelBrowser.session_id, { profile: { name: 'profiles-demo' } });
```python Python
# Create a browser without a profile
kernel_browser = await kernel.browsers.create()
# Later, load a profile into the browser
await kernel.browsers.update(kernel_browser.session_id, profile={"name": "profiles-demo"})
// Create a browser without a profile
kernelBrowser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{})
if err != nil {
panic(err)
}
// Later, load a profile into the browser
_, err = client.Browsers.Update(ctx, kernelBrowser.SessionID, kernel.BrowserUpdateParams{
Profile: shared.BrowserProfileParam{
Name: kernel.String("profiles-demo"),
},
})
if err != nil {
panic(err)
}The API and SDKs support listing, deleting, and downloading profile data as JSON. See the API reference for more details.
A profile can have any number of auth connections, each for a different domain. When you launch a browser with that profile, it is already logged in to every connected domain.
If your agent interacts with multiple sites as part of a single workflow, attach an auth connection for each site to one profile. The browser starts logged in to all of them:
```typescript TypeScript // Create a single profile with auth connections for three sites const gmailAuth = await kernel.auth.connections.create({ domain: 'gmail.com', profile_name: 'workflow-bot', });const slackAuth = await kernel.auth.connections.create({ domain: 'slack.com', profile_name: 'workflow-bot', });
const crmAuth = await kernel.auth.connections.create({ domain: 'crm.example.com', profile_name: 'workflow-bot', });
// Authenticate each connection (omitted for brevity)
// Launch a single browser — logged in to Gmail, Slack, and the CRM const browser = await kernel.browsers.create({ profile: { name: 'workflow-bot' }, stealth: true, });
```python Python
# Create a single profile with auth connections for three sites
gmail_auth = await kernel.auth.connections.create(
domain="gmail.com",
profile_name="workflow-bot",
)
slack_auth = await kernel.auth.connections.create(
domain="slack.com",
profile_name="workflow-bot",
)
crm_auth = await kernel.auth.connections.create(
domain="crm.example.com",
profile_name="workflow-bot",
)
# Authenticate each connection (omitted for brevity)
# Launch a single browser — logged in to Gmail, Slack, and the CRM
browser = await kernel.browsers.create(
profile={"name": "workflow-bot"},
stealth=True,
)
// Create a single profile with auth connections for three sites
gmailAuth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
Domain: "gmail.com",
ProfileName: "workflow-bot",
},
})
if err != nil {
panic(err)
}
_ = gmailAuth
slackAuth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
Domain: "slack.com",
ProfileName: "workflow-bot",
},
})
if err != nil {
panic(err)
}
_ = slackAuth
crmAuth, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
Domain: "crm.example.com",
ProfileName: "workflow-bot",
},
})
if err != nil {
panic(err)
}
_ = crmAuth
// Authenticate each connection (omitted for brevity)
// Launch a single browser — logged in to Gmail, Slack, and the CRM
browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
Profile: shared.BrowserProfileParam{
Name: kernel.String("workflow-bot"),
},
Stealth: kernel.Bool(true),
})
if err != nil {
panic(err)
}
_ = browserIf your platform has end users who each need their own set of authenticated accounts, map each user to a single profile. Attach all of that user's accounts as auth connections on their profile:
```typescript TypeScript // For each user on your platform, create one profile // and attach all their accounts as auth connections const userId = 'user-123';await kernel.auth.connections.create({ domain: 'gmail.com', profile_name: userId, });
await kernel.auth.connections.create({ domain: 'linkedin.com', profile_name: userId, });
await kernel.auth.connections.create({ domain: 'github.com', profile_name: userId, });
// When user-123 triggers a workflow, launch a browser with their profile const browser = await kernel.browsers.create({ profile: { name: userId }, stealth: true, });
```python Python
# For each user on your platform, create one profile
# and attach all their accounts as auth connections
user_id = "user-123"
await kernel.auth.connections.create(
domain="gmail.com",
profile_name=user_id,
)
await kernel.auth.connections.create(
domain="linkedin.com",
profile_name=user_id,
)
await kernel.auth.connections.create(
domain="github.com",
profile_name=user_id,
)
# When user-123 triggers a workflow, launch a browser with their profile
browser = await kernel.browsers.create(
profile={"name": user_id},
stealth=True,
)
// For each user on your platform, create one profile
// and attach all their accounts as auth connections
userID := "user-123"
if _, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
Domain: "gmail.com",
ProfileName: userID,
},
}); err != nil {
panic(err)
}
if _, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
Domain: "linkedin.com",
ProfileName: userID,
},
}); err != nil {
panic(err)
}
if _, err := client.Auth.Connections.New(ctx, kernel.AuthConnectionNewParams{
ManagedAuthCreateRequest: kernel.ManagedAuthCreateRequestParam{
Domain: "github.com",
ProfileName: userID,
},
}); err != nil {
panic(err)
}
// When user-123 triggers a workflow, launch a browser with their profile
browser, err := client.Browsers.New(ctx, kernel.BrowserNewParams{
Profile: shared.BrowserProfileParam{
Name: kernel.String(userID),
},
Stealth: kernel.Bool(true),
})
if err != nil {
panic(err)
}
_ = browser- A profile's
namemust be unique within your project. The same name can be reused across different projects in the same org. - Profiles store cookies and local storage. Start the session with
save_changes: trueto write changes back when the browser is closed. - To keep a profile immutable for a run, omit
save_changes(default) when creating the browser. - Multiple browsers in parallel can use the same profile, but only one browser should write (
save_changes: true) to it at a time. Parallel browsers withsave_changes: truemay cause profile corruption and unpredictable behavior. save_changesapplies to a profile attached to a single browser — either at creation (kernel.browsers.create()) or loaded afterward withkernel.browsers.update(). A profile set on a browser pool's config is loaded read-only and never persisted;save_changessent on a pool's profile is silently ignored. To persist per-user state through a pool, attach the profile after acquiring the browser and release withreuse: false— see Per-user profiles with pools.- Profile data is encrypted end to end using a per-organization key.