
Browse
- 243 installs
- 4 repo stars
- Updated July 23, 2026
- ulpi-io/skills
Let coding agents browse repos, docs, or structured sources interactively instead of guessing paths or stale context.
About
Provides browse-oriented agent tooling from ulpi-io for systematically exploring repositories, documentation trees, or linked resources so assistants gather ground-truth context before editing code.
- Interactive source browsing
- Agent-friendly navigation
- Reduced hallucinated file paths
- Structured exploration workflow
- CLI-oriented discovery
Browse by the numbers
- 243 all-time installs (skills.sh)
- +5 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #2,614 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/ulpi-io/skills --skill browseAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 243 |
|---|---|
| repo stars | ★ 4 |
| Last updated | July 23, 2026 |
| Repository | ulpi-io/skills ↗ |
What it does
Let coding agents browse repos, docs, or structured sources interactively instead of guessing paths or stale context.
Files
browse: Browser & Native App Automation for AI Agents
Target Decision — ALWAYS check this first
Before running any browse command, decide the correct target:
| User wants to... | Target | Command pattern |
|---|---|---|
| Open a URL, test a website, scrape web content | Browser (default) | browse goto <url> |
Test a local dev server (localhost) | Browser | browse goto http://localhost:3000 |
| Browse a site that blocks bots (Cloudflare, Turnstile) | Camoufox | browse --runtime camoufox --headed goto <url> |
| Browse with a specific camoufox fingerprint profile | Camoufox | browse --runtime camoufox --camoufox-profile <name> --headed goto <url> |
| Search Google, YouTube, Amazon, etc. | Browser | browse goto @google "query" |
| Interact with an iOS app (Settings, Safari, custom app) | iOS Simulator | browse --platform ios --app <bundleId> <cmd> |
| Interact with an Android app (Settings, Chrome, custom app) | Android Emulator | browse --platform android --app <package> <cmd> |
| Interact with a macOS desktop app (System Settings, TextEdit) | macOS App | browse --app <name> <cmd> |
| Install and test an iOS .app or .ipa file | iOS Simulator | browse sim start --platform ios --app ./MyApp.app --visible |
| Install and test an Android .apk file | Android Emulator | browse sim start --platform android --app ./app.apk --visible |
Key rules:
- No `--platform` or `--app` flag → browser target (Chromium). Use
gototo navigate. - `--runtime camoufox --headed` → anti-detection Firefox. Use when site blocks normal browsing. See
/browse-stealthskill for Turnstile/CAPTCHA bypass patterns. - `@macro` in goto URL → search macro expansion.
browse goto @google "query"expands to Google search URL. 14 macros: @google, @youtube, @amazon, @reddit, @wikipedia, @twitter, @yelp, @spotify, @netflix, @linkedin, @instagram, @tiktok, @twitch, @reddit_subreddit. - `--app` without `--platform` → macOS app automation. App must be running.
- `--platform ios --app` → iOS Simulator. Use
browse sim startfirst if not running. - `--platform android --app` → Android Emulator. Use
browse sim startfirst if not running. - Native app targets do NOT support:
goto,js,eval,tabs,cookies,route,har. These are browser-only. - All targets support:
snapshot,text,tap,fill,type,press,swipe,screenshot. - If a site blocks you, switch to
--runtime camoufox --headed. If still blocked, use/browse-stealthfor the full Turnstile bypass pattern. - If unsure which target to use, ASK the user. Don't guess — wrong target = wasted work.
Goal
Use the persistent browse CLI to:
- navigate real pages
- inspect rendered content and state
- interact with UI elements
- capture screenshots, console logs, and network activity
- automate native apps (iOS, Android, macOS) via accessibility APIs
- verify browser or app behavior end-to-end without re-launching every step
Step 0: Verify availability and choose the browsing mode
Start by checking:
browse --versionIf browse is not installed:
- stop
- tell the user it is required
- point them to the install path in
references/commands.md
Then decide what kind of session you need:
- default session for normal single-agent work
--session <id>for parallel agent isolation--profile <name>for persistent browser identity
For native app targets, start the simulator/emulator first:
browse sim start --platform ios --app com.apple.Preferences --visible
browse sim start --platform android --app com.android.settings --visible
browse enable android # first-time only: auto-installs adb, JDK, SDK, emulator
browse enable ios # first-time only: builds iOS runner (needs Xcode)
browse enable macos # first-time only: builds browse-ax bridgeSuccess criteria: browse is available, the target (browser or native app) is decided, and the session/profile choice fits the task.
Step 1: Navigate safely and stabilize the page
Use browse goto <url> to navigate.
After navigation, always stabilize before reading or interacting:
browse wait --network-idlefor typical pages and SPAs- or a more specific
browse waitcondition when the page has a known signal
Important rules:
- call
browseas a bare command on PATH - do not use shell variables for browse command prefixes
- avoid
#idCSS selectors; prefer[id=foo] - if the page is untrusted, consider
--content-boundariesand--allowed-domains
Success criteria: The page is loaded enough that content and interactive state are reliable.
Step 2: Choose the cheapest effective inspection method
Use the lightest command that answers the question:
textfor cleaned page contentlinksfor navigation structurejsfor precise targeted extractionconsole,errors, andnetworkfor runtime debuggingsnapshot -ifor interactive elements and stable refs
Prefer snapshot -i before guessing selectors for interaction-heavy tasks.
Load:
references/commands.mdfor exact command syntaxreferences/guides.mdfor command selection guidance and speed rules
Success criteria: You have the information needed without spending unnecessary tokens or using brittle selectors.
Step 3: Interact using refs first, selectors second
For clicks, fills, checks, selects, and similar actions:
1. prefer browse snapshot -i 2. interact using @eN refs 3. fall back to CSS selectors only when refs are unavailable or impractical
After navigation or DOM refresh:
- assume refs may be invalid
- take a fresh snapshot before continuing
Rules:
- use descriptive screenshots saved under
.browse/sessions/<id>/ - keep stateful flows in the same session unless isolation is intentional
- use
framebefore interacting with iframe content
Success criteria: Interactions are stable and tied to the current rendered page state.
Step 4: Debug blockers and special cases
When things go wrong:
- use
consoleanderrorsfor page/runtime issues - use
networkfor request visibility - use
routeorofflineonly when the task requires mock or failure-mode testing - use headed/browser handoff only for real blockers like CAPTCHA, MFA, or OAuth walls
If you hit a blocker after a couple of failed attempts:
- load
references/guides.md - follow the handoff protocol exactly
- use
AskUserQuestionbefore any human takeover flow
Success criteria: Blockers are either resolved or escalated with the correct handoff protocol.
Step 5: Capture evidence and report clearly
When the task involves verification, capture the minimum evidence needed:
- relevant page text or structured extraction
- screenshot path when visuals matter
- console/network findings when debugging
- the exact step or selector/ref that failed when reporting issues
Report:
- what you navigated to
- what actions you performed
- what the page actually did
- any artifacts created such as screenshots, HAR, or video
Success criteria: Another engineer can understand the observed browser behavior without rerunning the whole flow blindly.
Important Rules
- The browser persists between commands; cookies, tabs, and session state carry over.
- After
goto, wait before reading content or acting. snapshot -iis the default interaction surface.- Save screenshots under
.browse/sessions/<session-id>/or.browse/sessions/default/. - Use
--context deltafor ARIA diff with refs,--context fullfor complete snapshot with refs after write commands. - Do not install anything automatically.
- Do not modify Claude settings automatically; if the user wants pre-allowed browse permissions, point them to
references/permissions.md.
When To Load References
references/commands.md
Use for exact command syntax, flags, and extended examples.
references/guides.md
Use for speed rules, command-choice guidance, architecture notes, and the mandatory CAPTCHA/MFA handoff protocol.
references/permissions.md
Use when the user wants to pre-allow browse commands in Claude settings.
Guardrails
- Do not add
disable-model-invocation; this is a general-purpose browser verification skill. - Do not add
context: fork; browser results are usually needed in the current flow. - Do not add
paths:; this is a generic workflow skill. - Do not keep the full CLI manual inline in
SKILL.md. - Do not run
browse handoffwithout explicit user confirmation. - Do not save screenshots outside the browse session directories.
Runtime Selection
By default, browse uses Chromium via Playwright. Alternative runtimes:
| Runtime | Engine | Use case | Install |
|---|---|---|---|
playwright (default) | Chromium | General browsing, testing | Included |
camoufox | Firefox (anti-detection) | Sites with bot detection | npm install camoufox-js && npx camoufox-js fetch |
rebrowser | Chromium (stealth) | Alternative stealth approach | npm install rebrowser-playwright |
lightpanda | Lightpanda | Fast headless rendering | See lightpanda.io |
chrome | System Chrome | Use real Chrome with extensions | Chrome must be installed |
browse --runtime camoufox --headed goto https://protected-site.com
BROWSE_RUNTIME=camoufox browse goto https://example.comNew Features
Search Macros
browse goto @google "best coffee beans" # Google search
browse goto @youtube "tutorial" # YouTube search
browse goto @amazon "laptop" # Amazon search
browse goto @reddit "programming" # Reddit searchAll macros: @google, @youtube, @amazon, @reddit, @reddit_subreddit, @wikipedia, @twitter, @yelp, @spotify, @netflix, @linkedin, @instagram, @tiktok, @twitch
Safety Flags (opt-in features)
| Flag | Default | What it does |
|---|---|---|
BROWSE_CONSENT_DISMISS=1 | OFF | Auto-dismiss cookie banners after navigation |
BROWSE_CLICK_FORCE=1 or --force | OFF | Force-click through overlay interception |
BROWSE_READINESS=1 or --ready | OFF | Wait for hydration after goto |
BROWSE_SERP_FASTPATH=1 or --serp | OFF | Google SERP DOM extraction (fast, no refs) |
BROWSE_COMMAND_LOCK=0 | ON | Disable per-session command serialization |
BROWSE_CAMOUFOX_PROFILE=<name> | OFF | Use a named camoufox profile (.browse/camoufox-profiles/<name>.json) |
New Commands
| Command | Description |
|---|---|
images [sel] [--limit N] [--inline] | List page images with src/alt/dimensions |
youtube-transcript <url> [--lang en] | Extract YouTube captions via yt-dlp or browser |
schema | Extract JSON-LD, Microdata, RDFa structured data (parsed JSON) |
meta | Extract page meta tags (title, description, canonical, OG, Twitter, hreflang, robots, viewport) |
headings | Extract H1-H6 heading hierarchy with counts and indented tree |
profiles | List available camoufox profiles from .browse/camoufox-profiles/ |
Snapshot Windowing
Large snapshots (>80K chars) are automatically paginated:
browse snapshot -i # first page
browse snapshot -i --offset 500 # next page (line offset from previous output)Output Contract
Report:
1. the page or flow tested 2. the session/profile mode used if relevant 3. the key commands or interactions performed 4. the observed result 5. any artifacts or blockers such as screenshots, console errors, network failures, or handoff state
browse — Full Command Reference
Read this file when you need command syntax not covered in the SKILL.md Quick Reference, or need exact flags for a specific command category.
Quick Reference (all examples)
# Navigate to a page
browse goto https://example.com
# Read cleaned page text
browse text
# Take a screenshot (saved to .browse/sessions/default/screenshot.png)
browse screenshot
# Snapshot: accessibility tree with refs
browse snapshot -i
# Click by ref (after snapshot)
browse click @e3
# Fill by ref
browse fill @e4 "test@test.com"
# Double-click, focus, check/uncheck
browse dblclick @e3
browse focus @e5
browse check @e7
browse uncheck @e7
# Drag and drop
browse drag @e1 @e2
# Run JavaScript
browse js "document.title"
# Get all links
browse links
# Get input value / count elements
browse value "[id=email]"
browse count ".search-result"
# Click by CSS selector
browse click "button.submit"
# Fill a form by CSS selector (use [id=...] instead of # to avoid shell issues)
browse fill "[id=email]" "test@test.com"
browse fill "[id=password]" "abc123"
browse click "button[type=submit]"
# Scroll
browse scroll up
browse scroll down
browse scroll "[id=target]"
# Wait for navigation or network
browse wait ".loaded"
browse wait --url "**/dashboard"
browse wait --network-idle
# iframe targeting
browse frame "[id=my-iframe]"
browse text # reads from inside the iframe
browse click @e3 # clicks inside the iframe
browse frame main # back to main page
# Highlight an element (visual debugging)
browse highlight @e5
# Download a file
browse download @e3 ./file.pdf
# Network mocking
browse route "**/*.png" block
browse route "**/api/data" fulfill 200 '{"mock":true}'
browse route clear
# Offline mode
browse offline on
browse offline off
# JSON output mode
browse --json goto https://example.com
# Security: content boundaries
browse --content-boundaries text
# Security: domain restriction
browse --allowed-domains example.com,*.cdn.example.com goto https://example.com
# State persistence
browse state save mysite
browse state load mysite
browse state clean # delete states older than 7 days
browse state clean --older-than 30 # custom threshold
# Cookie management
browse cookie clear # clear all cookies
browse cookie set auth token --domain .example.com # set with options
browse cookie export ./cookies.json # export to file
browse cookie import ./cookies.json # import from file
# Cookie import from real browsers (macOS -- Chrome, Arc, Brave, Edge)
browse cookie-import --list # show installed browsers
browse cookie-import chrome --domain .example.com # import cookies for a domain
browse cookie-import arc --domain .github.com # import from Arc
browse cookie-import chrome --profile "Profile 1" --domain .site.com # specific Chrome profile
# Session auto-persistence (named sessions survive restarts)
browse --session myapp goto https://app.com/login # login...
browse session-close myapp # state auto-saved (encrypted if BROWSE_ENCRYPTION_KEY set)
browse --session myapp goto https://app.com/dashboard # cookies auto-restored
# Persistent profiles (full browser state, own Chromium)
browse --profile mysite goto https://app.com # all state persists automatically
browse --profile mysite snapshot -i # still logged in next time
browse profile list # list all profiles with size
browse profile delete old-site # remove a profile
# Load state at launch
browse --state auth.json goto https://app.com # load cookies before first command
# Auth vault (credentials never visible to LLM)
browse auth save github https://github.com/login user pass123
browse auth login github
# HAR recording
browse har start
browse goto https://example.com
browse har stop ./recording.har
# Video recording (watch a .webm of the session)
browse video start ./videos
browse goto https://example.com
browse click @e3
browse video stop
# Command recording (export replayable scripts)
browse record start
browse goto https://example.com
browse click "a"
browse fill "[id=search]" "test query"
browse record stop
browse record export replay ./recording.json # replay with: npx @puppeteer/replay ./recording.json
browse record export browse ./steps.json # replay with: cat steps.json | browse chain
# Both together (video + replayable script)
browse video start ./videos
browse record start
browse goto https://example.com
browse snapshot -i
browse click @e3
browse fill "[id=email]" "user@test.com"
browse record stop
browse video stop
browse record export replay ./recording.json
# Device emulation
browse emulate iphone
browse emulate reset
# Parallel sessions
browse --session agent-a goto https://site1.com
browse --session agent-b goto https://site2.com
# Clipboard
browse clipboard
browse clipboard write "copied text"
# Find elements semantically
browse find role button
browse find text "Submit"
browse find testid "login-btn"
# Screenshot diff (visual regression)
browse screenshot-diff baseline.png current.png
# Headed mode (visible browser)
browse --headed goto https://example.com
# Handoff (human takeover for CAPTCHA/MFA -- see guides.md for protocol)
browse handoff "stuck on CAPTCHA"
browse resume
# React debugging
browse react-devtools enable
browse react-devtools tree
browse react-devtools props @e3
browse react-devtools suspense
browse react-devtools disable
# Stealth mode (bypasses bot detection)
browse --runtime rebrowser goto https://example.com
# State list / show
browse state list
browse state show mysite
# Native app automation (Android, iOS, macOS)
browse sim start --platform android --app com.android.settings --visible
browse sim start --platform ios --app com.apple.Preferences --visible
browse --platform android --app com.android.settings snapshot -i
browse --platform ios --app com.apple.Preferences snapshot -i
browse --app "System Settings" snapshot -i # macOS
browse --platform android --app com.android.settings tap @e3
browse --platform android --app com.android.settings swipe up
browse --platform android --app com.android.settings press back
browse --platform ios --app com.apple.mobilesafari type "example.com"
browse --app TextEdit press "cmd+n" # macOS modifier combos
browse sim stop --platform android
browse sim stop --platform ios
# Install and test your own app from a file
browse sim start --platform ios --app ./build/MyApp.app --visible # .app bundle
browse sim start --platform ios --app ./MyApp.ipa --visible # .ipa archive
browse sim start --platform android --app ./app-debug.apk --visible # .apk file
# Cloud providers (encrypted API keys, never visible to agents)
browse provider save browserbase <api-key>
browse --provider browserbase goto https://example.com
# Performance audit
browse perf-audit https://example.com
browse perf-audit save baseline
browse perf-audit compare baselineNavigation
browse goto <url> Navigate current tab
browse goto <url> --ready Wait for hydration/readiness after navigation
browse goto @google "query" Search macro — expands to Google search URL
browse goto @youtube "query" Search macro — YouTube, Amazon, Reddit, Wikipedia, etc.
browse back Go back
browse forward Go forward
browse reload Reload page
browse url Print current URLContent extraction
browse text Cleaned page text (no scripts/styles)
browse html [selector] innerHTML of element, or full page HTML
browse links All links as "text -> href"
browse forms All forms + fields as JSON
browse accessibility Accessibility tree snapshot (ARIA)
browse images List page images (src, alt, dimensions)
browse images [selector] Images within a specific element
browse images --limit 20 Limit number of images returned
browse images --inline Include base64-encoded image data
browse schema Extract JSON-LD, Microdata, RDFa structured data (parsed JSON)
browse meta Extract page meta tags (title, description, canonical, OG, Twitter, hreflang, robots, viewport)
browse headings Extract H1-H6 heading hierarchy with counts and indented treeSnapshot (ref-based element selection)
browse snapshot Full accessibility tree with @refs
browse snapshot -i Interactive elements only -- terse flat list (minimal tokens)
browse snapshot -i -f Interactive elements -- full indented tree with props
browse snapshot -i -V Interactive elements -- viewport only (skip below-fold)
browse snapshot -c Compact (no empty structural elements)
browse snapshot -C Cursor-interactive (detect divs with cursor:pointer/onclick/tabindex)
browse snapshot -d <N> Limit depth to N levels
browse snapshot -s <sel> Scope to CSS selector
browse snapshot --offset <N> Start output from line N (windowing for large snapshots)
browse snapshot --max-chars <N> Limit snapshot output to N characters
browse snapshot --serp Google SERP fast extraction (structured results, no refs)
browse snapshot-diff Compare current vs previous snapshotAfter snapshot, use @refs as selectors in any command:
browse click @e3 Click the element assigned ref @e3
browse fill @e4 "value" Fill the input assigned ref @e4
browse hover @e1 Hover the element assigned ref @e1
browse html @e2 Get innerHTML of ref @e2
browse css @e5 "color" Get computed CSS of ref @e5
browse attrs @e6 Get attributes of ref @e6Refs are invalidated on navigation -- run snapshot again after goto.
Interaction
browse click <selector> Click element (CSS selector or @ref)
browse click <sel> --force Force-click through overlay interception (bypasses actionability checks)
browse click <sel> --if-exists Click only if element exists (no error if missing)
browse click <sel> --if-visible Click only if element is visible
browse click <x>,<y> Click at page coordinates (e.g. 590,461)
browse rightclick <selector> Right-click element (context menu)
browse dblclick <selector> Double-click element
browse fill <selector> <value> Fill input field
browse fill <sel> <val> --if-empty Fill only if field is empty
browse select <selector> <val> Select dropdown value
browse hover <selector> Hover over element
browse hover <sel> --if-exists Hover only if element exists
browse hover <sel> --if-visible Hover only if visible
browse focus <selector> Focus element
browse focus <sel> --if-exists Focus only if element exists
browse focus <sel> --if-visible Focus only if visible
browse tap <selector> Tap element (requires touch context via emulate)
browse tap <sel> --if-exists Tap only if element exists
browse tap <sel> --if-visible Tap only if visible
browse check <selector> Check checkbox
browse check <sel> --if-unchecked Check only if not already checked
browse uncheck <selector> Uncheck checkbox
browse drag <src> <tgt> Drag source to target
browse type <text> Type into focused element
browse press <key> Press key (Enter, Tab, Escape, etc.)
browse keydown <key> Hold key down
browse keyup <key> Release key
browse keyboard inserttext <t> Insert text without key events
browse scroll [sel|up|down] Scroll element/viewport/bottom
browse scrollinto <sel> Scroll element into view (explicit)
browse scrollintoview <sel> Alias for scrollinto
browse swipe <dir> [px] Swipe up/down/left/right (touch events)
browse mouse move <x> <y> Move mouse to coordinates
browse mouse down [button] Press mouse button (left/right/middle)
browse mouse up [button] Release mouse button
browse mouse wheel <dy> [dx] Scroll wheel
browse wait <sel> Wait for element to appear
browse wait <sel> --state hidden Wait for element to disappear
browse wait <ms> Wait for milliseconds
browse wait --text "..." Wait for text to appear in page
browse wait --fn "expr" Wait for JavaScript condition
browse wait --load <state> Wait for load state
browse wait --url <pattern> Wait for URL match
browse wait --network-idle Wait for network idle
browse wait --request <pattern> Wait for a matching network request
browse wait --download Wait for download, return temp path
browse wait --download ./report.pdf Wait and save to path
browse wait --download 60000 Custom timeout (ms)
browse wait --download ./file.pdf 60000 Both path and timeout
browse set geo <lat> <lng> Set geolocation
browse set media <scheme> Set color scheme (dark/light/no-preference)
browse header <name>:<value> Set request header
browse useragent <string> Set user agent string
browse viewport <WxH> Set viewport size (e.g. 375x812)
browse upload <sel> <files> Upload file(s) to a file input
browse highlight <selector> Highlight element (visual debugging)
browse download <sel> [path] Download file triggered by click
browse download <sel> --inline Return file content as base64 (no disk write)
browse dialog-accept [value] Set dialogs to auto-accept
browse dialog-dismiss Set dialogs to auto-dismiss (default)
browse emulate <device> Emulate device (iphone, pixel, etc.)
browse emulate reset Reset to desktop (1920x1080)
browse offline [on|off] Toggle offline modeCookies
browse cookie <n>=<v> Set cookie (shorthand)
browse cookie set <n> <v> [--domain d --secure] Set cookie with options
browse cookie clear Clear all cookies
browse cookie export <file> Export cookies to JSON file
browse cookie import <file> Import cookies from JSON fileNetwork
browse route <pattern> block Block matching requests
browse route <pattern> fulfill <s> [b] Mock with status + body
browse route clear Remove all routesInspection
browse js <expression> Run JS, print result
browse eval <js-file> Run JS file against page
browse css <selector> <prop> Get computed CSS property
browse attrs <selector> Get element attributes as JSON
browse element-state <selector> Element state (visible/enabled/checked/focused)
browse value <selector> Get input field value
browse count <selector> Count matching elements
browse box <selector> Get bounding box as JSON {x, y, width, height}
browse layout <selector> Get element layout details
browse request <index|url> Inspect a captured network request by index or URL pattern
browse dialog Last dialog info or "(no dialog detected)"
browse console [--clear] View/clear console messages
browse errors [--clear] View/clear page errors (filtered from console)
browse network [--clear] View/clear network requests
browse cookies Dump all cookies as JSON
browse storage [set <k> <v>] View/set localStorage
browse perf Page load performance timings
browse devices [filter] List available device names
browse clipboard Read system clipboard text
browse clipboard write <text> Write text to system clipboardVisual
browse screenshot [path] Viewport screenshot (default: .browse/sessions/{id}/screenshot.png)
browse screenshot --full [path] Full-page screenshot (entire scrollable page)
browse screenshot <sel|@ref> [path] Screenshot specific element
browse screenshot --clip x,y,w,h [path] Screenshot clipped region
browse screenshot --annotate [path] Screenshot with numbered badges + legend
browse pdf [path] Save as PDF
browse responsive [prefix] Screenshots at mobile/tablet/desktopFrames (iframe targeting)
browse frame <selector> Target an iframe (subsequent commands run inside it)
browse frame main Return to main pageFind (semantic element locators)
browse find role <query> Find elements by ARIA role
browse find text <query> Find elements by text content
browse find label <query> Find elements by label
browse find placeholder <query> Find elements by placeholder
browse find testid <query> Find elements by test ID
browse find alt <query> Find elements by alt text
browse find title <query> Find elements by title attribute
browse find first <sel> First matching element
browse find last <sel> Last matching element
browse find nth <n> <sel> Nth matching element (0-indexed)Compare
browse diff <url1> <url2> Text diff between two pages
browse screenshot-diff <base> [curr] Pixel-diff two PNG screenshotsMulti-step (chain)
echo '[["goto","https://example.com"],["snapshot","-i"],["click","@e1"]]' | browse chainTabs
browse tabs List tabs (id, url, title)
browse tab <id> Switch to tab
browse newtab [url] Open new tab
browse closetab [id] Close tabSessions (parallel agents)
browse --session <id> <cmd> Run command in named session
browse sessions List active sessions
browse session-close <id> Close a sessionProfiles
browse --profile <name> <cmd> Use persistent browser profile
browse profile list List profiles with disk size
browse profile delete <name> Delete a profile
browse profile clean [--older-than <d>] Remove old profiles (default: 7 days)
browse profiles List available camoufox profiles from .browse/camoufox-profiles/State persistence
browse state save [name] Save cookies + localStorage (all origins)
browse state load [name] Restore saved state
browse state list List saved states
browse state show [name] Show contents of saved state
browse state clean Delete states older than 7 days
browse state clean --older-than N Custom age threshold (days)Cookie import (macOS -- borrow auth from real browsers)
browse cookie-import --list List installed browsers
browse cookie-import <browser> --domain <d> Import cookies for a domain
browse cookie-import <browser> --profile <p> --domain <d> Specific Chrome profileAuth vault
browse auth save <name> <url> <user> <pass|--password-stdin> Save credentials (encrypted)
browse auth login <name> Auto-login using saved credentials
browse auth list List saved credentials
browse auth delete <name> Delete credentialsHAR recording
browse har start Start recording network traffic
browse har stop [path] Stop and save HAR fileVideo recording
browse video start [dir] Start recording video (WebM, compositor-level)
browse video stop Stop recording and save video files
browse video status Check if recording is activeCommand recording & export
browse record start Start recording commands
browse record stop Stop recording, keep steps for export
browse record status Recording state and step count
browse record export browse [path] Export as chain-compatible JSON (replay with browse chain)
browse record export replay [path] Export as Chrome DevTools Recorder (Playwright/Puppeteer)
browse record export replay --selectors css,aria [path] Filter selector types in exportNative App Automation
browse sim start --platform ios|android --app <id-or-path> [--visible] [--device <name>] Start + install/launch app
browse sim stop --platform ios|android Stop simulator/emulator
browse sim status --platform ios|android Check runner status
browse --platform ios --app <bundleId> <command> Target iOS app
browse --platform android --app <package> <command> Target Android app
browse --app <name> <command> Target macOS appThe --app flag accepts a bundle ID, package name, or file path (.app/.ipa/.apk). File paths auto-install the app into the simulator/emulator.
Supported commands on all app platforms: snapshot, text, tap, fill, type, press, swipe, screenshot. macOS also supports modifier combos: browse --app TextEdit press "cmd+n". Android auto-installs adb, Java, SDK, and emulator on first use (macOS via Homebrew).
Common iOS Bundle IDs
| App | Bundle ID |
|---|---|
| Settings | com.apple.Preferences |
| Safari | com.apple.mobilesafari |
| Maps | com.apple.Maps |
| Photos | com.apple.mobileslideshow |
| Calendar | com.apple.mobilecal |
Common Android Package Names
| App | Package Name |
|---|---|
| Settings | com.android.settings |
| Chrome | com.android.chrome |
| Dialer | com.google.android.dialer |
| Messages | com.google.android.apps.messaging |
| Calculator | com.google.android.calculator |
Platform enablement (run once)
browse enable android # Auto-installs adb, JDK, SDK, emulator, driver
browse enable ios # Builds iOS runner (needs Xcode)
browse enable macos # Builds browse-ax bridge
browse enable all # All platformsPerformance audit
browse perf-audit [url] Full performance audit (Web Vitals, resources, images, fonts, DOM, render-blocking, third-party, stack detection, correlations, recommendations)
browse perf-audit [url] --no-coverage Skip JS/CSS coverage collection (faster)
browse perf-audit [url] --no-detect Skip framework/SaaS/infrastructure detection
browse perf-audit [url] --json Output as structured JSON (for programmatic use)
browse perf-audit [url] --budget lcp:2500,cls:0.1,tbt:300 Set performance budgets (fail if exceeded)
browse perf-audit save [name] Save audit report to .browse/audits/ (auto-names from URL + date if omitted)
browse perf-audit compare <base> [curr] Compare saved baseline vs current page or another saved audit (regression detection)
browse perf-audit list List saved audit reports (name, size, date)
browse perf-audit delete <name> Delete a saved audit report
browse detect Detect tech stack: frameworks, SaaS platforms, CDN, protocol, compression, caching, DOM complexity, third-party inventory
browse coverage start Start JS/CSS code coverage collection
browse coverage stop Stop collection and report per-file used/unused bytes
browse initscript set <code> Inject JS that runs before every page load (pre-navigation observers, mocks, polyfills)
browse initscript show Show current init script
browse initscript clear Remove init scriptYouTube transcript
browse youtube-transcript <url> Extract captions from YouTube video
browse youtube-transcript <url> --lang en Specify caption languageAPI requests
browse api <method> <url> Make HTTP request (GET, POST, PUT, DELETE, etc.)
browse api <method> <url> --body '{"key":"val"}' With JSON body
browse api <method> <url> --header "Auth:Bearer x" With custom headerAssertions (expect)
browse expect --url <pattern> Assert current URL matches
browse expect --text <text> Assert text exists on page
browse expect --visible <selector> Assert element is visible
browse expect --hidden <selector> Assert element is hidden
browse expect --count <selector> <n> Assert element count
browse expect --request <pattern> Assert a network request was made
browse expect --timeout 5000 Custom timeout for assertions (ms)Visual & Accessibility audit
browse visual Visual snapshot of the page
browse a11y-audit Accessibility audit (WCAG violations, warnings, passes)Flows (reusable test sequences)
browse flow <file.yaml> Run a flow from a YAML file
browse flow save <name> Save recorded commands as a named flow
browse flow run <name> Run a saved flow by name
browse flow list List saved flowsRetry & Watch
browse retry "<cmd>" --until <condition> Retry a command until condition is met
browse retry "<cmd>" --until <cond> --max 5 Max retry attempts (default: 10)
browse retry "<cmd>" --until <cond> --backoff Exponential backoff between retries
browse watch "<selector>" Watch an element for changes
browse watch "<sel>" --on-change "<cmd>" Run command when element changes
browse watch "<sel>" --timeout 30000 Custom watch timeout (ms)Cloud Providers
browse provider save <name> <key> Save provider API key (encrypted)
browse provider list List saved providers
browse provider delete <name> Delete provider keyReact DevTools
browse react-devtools enable Enable React DevTools (downloads hook, injects, reloads)
browse react-devtools disable Disable React DevTools
browse react-devtools tree Component tree with indentation
browse react-devtools props <sel> Props/state/hooks of component at element
browse react-devtools suspense Suspense boundaries + status
browse react-devtools errors Error boundaries + caught errors
browse react-devtools profiler Render timing per component
browse react-devtools hydration Hydration timing (Next.js)
browse react-devtools renders What re-rendered since last commit
browse react-devtools owners <sel> Parent component chain
browse react-devtools context <sel> Context values consumed by componentServer management
browse status Server health, uptime, session count
browse instances List all running browse servers (instance, PID, port, status)
browse version Print CLI version
browse doctor System check (Node, Playwright, Chromium)
browse upgrade Self-update via npm
browse stop Shutdown server
browse restart Kill + restart server
browse inspect Open DevTools (requires BROWSE_DEBUG_PORT)CLI Flags
| Flag | Description |
|---|---|
--session <id> | Named session (isolates tabs, refs, cookies — auto-persists on close) |
--profile <name> | Persistent browser profile (own Chromium, full state) |
--state <path> | Load state file (cookies/storage) before first command |
--json | Wrap output as {success, data, command} |
--content-boundaries | Wrap page content in nonce-delimited markers (prompt injection defense) |
--allowed-domains <d,d> | Block navigation/resources outside allowlist |
--max-output <n> | Truncate output to N characters |
--headed | Run browser in headed (visible) mode |
--chrome | Shortcut for --runtime chrome --headed (uses real Chrome, bypasses bot detection) |
--cdp <port> | Connect to Chrome on a specific debugging port |
--connect | Auto-discover and connect to a running Chrome instance |
--provider <name> | Cloud browser provider (browserless, browserbase) |
--runtime <name> | Browser engine: playwright (default), camoufox (anti-detection Firefox), rebrowser (stealth), lightpanda, chrome |
--ready | Wait for hydration/readiness after goto |
--force | Force-click through overlay interception |
--serp | Google SERP fast extraction mode |
--mcp | Run as MCP server (for Cursor, Windsurf, Cline) |
--context | Show state changes after commands |
--context delta | ARIA diff with refs |
--context full | Complete snapshot with refs after write commands |
--camoufox-profile <name> | Use a named camoufox profile for browser launch (JSON in .browse/camoufox-profiles/<name>.json). Only applies when starting a new server. |
| `--platform <ios\ | android>` |
--app <id-or-path> | Target app by bundle ID, package name, or file path (.app/.ipa/.apk) |
--device <name> | Simulator/emulator device name (e.g. "iPhone 15", "Pixel 7") |
Handoff (human takeover)
browse handoff [reason] Swap to visible browser for user to solve CAPTCHA/MFA
browse resume Swap back to headless, returns fresh snapshotSee guides.md for the mandatory handoff protocol.
browse — Operational Guides
Read this file when you need the handoff protocol, optimization tips, or help choosing which command to use.
Handoff Protocol (MANDATORY)
Read this section when you hit CAPTCHA, MFA, OAuth, or any blocker after 2-3 failed attempts. The server auto-suggests handoff after 3 consecutive failures (look for HINT in error messages).
When the browser hits a blocker you can't solve, you MUST follow this exact 3-step protocol. Do NOT skip any step.
Step 1 — Ask permission (REQUIRED before handoff)
Use AskUserQuestion (or your platform's equivalent interactive prompt tool) to ask the user before opening the browser. Do NOT just print text and proceed — you MUST wait for an explicit response.
AskUserQuestion:
question: "I'm stuck on a CAPTCHA at [URL]. Can I open a visible browser so you can solve it?"
options:
- label: "Yes, open browser"
description: "Opens a visible Chrome window with your current session"
- label: "No, try something else"
description: "I'll try cookie-import, auth login, or a different approach"If your platform does not have AskUserQuestion, ask the user via text and wait for their response before proceeding. Do NOT run handoff without explicit user confirmation.
If the user says no, try cookie-import, auth login, or a different approach.
Step 2 — Handoff + wait for user (REQUIRED)
Run the handoff command, then use AskUserQuestion (or equivalent) to wait for the user to finish:
browse handoff "Stuck on CAPTCHA at login page"Then immediately prompt the user:
AskUserQuestion:
question: "Browser is open. Please solve the CAPTCHA, then click Done."
options:
- label: "Done"
description: "I've solved it, return to headless mode"
- label: "Cancel"
description: "Close the browser, try something else"Do NOT proceed or do any other work while waiting. The user is interacting with the visible browser — wait for their response.
Step 3 — Resume
After the user responds:
browse resume
# Returns fresh snapshot — continue working with itIf "Done" — continue with the fresh snapshot from resume. If "Cancel" — resume anyway (closes headed browser), then try alternative approach.
When to Handoff
- CAPTCHA or bot detection blocking progress
- Multi-factor authentication requiring a physical device
- OAuth popup that redirects to a third-party login
- Any blocker after 2-3 failed attempts at the same step
- The server auto-suggests handoff after 3 consecutive failures (look for HINT in error messages)
When NOT to Handoff
- Normal navigation/interaction failures — retry or try a different selector
- Pages that just need more time to load — use
waitcommands - Cookie/auth issues — try
cookie-importorauth loginfirst
Handoff Rules
- NEVER run
browse handoffwithout asking the user first (Step 1) - NEVER proceed without waiting for the user to finish (Step 2)
- ALWAYS tell the user what they need to do in the visible browser
- ALWAYS run
browse resumeafter the user is done
Speed Rules
Read this section to optimize your command usage and minimize token consumption.
1. Navigate once, query many times. goto loads the page; then text, js, css, screenshot all run against the loaded page instantly. 2. Use `snapshot -i` for interaction. Get refs for all interactive elements, then click/fill by ref. No need to guess CSS selectors. 3. Use `snapshot -C` for SPAs. Catches cursor:pointer divs and onclick handlers that ARIA misses. 4. Use `js` for precision. js "document.querySelector('.price').textContent" is faster than parsing full page text. 5. Use `links` to survey. Faster than text when you just need navigation structure. 6. Use `chain` for multi-step flows. Avoids CLI overhead per step. 7. Use `responsive` for layout checks. One command = 3 viewport screenshots. 8. Use `--session` for parallel work. Multiple agents can browse simultaneously without interference. 9. Use `value`/`count` instead of `js`. Purpose-built commands are cleaner than js "document.querySelector(...).value". 10. Use `frame` for iframes. Don't try to reach into iframes with CSS — use frame [id=x] first.
When to Use What
Read this section when you're unsure which command to use for a task.
| Task | Commands |
|---|---|
| Read a page | goto <url> then text |
| Interact with elements | snapshot -i then click @e3 |
| Find hidden clickables | snapshot -i -C then click @e15 |
| Check if element exists | count ".thing" |
| Get input value | value "[id=email]" |
| Extract specific data | js "document.querySelector('.price').textContent" |
| Visual check | screenshot then Read .browse/sessions/default/screenshot.png |
| Fill and submit form | snapshot -i then fill @e4 "val" then click @e5 |
| Check/uncheck boxes | check @e7 / uncheck @e7 |
| Check CSS | css "selector" "property" or css @e3 "property" |
| Inspect DOM | html "selector" or attrs @e3 |
| Debug console errors | console |
| Check network requests | network |
| Mock API responses | route "**/api/*" fulfill 200 '{"data":[]}' |
| Block ads/trackers | route "**/*.doubleclick.net/*" block |
| Test offline behavior | offline on then test then offline off |
| Interact in iframe | frame "[id=payment]" then fill @e2 "4242..." then frame main |
| Check local dev | goto http://127.0.0.1:3000 |
| Compare two pages | diff <url1> <url2> |
| Mobile layout check | responsive .browse/sessions/default/resp |
| Test on mobile device | emulate iphone then goto <url> then screenshot |
| Save/restore session | state save mysite / state load mysite |
| Auto-login | auth save gh https://github.com/login user pass then auth login gh |
| Record network | har start then browse then har stop ./out.har |
| Record video | video start ./vids then browse then video stop |
| Export automation script | record start then browse then record export replay ./recording.json |
| Parallel agents | --session agent-a <cmd> / --session agent-b <cmd> |
| Multi-step flow | `echo '[...]' \ |
| Secure browsing | --allowed-domains example.com goto https://example.com |
| Scroll through results | scroll down then text then scroll down then text |
| Drag and drop | drag @e1 @e2 |
| Read/write clipboard | clipboard / clipboard write "text" |
| Find by accessibility | find role button / find text "Submit" |
| Visual regression | screenshot-diff baseline.png |
| Debug with DevTools | inspect (set BROWSE_DEBUG_PORT first) |
| Get element position | box @e3 |
| Check page errors | errors |
| Right-click context menu | rightclick @e3 |
| Test mobile gestures | emulate iphone then tap @e1 / swipe down |
| Set dark mode | set media dark |
| Test geolocation | set geo 37.7 -122.4 then verify in page |
| Export/import cookies | cookie export ./cookies.json / cookie import ./cookies.json |
| Limit output size | --max-output 5000 text |
| See the browser | browse --headed goto <url> |
| CAPTCHA / MFA blocker | handoff "reason" then user solves then resume (see Handoff Protocol above) |
| Debug React components | react-devtools enable then tree then props @e3 |
| Debug hydration issues | react-devtools enable then hydration |
| Find suspense blockers | react-devtools enable then suspense |
| Bypass bot detection | --runtime rebrowser goto <url> |
| Persistent login state | --profile mysite then browse then close then reopen (still logged in) |
| Cloud browser (CI/CD) | provider save browserbase <key> then --provider browserbase goto <url> |
Architecture
Read this section to understand the system design.
- Persistent Chromium daemon on localhost (port 9400-10400)
- Bearer token auth per session
- One server per project directory —
--sessionhandles agent isolation - Session multiplexing: multiple agents share one Chromium via isolated BrowserContexts
- For separate servers: set
BROWSE_INSTANCEenv var (e.g., fault isolation between teams) browse instances— discover all running servers (PID, port, status, session count)- Project-local state:
.browse/directory at project root (auto-created, self-gitignored) sessions/{id}/— per-session screenshots, logs, PDFsstates/{name}.json— saved browser state (cookies + localStorage)browse-server.json— server PID, port, auth token- Auto-shutdown when all sessions idle past 30 min
- Chromium crash — server exits — auto-restarts on next command
- AI-friendly error messages: Playwright errors rewritten to actionable hints
- CDP remote connection:
BROWSE_CDP_URLto connect to existing Chrome - Policy enforcement:
browse-policy.jsonfor allow/deny/confirm rules - Two browser engines: playwright (default) and rebrowser (stealth, bypasses bot detection)
browse — Permission Rules for Claude Code
Add these rules to .claude/settings.json under permissions.allow to pre-allow all browse commands. Merge with existing rules — do not overwrite.
"Bash(browse:*)",
"Bash(browse goto:*)", "Bash(browse back:*)", "Bash(browse forward:*)",
"Bash(browse reload:*)", "Bash(browse url:*)", "Bash(browse text:*)",
"Bash(browse html:*)", "Bash(browse links:*)", "Bash(browse forms:*)",
"Bash(browse accessibility:*)", "Bash(browse snapshot:*)",
"Bash(browse snapshot-diff:*)", "Bash(browse click:*)",
"Bash(browse dblclick:*)", "Bash(browse fill:*)", "Bash(browse select:*)",
"Bash(browse hover:*)", "Bash(browse focus:*)",
"Bash(browse check:*)", "Bash(browse uncheck:*)",
"Bash(browse type:*)", "Bash(browse press:*)",
"Bash(browse keydown:*)", "Bash(browse keyup:*)",
"Bash(browse scroll:*)", "Bash(browse wait:*)",
"Bash(browse viewport:*)", "Bash(browse upload:*)",
"Bash(browse drag:*)", "Bash(browse highlight:*)", "Bash(browse download:*)",
"Bash(browse dialog-accept:*)", "Bash(browse dialog-dismiss:*)",
"Bash(browse js:*)", "Bash(browse eval:*)", "Bash(browse css:*)",
"Bash(browse attrs:*)", "Bash(browse element-state:*)", "Bash(browse dialog:*)",
"Bash(browse console:*)", "Bash(browse network:*)",
"Bash(browse cookies:*)", "Bash(browse storage:*)", "Bash(browse perf:*)",
"Bash(browse value:*)", "Bash(browse count:*)",
"Bash(browse devices:*)", "Bash(browse emulate:*)",
"Bash(browse screenshot:*)", "Bash(browse pdf:*)",
"Bash(browse responsive:*)", "Bash(browse diff:*)",
"Bash(browse chain:*)", "Bash(browse tabs:*)", "Bash(browse tab:*)",
"Bash(browse newtab:*)", "Bash(browse closetab:*)",
"Bash(browse frame:*)",
"Bash(browse sessions:*)", "Bash(browse session-close:*)",
"Bash(browse state:*)", "Bash(browse auth:*)", "Bash(browse har:*)", "Bash(browse video:*)",
"Bash(browse record:*)",
"Bash(browse route:*)", "Bash(browse offline:*)",
"Bash(browse status:*)", "Bash(browse stop:*)", "Bash(browse restart:*)",
"Bash(browse cookie:*)", "Bash(browse header:*)",
"Bash(browse useragent:*)",
"Bash(browse clipboard:*)", "Bash(browse screenshot-diff:*)",
"Bash(browse find:*)", "Bash(browse inspect:*)",
"Bash(browse instances:*)", "Bash(browse --headed:*)",
"Bash(browse rightclick:*)", "Bash(browse tap:*)",
"Bash(browse swipe:*)", "Bash(browse mouse:*)",
"Bash(browse keyboard:*)", "Bash(browse scrollinto:*)",
"Bash(browse scrollintoview:*)", "Bash(browse set:*)",
"Bash(browse box:*)", "Bash(browse errors:*)",
"Bash(browse doctor:*)", "Bash(browse upgrade:*)",
"Bash(browse --max-output:*)",
"Bash(browse handoff:*)", "Bash(browse resume:*)",
"Bash(browse react-devtools:*)", "Bash(browse profile:*)",
"Bash(browse --chrome:*)", "Bash(browse provider:*)",
"Bash(browse cookie-import:*)", "Bash(browse cookie-export:*)"