kernel-agent-browser

v2026.09.24

Best practices for using agent-browser with Kernel cloud browsers. Use when automating websites with agent-browser -p kernel, tuning stealth or proxy behavior, persisting profiles, handling iframes, discovering Kernel session IDs or live views, or cleaning up cloud sessions.

GitHub
Install command
npx skhub add kernel/kernel-agent-browser
Markdown
SKILL.md

Agent-Browser with Kernel Cloud Browsers

This skill documents best practices for using agent-browser's built-in Kernel provider (-p kernel) for cloud browser automation.

When to Use This Skill

Use this skill when you need to:

  • Automate websites using agent-browser -p kernel commands
  • Handle bot detection on sites with aggressive anti-bot measures
  • Persist login sessions across automation runs using profiles
  • Work with iframes including cross-origin payment forms
  • Get live view URLs for debugging or manual intervention
  • Find the underlying Kernel session ID for advanced Playwright scripting
  • Create site-specific automation skills for new websites

References

Prerequisites

Load the kernel-cli skill for Kernel CLI installation and authentication.

Environment Variables

Set these before your first agent-browser -p kernel call. The CLI holds state between invocations.

VariableDescriptionDefault
KERNEL_API_KEYRequired. Your Kernel API key for authentication(none)
KERNEL_HEADLESSRun browser in headless mode (true/false)true
KERNEL_STEALTHLaunch a stealth browser (true/false)false
KERNEL_TIMEOUT_SECONDSSession timeout in seconds300
KERNEL_PROFILE_NAMECurrently unusable with -p kernel in agent-browser 0.33.0; use the CDP workaround below(none)

Recommended Configuration

Set options explicitly; agent-browser reads them when it creates the provider session.

export KERNEL_API_KEY="your-api-key"
export KERNEL_TIMEOUT_SECONDS=600     # 10-minute timeout for complex workflows
export KERNEL_HEADLESS=false          # Required when you need a live view
export KERNEL_STEALTH=true            # Opt in for bot-sensitive sites
# Do not set KERNEL_PROFILE_NAME with -p kernel; use the workaround below.

Profile Persistence

Warning: KERNEL_PROFILE_NAME doesn't work with -p kernel in agent-browser 0.33.0. It sends profile as a string instead of the object required by Kernel, so session creation fails with HTTP 400. It also doesn't set save_changes. Profiles must be pre-created.

Until this is fixed upstream, create the browser with the Kernel CLI and attach agent-browser over CDP. Don't combine -p kernel with --cdp.

PROFILE_NAME=mysite  # Create once with: kernel profiles create --name mysite
kernel profiles get "$PROFILE_NAME" >/dev/null
BROWSER=$(kernel browsers create --profile-name "$PROFILE_NAME" --save-changes --timeout 600 -o json)
SESSION_ID=$(jq -er '.session_id' <<<"$BROWSER")
CDP_URL=$(jq -er '.cdp_ws_url' <<<"$BROWSER")
trap 'kernel browsers delete "$SESSION_ID" >/dev/null 2>&1 || true' EXIT

agent-browser --session mysite --cdp "$CDP_URL" open https://example.com
agent-browser --session mysite snapshot -i
# Run additional commands with --session mysite, then disconnect and end the Kernel session.
agent-browser --session mysite close
kernel browsers delete "$SESSION_ID"
trap - EXIT

Don't print or share CDP_URL; it grants browser access. Deleting the CLI-created session finalizes --save-changes, so later sessions can reuse the authenticated profile.

Basic Usage

agent-browser -p kernel open <url>        # Navigate to page
agent-browser -p kernel snapshot -i       # Get interactive elements with refs
agent-browser -p kernel click @e1         # Click element by ref
agent-browser -p kernel fill @e2 "text"   # Fill input by ref
agent-browser -p kernel close             # Close the provider session

For provider-managed sessions, use -p kernel with each command. For the profile/CDP workaround, reuse the same --session name and don't add -p kernel.

Semantic Selectors (Recommended)

Instead of ephemeral @e refs that change on every page load, use semantic selectors via the find command for more stable, readable automation:

# By ARIA role + accessible name (most stable)
agent-browser -p kernel find role button click --name "Log In"
agent-browser -p kernel find role textbox fill "user@email.com" --name "Email"

# By visible text content
agent-browser -p kernel find text "View Menus" click
agent-browser -p kernel find text "Submit Order" click

# By form label (great for inputs)
agent-browser -p kernel find label "Username" fill "myuser"
agent-browser -p kernel find label "Password" fill "secret123"

# By placeholder text
agent-browser -p kernel find placeholder "Search..." type "query"

# By data-testid (if the site uses them)
agent-browser -p kernel find testid "submit-btn" click

# By position (when needed)
agent-browser -p kernel find first "li.item" click
agent-browser -p kernel find nth 2 ".card" hover

When to Use Which Selector

Selector TypeBest ForStability
find role --nameButtons, links, navigation⭐⭐⭐ Most stable
find labelForm inputs with labels⭐⭐⭐ Most stable
find textClickable text elements⭐⭐ Stable
find testidSites with test attributes⭐⭐⭐ Most stable
find placeholderSearch boxes, inputs⭐⭐ Stable
@e refsUnknown sites, quick iteration⭐ Ephemeral

Recommendation: Use find for production automation. Use @e refs for exploration and quick prototyping, then convert to semantic selectors.

Find the Kernel Session and Live View

Match agent-browser's CDP endpoint to the active Kernel session. Compare the URL without its query string: the CLI and agent-browser can hold different short-lived jwt query values for the same session. The endpoint's scheme, host, and path remain stable. This is more reliable than guessing from creation time when several sessions share a profile. This workflow requires jq.

CDP_URL="$(agent-browser -p kernel get cdp-url)"
CDP_ENDPOINT="${CDP_URL%%\?*}"
SESSION_ID="$(
  kernel browsers list --status active --limit 100 -o json |
    jq -r --arg endpoint "$CDP_ENDPOINT" \
      '.[] | select((.cdp_ws_url | split("?")[0]) == $endpoint) | .session_id' |
    head -n 1
)"
test -n "$SESSION_ID"

kernel browsers view "$SESSION_ID"

Do not print or share the CDP URL; it grants browser access. Share a live view URL only with the intended user. A headless session has no live view. If you use --session <name>, include it on every agent-browser command, including get cdp-url.

Handling Bot Detection

Stealth and Proxy Routing

Stealth is opt-in in current agent-browser releases. Set KERNEL_STEALTH=true before the first command for a session; changing it later does not reconfigure the running browser.

A stealth browser can use Kernel's default stealth proxy. If that proxy causes a site-specific network or reputation failure and direct metro egress is acceptable, change the running session without disabling stealth:

kernel browsers update "$SESSION_ID" --disable-default-proxy
# Retry the navigation and compare behavior.

# Re-enable the default stealth proxy while continuing the same session.
kernel browsers update "$SESSION_ID" --disable-default-proxy=false

Direct egress changes the public IP and can reduce anti-bot protection. Prefer the default proxy unless testing shows it is the problem. For a configured Kernel proxy, use --proxy-id <proxy-id>; remove it with --clear-proxy.

Manual Login Fallback

If automated login fails:

  1. Resolve SESSION_ID using the CDP-matching workflow above.
  2. Run kernel browsers view "$SESSION_ID" and give the URL only to the intended user.
  3. Ask the user to complete login, then continue in the same agent-browser session.
  4. To persist the login, use the CLI-created profile/CDP workflow above. Close agent-browser, then delete the Kernel session so --save-changes finalizes.

JavaScript Fallback for Tricky Elements

Some elements (especially on bot-protected sites) don't respond to standard commands:

# Click by CSS selector
agent-browser -p kernel eval "document.querySelector('.submit-btn').click()"

# Fill by selector (with event dispatch)
agent-browser -p kernel eval "
  const el = document.querySelector('#email');
  el.value = 'user@example.com';
  el.dispatchEvent(new Event('input', {bubbles: true}));
  el.dispatchEvent(new Event('change', {bubbles: true}));
"

# Click by test ID
agent-browser -p kernel eval "document.querySelector('[data-testid=\"submit\"]').click()"

Anti-Bot Form Fields

Some payment processors (e.g., Point and Pay) use decoy form fields. Only fill fields matching specific patterns:

agent-browser -p kernel eval "
  const realInputs = Array.from(document.querySelectorAll('input'))
    .filter(el => el.name && el.name.startsWith('xeiinput'));
  // Fill only these inputs
"

Handling Iframes

Same-Origin Iframes

Use the frame command to switch context:

agent-browser -p kernel frame "#iframe-id"   # Switch to iframe
agent-browser -p kernel snapshot -i          # Snapshot within iframe
agent-browser -p kernel click @e1            # Interact within iframe
agent-browser -p kernel frame main           # Return to main frame

Cross-Origin Iframes

Try agent-browser frame first; current releases can switch into iframe context, including many cross-origin frames. If an out-of-process or payment iframe still fails, resolve SESSION_ID and use Kernel's Playwright executor:

kernel browsers playwright execute "$SESSION_ID" '
  const frame = page.frameLocator("#payment-iframe");
  await frame.locator("#card-number").fill("4111111111111111");
  await frame.locator("#submit").click();
'

Return to the main document with agent-browser -p kernel frame main after frame interactions.

Waiting Strategies

Smart waits are critical for fast, reliable automation. Using condition-based waits instead of fixed timeouts can reduce execution time by 50%+ while improving reliability.

Smart Waits (Recommended)

# Wait for page load states
agent-browser -p kernel wait --load domcontentloaded  # DOM ready
agent-browser -p kernel wait --load networkidle       # Network settled

# Wait for specific URL pattern (great for redirects after login)
agent-browser -p kernel wait --url "**/dashboard"
agent-browser -p kernel wait --url "**/order-confirmation"

# Wait for text to appear (great for dynamic content)
agent-browser -p kernel wait --text "Password"        # Field appeared
agent-browser -p kernel wait --text "Order confirmed" # Success message

# Wait for JavaScript condition
agent-browser -p kernel wait --fn "window.appReady === true"
agent-browser -p kernel wait --fn "document.querySelector('.spinner') === null"

# Wait for element by CSS selector
agent-browser -p kernel wait "#login-form"
agent-browser -p kernel wait ".results-loaded"

Fixed Waits (Last Resort)

# Only when no condition is available
agent-browser -p kernel wait 2000

Element Refs Best Practices

Element refs (@e1, @e2, etc.) are ephemeral and change:

  • After page navigation
  • After significant DOM updates
  • Between browser sessions

Always take a fresh snapshot before interacting:

agent-browser -p kernel snapshot -i
# Now use the refs from this snapshot
agent-browser -p kernel click @e5

Filtering Snapshots

# Filter for specific elements
agent-browser -p kernel snapshot -i | grep -i "button\|submit"

# Scope to a specific area
agent-browser -p kernel snapshot -s "#main-content" -i

Login Patterns

Single-Page Form (Optimized)

Username and password on the same page:

agent-browser -p kernel open https://example.com/login
agent-browser -p kernel wait --load domcontentloaded

# Use semantic selectors for stability
agent-browser -p kernel find label "Email" fill "user@example.com"
agent-browser -p kernel find label "Password" fill "secret123"
agent-browser -p kernel find role button click --name "Sign In"

# Wait for actual redirect, not arbitrary timeout
agent-browser -p kernel wait --url "**/dashboard"

Two-Step Form (Optimized)

Username first, then password on a second screen:

agent-browser -p kernel open https://example.com/login
agent-browser -p kernel wait --load domcontentloaded

# Step 1: Username
agent-browser -p kernel find label "Username" fill "myuser"
agent-browser -p kernel press Enter

# Wait for password field to appear (not a fixed sleep!)
agent-browser -p kernel wait --text "Password"

# Step 2: Password
agent-browser -p kernel find label "Password" fill "secret123"
agent-browser -p kernel press Enter

# Wait for successful redirect
agent-browser -p kernel wait --url "**/home"

Modal Login

Login form appears in a modal overlay:

# Click login link to open modal
agent-browser -p kernel find text "Log In" click
agent-browser -p kernel wait --text "Password"  # Wait for modal

# Fill modal fields
agent-browser -p kernel find label "Email" fill "user@example.com"
agent-browser -p kernel find label "Password" fill "password123"
agent-browser -p kernel find role button click --name "Sign In"
agent-browser -p kernel wait --url "**/dashboard"

Fallback: JavaScript for Tricky Modals

Some modals don't expose accessible labels:

agent-browser -p kernel eval "document.querySelector('.login-link').click()"
agent-browser -p kernel wait 1000

agent-browser -p kernel eval "
  document.getElementById('username').value = 'user@example.com';
  document.getElementById('username').dispatchEvent(new Event('input', {bubbles: true}));
  document.getElementById('password').value = 'password123';
  document.getElementById('password').dispatchEvent(new Event('input', {bubbles: true}));
  document.querySelector('button[type=submit]').click();
"
agent-browser -p kernel wait --url "**/dashboard"

Handling New Tabs

Some links open in new tabs:

# Click link that opens new tab
agent-browser -p kernel click @e38
agent-browser -p kernel tab 1           # Switch to new tab (0-indexed)
agent-browser -p kernel wait 2000
agent-browser -p kernel snapshot -i     # Interact with new tab

Screenshots and Debugging

# Take screenshot
agent-browser -p kernel screenshot ~/Downloads/page.png

# Full page screenshot
agent-browser -p kernel screenshot ~/Downloads/full.png --full

# View console messages
agent-browser -p kernel console

# View page errors
agent-browser -p kernel errors

# Get current URL
agent-browser -p kernel get url

Session Management

Cleanup

Close the same named agent-browser session you opened. This saves profile changes and deletes its Kernel browser:

agent-browser -p kernel close
# Named session: agent-browser -p kernel --session site1 close

If agent-browser is unavailable or close fails, delete the orphan explicitly:

kernel browsers delete "$SESSION_ID"

Do not use close --all when unrelated agent-browser sessions may be running.

Multiple Sessions

Run parallel browser sessions with named sessions:

agent-browser -p kernel --session site1 open https://site1.com
agent-browser -p kernel --session site2 open https://site2.com
agent-browser -p kernel session list

Common Gotchas

  1. Refs change after navigation: Re-snapshot after links, submissions, or major DOM updates.
  2. Wait for outcomes: Use URL, text, load-state, or JavaScript conditions after asynchronous actions.
  3. Provider settings are launch-time settings: Close the current session before changing KERNEL_HEADLESS, KERNEL_STEALTH, or timeout.
  4. Profile persistence needs the CDP workaround: KERNEL_PROFILE_NAME is currently broken. Close agent-browser, then delete the CLI-created Kernel session to finalize --save-changes.
  5. Stealth is not sufficient for every site: Compare proxy routing, use manual login, or fall back to direct Playwright for difficult frames.

Quick Reference

# Start a standard provider session (for persistence, use the CDP workflow above)
export KERNEL_TIMEOUT_SECONDS=600
agent-browser -p kernel open https://example.com

# Basic interaction with semantic selectors (recommended)
agent-browser -p kernel wait --load domcontentloaded
agent-browser -p kernel find label "Email" fill "user@example.com"
agent-browser -p kernel find label "Password" fill "secret"
agent-browser -p kernel find role button click --name "Submit"
agent-browser -p kernel wait --url "**/success"

# Alternative: snapshot + refs (for exploration)
agent-browser -p kernel snapshot -i
agent-browser -p kernel fill @eN "text"
agent-browser -p kernel click @eM

# Resolve the underlying session before manual intervention
CDP_URL="$(agent-browser -p kernel get cdp-url)"
CDP_ENDPOINT="${CDP_URL%%\?*}"
SESSION_ID="$(kernel browsers list --status active --limit 100 -o json |
  jq -r --arg endpoint "$CDP_ENDPOINT" \
    '.[] | select((.cdp_ws_url | split("?")[0]) == $endpoint) | .session_id' |
  head -n 1)"
test -n "$SESSION_ID"
kernel browsers view "$SESSION_ID"

# Cleanup (delete by ID only if close fails)
agent-browser -p kernel close

Selector Cheat Sheet

# Buttons and links
agent-browser -p kernel find role button click --name "Submit"
agent-browser -p kernel find role link click --name "Next"
agent-browser -p kernel find text "Click here" click

# Form inputs
agent-browser -p kernel find label "Email" fill "user@example.com"
agent-browser -p kernel find placeholder "Search" type "query"
agent-browser -p kernel find testid "username-input" fill "myuser"

# Smart waits
agent-browser -p kernel wait --load domcontentloaded
agent-browser -p kernel wait --text "Success"
agent-browser -p kernel wait --url "**/dashboard"
agent-browser -p kernel wait --fn "window.loaded === true"
Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.24

Published

Sep 24, 2026

Category

Uncategorized

License

MIT

Source path

plugins/kernel-cli/skills/kernel-agent-browser

Default branch

main

Latest commit

47eab5f

Tree SHA

a212e92