feat: Add browserless.io as a browser provider (#502)

* feat: Add browserless as a hosted option + boolean env-parsing utility

* Add ensureDomainFilter, sanitizeExistingPage and move parseBooleanParam

* Add docs in relevant places, fix utils, rename of API env var

* Update readme

* Fix env variable name in readme

* Cleanup session stop urls when errors happen

* Fix browserlessStopUrl not being assigned in happy path
This commit is contained in:
Joel Griffith
2026-03-13 00:45:02 -05:00
committed by GitHub
parent fb7185d860
commit b9a24df40f
6 changed files with 279 additions and 74 deletions
+112 -56
View File
@@ -165,6 +165,7 @@ agent-browser find nth <n> <sel> <action> [value] # Nth match
**Options:** `--name <name>` (filter role by accessible name), `--exact` (require exact text match)
**Examples:**
```bash
agent-browser find role button click --name "Submit"
agent-browser find text "Sign In" click
@@ -375,6 +376,7 @@ agent-browser session
```
Each session has its own:
- Browser instance
- Cookies and storage
- Navigation history
@@ -396,6 +398,7 @@ AGENT_BROWSER_PROFILE=~/.myapp-profile agent-browser open myapp.com
```
The profile directory stores:
- Cookies and localStorage
- IndexedDB data
- Service workers
@@ -432,10 +435,10 @@ export AGENT_BROWSER_ENCRYPTION_KEY=<64-char-hex-key>
agent-browser --session-name secure open example.com
```
| Variable | Description |
|----------|-------------|
| `AGENT_BROWSER_SESSION_NAME` | Auto-save/load state persistence name |
| `AGENT_BROWSER_ENCRYPTION_KEY` | 64-char hex key for AES-256-GCM encryption |
| Variable | Description |
| --------------------------------- | -------------------------------------------------- |
| `AGENT_BROWSER_SESSION_NAME` | Auto-save/load state persistence name |
| `AGENT_BROWSER_ENCRYPTION_KEY` | 64-char hex key for AES-256-GCM encryption |
| `AGENT_BROWSER_STATE_EXPIRE_DAYS` | Auto-delete states older than N days (default: 30) |
## Security
@@ -449,14 +452,14 @@ agent-browser includes security features for safe AI agent deployments. All feat
- **Action Confirmation** -- Require explicit approval for sensitive action categories: `--confirm-actions eval,download`
- **Output Length Limits** -- Prevent context flooding: `--max-output 50000`
| Variable | Description |
|----------|-------------|
| `AGENT_BROWSER_CONTENT_BOUNDARIES` | Wrap page output in boundary markers |
| `AGENT_BROWSER_MAX_OUTPUT` | Max characters for page output |
| `AGENT_BROWSER_ALLOWED_DOMAINS` | Comma-separated allowed domain patterns |
| `AGENT_BROWSER_ACTION_POLICY` | Path to action policy JSON file |
| `AGENT_BROWSER_CONFIRM_ACTIONS` | Action categories requiring confirmation |
| `AGENT_BROWSER_CONFIRM_INTERACTIVE` | Enable interactive confirmation prompts |
| Variable | Description |
| ----------------------------------- | ---------------------------------------- |
| `AGENT_BROWSER_CONTENT_BOUNDARIES` | Wrap page output in boundary markers |
| `AGENT_BROWSER_MAX_OUTPUT` | Max characters for page output |
| `AGENT_BROWSER_ALLOWED_DOMAINS` | Comma-separated allowed domain patterns |
| `AGENT_BROWSER_ACTION_POLICY` | Path to action policy JSON file |
| `AGENT_BROWSER_CONFIRM_ACTIONS` | Action categories requiring confirmation |
| `AGENT_BROWSER_CONFIRM_INTERACTIVE` | Enable interactive confirmation prompts |
See [Security documentation](https://agent-browser.dev/security) for details.
@@ -474,13 +477,13 @@ agent-browser snapshot -s "#main" # Scope to CSS selector
agent-browser snapshot -i -c -d 5 # Combine options
```
| Option | Description |
|--------|-------------|
| `-i, --interactive` | Only show interactive elements (buttons, links, inputs) |
| `-C, --cursor` | Include cursor-interactive elements (cursor:pointer, onclick, tabindex) |
| `-c, --compact` | Remove empty structural elements |
| `-d, --depth <n>` | Limit tree depth |
| `-s, --selector <sel>` | Scope to CSS selector |
| Option | Description |
| ---------------------- | ----------------------------------------------------------------------- |
| `-i, --interactive` | Only show interactive elements (buttons, links, inputs) |
| `-C, --cursor` | Include cursor-interactive elements (cursor:pointer, onclick, tabindex) |
| `-c, --compact` | Remove empty structural elements |
| `-d, --depth <n>` | Limit tree depth |
| `-s, --selector <sel>` | Scope to CSS selector |
The `-C` flag is useful for modern web apps that use custom clickable elements (divs, spans) instead of standard buttons/links.
@@ -596,8 +599,8 @@ export AGENT_BROWSER_DEFAULT_TIMEOUT=45000
> **Note:** Setting this above 30000 (30s) may cause EAGAIN errors on slow operations because the CLI's read timeout will expire before Playwright responds. The CLI retries transient errors automatically, but response times will increase.
| Variable | Description |
|----------|-------------|
| Variable | Description |
| ------------------------------- | ------------------------------------------------- |
| `AGENT_BROWSER_DEFAULT_TIMEOUT` | Default Playwright timeout in ms (default: 25000) |
## Selectors
@@ -623,6 +626,7 @@ agent-browser hover @e4 # Hover the link
```
**Why use refs?**
- **Deterministic**: Ref points to exact element from snapshot
- **Fast**: No DOM re-query needed
- **AI-friendly**: Snapshot + ref workflow is optimal for LLMs
@@ -723,6 +727,7 @@ agent-browser open other-site.com
```
This is useful for:
- **Skipping login flows** - Authenticate via headers instead of UI
- **Switching users** - Start new sessions with different auth tokens
- **API testing** - Access protected endpoints directly
@@ -744,6 +749,7 @@ agent-browser set headers '{"X-Custom-Header": "value"}'
## Custom Browser Executable
Use a custom browser executable instead of the bundled Chromium. This is useful for:
- **Serverless deployment**: Use lightweight Chromium builds like `@sparticuz/chromium` (~50MB vs ~684MB)
- **System browsers**: Use an existing Chrome/Chromium installation
- **Custom builds**: Use modified browser builds
@@ -804,6 +810,7 @@ agent-browser screenshot report.png
```
The `--allow-file-access` flag adds Chromium flags (`--allow-file-access-from-files`, `--allow-file-access`) that allow `file://` URLs to:
- Load and render local files
- Access other local files via JavaScript (XHR, fetch)
- Load local resources (images, scripts, stylesheets)
@@ -831,10 +838,12 @@ agent-browser --cdp "wss://your-browser-service.com/cdp?token=..." snapshot
```
The `--cdp` flag accepts either:
- A port number (e.g., `9222`) for local connections via `http://localhost:{port}`
- A full WebSocket URL (e.g., `wss://...` or `ws://...`) for remote browser services
This enables control of:
- Electron apps
- Chrome/Chromium instances with remote debugging
- WebView2 applications
@@ -854,10 +863,12 @@ AGENT_BROWSER_AUTO_CONNECT=1 agent-browser snapshot
```
Auto-connect discovers Chrome by:
1. Reading Chrome's `DevToolsActivePort` file from the default user data directory
2. Falling back to probing common debugging ports (9222, 9229)
This is useful when:
- Chrome 144+ has remote debugging enabled via `chrome://inspect/#remote-debugging` (which uses a dynamic port)
- You want a zero-configuration connection to your existing browser
- You don't want to track which port Chrome is using
@@ -881,6 +892,7 @@ This starts a WebSocket server on the specified port that streams the browser vi
Connect to `ws://localhost:9223` to receive frames and send input:
**Receive frames:**
```json
{
"type": "frame",
@@ -897,6 +909,7 @@ Connect to `ws://localhost:9223` to receive frames and send input:
```
**Send mouse events:**
```json
{
"type": "input_mouse",
@@ -909,6 +922,7 @@ Connect to `ws://localhost:9223` to receive frames and send input:
```
**Send keyboard events:**
```json
{
"type": "input_keyboard",
@@ -919,6 +933,7 @@ Connect to `ws://localhost:9223` to receive frames and send input:
```
**Send touch events:**
```json
{
"type": "input_touch",
@@ -939,16 +954,19 @@ await browser.launch({ headless: true });
await browser.navigate('https://example.com');
// Start screencast
await browser.startScreencast((frame) => {
// frame.data is base64-encoded image
// frame.metadata contains viewport info
console.log('Frame received:', frame.metadata.deviceWidth, 'x', frame.metadata.deviceHeight);
}, {
format: 'jpeg',
quality: 80,
maxWidth: 1280,
maxHeight: 720,
});
await browser.startScreencast(
(frame) => {
// frame.data is base64-encoded image
// frame.metadata contains viewport info
console.log('Frame received:', frame.metadata.deviceWidth, 'x', frame.metadata.deviceHeight);
},
{
format: 'jpeg',
quality: 80,
maxWidth: 1280,
maxHeight: 720,
}
);
// Inject mouse events
await browser.injectMouseEvent({
@@ -1000,18 +1018,18 @@ agent-browser open example.com
Or add to your config file (`agent-browser.json`):
```json
{"native": true}
{ "native": true }
```
### What's Different
| | Default (Node.js) | Native (`--native`) |
|---|---|---|
| **Runtime** | Node.js + Playwright | Pure Rust binary |
| **Protocol** | Playwright protocol | Direct CDP / WebDriver |
| **Install size** | Larger (Node.js + npm deps) | Smaller (single binary) |
| **Browser support** | Chromium, Firefox, WebKit | Chromium, Safari (via WebDriver) |
| **Stability** | Stable | Experimental |
| | Default (Node.js) | Native (`--native`) |
| ------------------- | --------------------------- | -------------------------------- |
| **Runtime** | Node.js + Playwright | Pure Rust binary |
| **Protocol** | Playwright protocol | Direct CDP / WebDriver |
| **Install size** | Larger (Node.js + npm deps) | Smaller (single binary) |
| **Browser support** | Chromium, Firefox, WebKit | Chromium, Safari (via WebDriver) |
| **Stability** | Stable | Experimental |
### Known Limitations
@@ -1021,13 +1039,13 @@ Or add to your config file (`agent-browser.json`):
## Platforms
| Platform | Binary | Fallback |
|----------|--------|----------|
| macOS ARM64 | Native Rust | Node.js |
| macOS x64 | Native Rust | Node.js |
| Linux ARM64 | Native Rust | Node.js |
| Linux x64 | Native Rust | Node.js |
| Windows x64 | Native Rust | Node.js |
| Platform | Binary | Fallback |
| ----------- | ----------- | -------- |
| macOS ARM64 | Native Rust | Node.js |
| macOS x64 | Native Rust | Node.js |
| Linux ARM64 | Native Rust | Node.js |
| Linux x64 | Native Rust | Node.js |
| Windows x64 | Native Rust | Node.js |
## Usage with AI Agents
@@ -1071,6 +1089,7 @@ For more consistent results, add to your project or global instructions file:
Use `agent-browser` for web automation. Run `agent-browser --help` for all commands.
Core workflow:
1. `agent-browser open <url>` - Navigate to page
2. `agent-browser snapshot -i` - Get interactive elements with refs (@e1, @e2)
3. `agent-browser click @e1` / `fill @e2 "text"` - Interact using refs
@@ -1122,11 +1141,11 @@ export AGENT_BROWSER_IOS_DEVICE="iPhone 16 Pro"
agent-browser open https://example.com
```
| Variable | Description |
|----------|-------------|
| `AGENT_BROWSER_PROVIDER` | Set to `ios` to enable iOS mode |
| Variable | Description |
| -------------------------- | ----------------------------------------------- |
| `AGENT_BROWSER_PROVIDER` | Set to `ios` to enable iOS mode |
| `AGENT_BROWSER_IOS_DEVICE` | Device name (e.g., "iPhone 16 Pro", "iPad Pro") |
| `AGENT_BROWSER_IOS_UDID` | Device UDID (alternative to device name) |
| `AGENT_BROWSER_IOS_UDID` | Device UDID (alternative to device name) |
**Supported devices:** All iOS Simulators available in Xcode (iPhones, iPads), plus real iOS devices.
@@ -1137,6 +1156,7 @@ agent-browser open https://example.com
Appium also supports real iOS devices connected via USB. This requires additional one-time setup:
**1. Get your device UDID:**
```bash
xcrun xctrace list devices
# or
@@ -1144,6 +1164,7 @@ system_profiler SPUSBDataType | grep -A 5 "iPhone\|iPad"
```
**2. Sign WebDriverAgent (one-time):**
```bash
# Open the WebDriverAgent Xcode project
cd ~/.appium/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent
@@ -1151,12 +1172,14 @@ open WebDriverAgent.xcodeproj
```
In Xcode:
- Select the `WebDriverAgentRunner` target
- Go to Signing & Capabilities
- Select your Team (requires Apple Developer account, free tier works)
- Let Xcode manage signing automatically
**3. Use with agent-browser:**
```bash
# Connect device via USB, then:
agent-browser -p ios --device "<DEVICE_UDID>" open https://example.com
@@ -1166,11 +1189,44 @@ agent-browser -p ios --device "John's iPhone" open https://example.com
```
**Real device notes:**
- First run installs WebDriverAgent to the device (may require Trust prompt)
- Device must be unlocked and connected via USB
- Slightly slower initial connection than simulator
- Tests against real Safari performance and behavior
### Browserless
[Browserless](https://browserless.io) provides cloud browser infrastructure with a Sessions API. Use it when running agent-browser in environments where a local browser isn't available.
To enable Browserless, use the `-p` flag:
```bash
export BROWSERLESS_API_KEY="your-api-token"
agent-browser -p browserless open https://example.com
```
Or use environment variables for CI/scripts:
```bash
export AGENT_BROWSER_PROVIDER=browserless
export BROWSERLESS_API_KEY="your-api-token"
agent-browser open https://example.com
```
Optional configuration via environment variables:
| Variable | Description | Default |
| -------------------------- | ------------------------------------------------ | --------------------------------------- |
| `BROWSERLESS_API_URL` | Base API URL (for custom regions or self-hosted) | `https://production-sfo.browserless.io` |
| `BROWSERLESS_BROWSER_TYPE` | Type of browser to use (chromium or chrome) | chromium |
| `BROWSERLESS_TTL` | Session TTL in milliseconds | `300000` |
| `BROWSERLESS_STEALTH` | Enable stealth mode (`true`/`false`) | `true` |
When enabled, agent-browser connects to a Browserless cloud session instead of launching a local browser. All commands work identically.
Get your API token from the [Browserless Dashboard](https://browserless.io).
### Browserbase
[Browserbase](https://browserbase.com) provides remote browser infrastructure to make deployment of agentic browsing agents easy. Use it when running the agent-browser CLI in an environment where a local browser isn't feasible.
@@ -1238,12 +1294,12 @@ agent-browser open https://example.com
Optional configuration via environment variables:
| Variable | Description | Default |
|----------|-------------|---------|
| `KERNEL_HEADLESS` | Run browser in headless mode (`true`/`false`) | `false` |
| `KERNEL_STEALTH` | Enable stealth mode to avoid bot detection (`true`/`false`) | `true` |
| `KERNEL_TIMEOUT_SECONDS` | Session timeout in seconds | `300` |
| `KERNEL_PROFILE_NAME` | Browser profile name for persistent cookies/logins (created if it doesn't exist) | (none) |
| Variable | Description | Default |
| ------------------------ | -------------------------------------------------------------------------------- | ------- |
| `KERNEL_HEADLESS` | Run browser in headless mode (`true`/`false`) | `false` |
| `KERNEL_STEALTH` | Enable stealth mode to avoid bot detection (`true`/`false`) | `true` |
| `KERNEL_TIMEOUT_SECONDS` | Session timeout in seconds | `300` |
| `KERNEL_PROFILE_NAME` | Browser profile name for persistent cookies/logins (created if it doesn't exist) | (none) |
When enabled, agent-browser connects to a Kernel cloud session instead of launching a local browser. All commands work identically.