- Add new `extract_data` action that uses CSS selectors (querySelectorAll) to
extract structured data directly from the page without LLM cost. Supports
extracting text, href, src, or any HTML attribute from matching elements.
Returns structured JSON and optionally saves to CSV/JSONL/JSON files.
- Add `save_to_file` parameter to existing `extract` action so LLM-extracted
content can be written directly to a file instead of consuming context window
tokens. Enables accumulating data across multiple pages.
- Update both system prompts with a new `<data_extraction>` section that guides
the agent on when to use extract_data vs extract vs evaluate, and documents
the multi-page extraction pattern (extract → click Next → extract → repeat
with save_to_file appending to same file).
These changes address the core data extraction inefficiency where the agent was
forced to output all extracted tokens through the LLM, making bulk extraction
(100+ items, multi-page scraping) slow and expensive.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When evaluate or extract returns results longer than MAX_MEMORY_LENGTH,
the full data is placed in extracted_content (shown only once via
read_state) and long_term_memory gets a useless summary. This causes
the agent to lose access to the data in later steps and hallucinate
placeholder text like "JSON_STRING_FROM_STEP_6".
Increasing the threshold 10x means most real-world results will stay
in long_term_memory and persist across steps.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add 0-byte file check in upload_file handler to catch empty files early
with a clear error message instead of silently passing them to websites
- Add 0-byte file check in CDP upload watchdog before setFileInputFiles
to prevent uploading empty files that cause cascading failures
- Replace hardcoded text extension list in read_file_structured() with
dynamic derivation from _file_types, so new text-based file types
are automatically supported for external file reading
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
Updated all examples to use ChatBrowserUse(model='bu-2-0') so they run
against the current recommended model and produce consistent results. No
library code changes.
- **Refactors**
- Replaced ChatBrowserUse() with ChatBrowserUse(model='bu-2-0') across
example folders (browser, getting_started, features, integrations,
sandbox, use-cases).
- No API changes; examples remain runnable as before.
<sup>Written for commit 20f4f2a984.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
## Summary
This PR adds support for connecting to an existing browser instance via
Chrome DevTools Protocol (CDP) URL in the skill_cli commands.
## Why This Is Needed
The current `skill_cli` (used by `browser-use open`, `browser-use
state`, etc.) only supports three browser modes:
- `chromium`: Launches a new Playwright-managed Chromium
- `real`: Launches user's Chrome with their profile
- `remote`: Uses Browser-Use Cloud service
However, many use cases require connecting to an **already-running
browser**:
1. **Remote browser automation via SSH tunnels** - A server running
Claude Code can control a local browser on a developer's machine through
SSH RemoteForward (e.g., `RemoteForward 9222 127.0.0.1:9222`)
2. **Docker integration** - Connecting to browsers running in containers
3. **Reusing authenticated sessions** - Connect to a browser where the
user is already logged into services
4. **Headless CI/CD pipelines** - Connect to pre-configured browser
instances
The `BrowserSession` class already supports `cdp_url` parameter, and the
TUI mode (`browser-use-tui --cdp-url`) exposes it. However, the simple
CLI commands (`browser-use open`, `browser-use state`, `browser-use
click`, etc.) did not have this capability.
## Changes
| File | Change |
|------|--------|
| `skill_cli/main.py` | Added `--cdp-url` argument, pass through to
`ensure_server()` and server command |
| `skill_cli/server.py` | Accept `--cdp-url` arg, store in
`SessionServer`, pass to registry |
| `skill_cli/sessions.py` | Added `cdp_url` parameter to `SessionInfo`,
`get_or_create()`, and `create_browser_session()`. CDP URL takes
precedence over other modes |
## Usage
```bash
# Start Chrome with remote debugging on your machine
chrome --remote-debugging-port=9222
# Now use browser-use CLI to control it
browser-use --cdp-url http://localhost:9222 open https://example.com
browser-use --cdp-url http://localhost:9222 state
browser-use --cdp-url http://localhost:9222 click 5
browser-use --cdp-url http://localhost:9222 screenshot /tmp/screen.png
```
### Remote Server Example (SSH Tunnel)
```bash
# On your local machine - start Chrome with remote debugging
chrome --remote-debugging-port=9222
# SSH config with RemoteForward
# Host myserver
# RemoteForward 9222 127.0.0.1:9222
# On the remote server
browser-use --cdp-url http://localhost:9222 open https://github.com
```
## Testing
Tested with Chrome remote debugging over SSH tunnel:
- Successfully controlled a local macOS Chrome browser from a remote
Linux server
- Verified: `open`, `state`, `click`, `screenshot` commands all work
correctly
- The browser on the local machine responds to commands issued from the
remote server
## Notes
- Vibe coded with Claude Opus 4.5
- ~15 lines of code change across 3 files
- CDP URL takes precedence over `--browser` mode when both are specified
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Add a --cdp-url flag to skill_cli to connect to an already-running
browser via Chrome DevTools Protocol. This enables remote and
containerized automation and reusing authenticated sessions; cdp_url
overrides the browser mode and defaults the session to cdp-default to
avoid conflicts.
- **New Features**
- Added --cdp-url to browser-use CLI and passed it through the server to
session creation.
- Session creation uses cdp_url when present, taking precedence over
chromium/real/remote.
- When --cdp-url is set and session is "default", use "cdp-default" to
avoid reusing an incompatible session.
- **Migration**
- Start a browser with remote debugging (e.g., Chrome
--remote-debugging-port=9222).
- Use: browser-use --cdp-url http://localhost:9222 <command>
<sup>Written for commit 7a32885644.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
## Summary
- Add Installation section with `uvx`/`uv pip` commands and `browser-use
install`
- Add API Key Configuration section explaining resolution order (flag →
env var → config file)
- Document CLI aliases (`bu`, `browser`, `browseruse`)
- Add `browser-use install` to Setup commands and Troubleshooting
The SKILL.md was missing critical information for users who don't have
the CLI installed - they had no way to know how to install it or
configure API keys.
## Test plan
- [x] Verify SKILL.md renders correctly
- [ ] Confirm installation commands work as documented
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Added installation steps and API key setup to SKILL.md so new users can
install the browser-use CLI and configure keys quickly. Documented
uvx/uv pip commands, the browser-use install command for Chromium
dependencies, API key resolution order (flag → env var → config file),
CLI aliases, and updates to Setup and Troubleshooting.
<sup>Written for commit 5682268a03.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
## Summary
- Increased default `step_timeout` from 120s (2 min) to 180s (3 min)
## Motivation
Production data analysis (BU2, last 24h) revealed:
- **36.5% of consecutive failures** are `AsyncIO CancelledError` in
`get_browser_state_summary`
- Complex pages can take 30-60s for DOM extraction + 30-60s for LLM call
+ action execution
- The 120s default was too tight for complex pages or slow network
conditions
## Analysis
| Metric | Value |
|--------|-------|
| Tasks with browser state timeout | 81 (36.5% of failures) |
| Median timeout duration | 5.06 min |
| Time per step (timeout tasks) | 13.0s median |
| Time per step (success tasks) | 6.0s median |
The step timeout wraps the entire step: browser state retrieval + LLM
call + action execution. 180s provides ~50% more buffer while still
catching genuinely stuck steps.
## Test plan
- [ ] Verify step timeout behavior
- [ ] Monitor timeout rates in production
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Low risk: a single default parameter change that only affects how long
a step can run before timing out, potentially increasing worst-case step
latency but not changing core logic.
>
> **Overview**
> Raises the default `step_timeout` in `Agent` initialization from 120s
to 180s, giving each step more time for browser-state retrieval, LLM
calls, and action execution before a timeout is raised.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
3c927b4f9b. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Increased the default per-step timeout from 120s (2 min) to 180s (3 min)
to reduce CancelledError timeouts on complex pages and slow networks.
This gives more time for browser state retrieval, LLM calls, and action
execution while keeping the total task timeout unchanged.
<sup>Written for commit 3c927b4f9b.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
## Summary
- Increased default LLM timeout from 45s to 75s for gemini models
(non-3-pro)
- Added explicit 75s timeout for browser-use models
## Motivation
Production data analysis (last 24h) revealed:
- **gemini-3-pro-preview**: 48% timeout rate with median 23s/step for
timeouts vs 19s/step for success (only 21% slower)
- **browser-use-2.0**: Timeout tasks have 74% slower time per step
(10.7s vs 6.0s median)
- Most timeouts occur on steps 11-20 where tasks are actively making
progress
The 45s default was too aggressive for these models. 75s provides ~3x
the median step time as buffer while still catching genuinely stuck
tasks.
## Test plan
- [ ] Verify timeout behavior with gemini models
- [ ] Verify timeout behavior with browser-use models
- [ ] Monitor timeout rates in production
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Low risk: only adjusts default per-step LLM call timeouts, which may
increase worst-case latency but doesn’t change core agent logic or
security-sensitive behavior.
>
> **Overview**
> Increases the auto-selected `llm_timeout` in `Agent` when not
explicitly provided: Gemini models (non `3-pro`) now use 75s instead of
45s, and the generic default fallback is raised from 60s to 75s
(affecting models not matched by the other heuristics, including
browser-use fine-tuned models).
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
40336731d5. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Increased LLM step timeout to 75s for Gemini (non‑3‑pro) and raised the
generic default timeout to 75s to reduce false timeouts during active
progress. Gemini 3‑pro stays at 90s; Groq remains 30s;
Claude/Sonnet/Deepseek remain 90s. This also applies to Browser‑Use and
other models using the default.
- **Bug Fixes**
- Set Gemini (non‑3‑pro) timeout from 45s to 75s.
- Raised generic default timeout from 60s to 75s (affects Browser‑Use
and other unmatched models).
- Rationale: production data showed high timeouts on active steps (e.g.,
Gemini median 23s/step; Browser‑Use timeouts 74% slower).
<sup>Written for commit 40336731d5.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
Production data analysis (24h) shows:
- 36.5% of consecutive failures are AsyncIO CancelledError in browser state retrieval
- Complex pages can take 30-60s for DOM extraction + 30-60s for LLM call
- 120s was too tight for complex pages with slow network
180s (3 min) gives ~50% more buffer while still catching stuck steps.
This is the per-step timeout, not the total task timeout.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Based on production data analysis showing:
- gemini-3-pro-preview has 48% timeout rate with median 23s/step
- browser-use-2.0 timeout tasks have 74% slower time per step (10.7s vs 6.0s)
- Most timeouts occur on steps 11-20 where tasks are making progress
The 45s default was too aggressive. 75s provides ~3x the median step time
as buffer while still catching genuinely stuck tasks.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The SKILL.md was missing critical information for users who don't have
the CLI installed. Added:
- Installation section with uvx/uv pip commands
- browser-use install command for Chromium dependencies
- API key configuration section (env var, config file, flag)
- CLI aliases (bu, browser, browseruse)
- install command in troubleshooting
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
Bumped browser-use version from 0.11.4 to 0.11.5 in pyproject.toml to
publish the latest patch.
<sup>Written for commit 93fd57258e.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
Continuation of
[#3801](https://github.com/browser-use/browser-use/pull/3801) by
@Mr-Neutr0n - removed test and resolved lint. Resolves
[#3726](https://github.com/browser-use/browser-use/issues/3726) and
[#3865](https://github.com/browser-use/browser-use/issues/3865).
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Stop sending screenshots to the judge LLM when use_vision=False to
prevent sensitive data leakage. Resolves#3726 and #3865.
- **Bug Fixes**
- Added use_vision param to construct_judge_messages() and respected it.
- Skipped screenshot selection/encoding when use_vision is False.
- Passed settings.use_vision from _judge_trace() to
construct_judge_messages(); True/'auto' still include images.
<sup>Written for commit b00ffd5380.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
Adds the bu-2-0 premium model with explicit pricing and SDK support. You
can now select it via llm.bu_2_0 or ChatBrowserUse(model='bu-2-0').
- New Features
- Added bu-2-0 pricing (input/output/cache) to CUSTOM_MODEL_PRICING.
- Exposed bu_2_0 in browser_use.llm.models and listed it in
ChatBrowserUse options.
- Updated example to use bu-2-0; corrected bu-1-0 pricing comments.
<sup>Written for commit c011c529fc.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
This prevents conflicts when switching between browser modes. Session parameters
(browser mode, cdp_url, etc.) are set at creation time and cannot be changed.
Without this fix, an existing 'default' session using chromium mode would be
silently reused when the user specifies --cdp-url, causing the CDP connection
to be ignored.
The same issue would occur switching between any browser modes (e.g., --browser
chromium to --browser real), but CDP is the most common case where users expect
to connect to a specific existing browser instance.
The session remap is placed early in main() before any command handling (server,
sessions, close --all) so those commands also target the correct session.
Users can still override with explicit --session flag if needed.
Continuation of
[#3896](https://github.com/browser-use/browser-use/pull/3896) by
@Jacky040124 - condensed comments to match codebase style. Resolves
#3889.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes Draft.js editors dropping the first typed character. Detects
Draft.js (class includes DraftEditor or
data-contents/data-block/data-offset-key) and prepends a sacrificial
space only when the input is cleared first, so the space is consumed and
the intended text is preserved.
<sup>Written for commit c62ceafa25.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
Set Gemini thinking to auto by default. Align thinking config per model
(Gemini 3 Pro, 3 Flash, 2.5) for better defaults and fewer
misconfigurations.
- **Refactors**
- Gemini 3 Pro: uses thinking_level only, defaults to low; warns on
thinking_budget and on minimal/medium.
- Gemini 3 Flash: supports both; uses thinking_level if set, else
thinking_budget = -1.
- Gemini 2.5: uses thinking_budget only, default -1; warns if
thinking_level is set.
- Example: simplified ChatBrowserUse usage by removing explicit model.
<sup>Written for commit ee35b53b12.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
## Summary
* Fixes `dropdown_options` failing on ARIA combobox elements with
dynamically rendered options.
* Adds proper handling for `aria-controls`-linked listboxes and expands
collapsed comboboxes before extraction.
## Changes
### Updated handler in `default_action_watchdog.py`:
* Detects `role="combobox"` with `aria-controls`.
* Expands the combobox via dispatched focus/click events.
* Waits briefly for dynamic options to render.
* Resolves the listbox by `aria-controls` and extracts
`[role="option"]`.
* Returns structured results consistent with existing dropdown output.
Addresses issue #3694
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes dropdown option extraction for ARIA comboboxes with dynamic menus
by expanding the control and reading options from its aria-controls
listbox. Resolves#3694 and restores reliable dropdown_options behavior
for ARIA patterns.
- **Bug Fixes**
- Detect role="combobox" with aria-controls and use a dedicated handler.
- Expand collapsed comboboxes (focus/click/mousedown) and wait for
dynamic options.
- Read options from the controlled listbox ([role="option"], with li
fallback), return consistent output, then collapse.
- Keep generic dropdown logic scoped to menu/listbox (combobox handled
separately).
- Clear error messages and logging when listbox or options are missing.
<sup>Written for commit 7cf8575e4a.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
Always index scrollable dropdown containers so they can be targeted by
select_dropdown, even when they contain interactive descendants.
Addresses #3538.
- **Bug Fixes**
- Detect dropdowns by role (listbox, menu, combobox, menubar, tree,
grid), tag (select), or common classes (dropdown, dropdown-menu,
select-menu, Semantic UI “ui dropdown”).
- Leave other scrollable elements unchanged: only indexed when they have
no interactive descendants.
<sup>Written for commit 7bacbbbfa2.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
Resolves#2867.
The select_dropdown action was claiming success even when frameworks
like Wix intercepted and reverted the programmatic selection. The agent
would report task completion, but the dropdown value remained unchanged.
- Added verification after setting selection - checks if `element.value
=== expectedValue`
- If framework reverted the value, try click-based fallback (mousedown
-> selectedIndex -> click option -> mouseup -> change)
- If both methods fail, properly report the error instead of claiming
success
- Agent can then recover by clicking visible option elements directly
Only affects native `<select>` elements in
`on_SelectDropdownOptionEvent`. ARIA/custom dropdowns already use
click-based selection.
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes dropdown selection reliability by verifying the final value and
retrying with a click-based fallback when frameworks revert programmatic
changes. Aligns with #2867 so the agent no longer claims success when
the value doesn’t stick.
- **Bug Fixes**
- Verify selection after setting (element.value === expectedValue).
- If reverted, use click-based fallback (focus, mousedown, set
selectedIndex, click option, mouseup, change, blur).
- If both methods fail, return a clear error so the agent can recover.
- Provide target option and available options when a revert is detected
to aid recovery.
- Scope: affects native <select> in on_SelectDropdownOptionEvent;
ARIA/custom dropdowns unchanged.
<sup>Written for commit 6f8c077932.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated description by cubic. -->
## Summary by cubic
Removed the duplicate --headed flag from the open subcommand so the
global --headed option is respected. Fixes the parsing bug tracked in
issue #3931.
- **Bug Fixes**
- Removed the open subcommand’s --headed arg that was shadowing the
global flag.
- Added tests to verify --headed works before subcommands, with
--session and --browser, and defaults to False.
<sup>Written for commit acd05e30e0.
Summary will update on new commits.</sup>
<!-- End of auto-generated description by cubic. -->