diff --git a/.changeset/browserbase-proxy-stealth.md b/.changeset/browserbase-proxy-stealth.md new file mode 100644 index 000000000..6d3a8087d --- /dev/null +++ b/.changeset/browserbase-proxy-stealth.md @@ -0,0 +1,13 @@ +--- +"agent-browser": patch +--- + +### New Features + +- **Browserbase proxy support** - Enable Browserbase's residential proxy via `BROWSERBASE_PROXY=1` environment variable to route traffic through residential IPs instead of datacenter IPs +- **Browserbase advanced stealth** - Enable advanced stealth mode via `BROWSERBASE_ADVANCED_STEALTH=1` and configure OS fingerprint via `BROWSERBASE_OS` (windows, mac, linux, mobile, tablet) +- **Image blocking for providers** - Block image loading to save proxy bandwidth via `BROWSERBASE_BLOCK_IMAGES=1` environment variable, using CDP Fetch interception to abort image requests (note: not recommended on sites with anti-bot protection) + +### Bug Fixes + +- **Browserbase session creation** - Fixed 415 "Unsupported Media Type" error when using `-p browserbase` by sending a JSON body with the session creation request (regression from #625) diff --git a/cli/src/native/actions.rs b/cli/src/native/actions.rs index bebffc207..272bdf7f7 100644 --- a/cli/src/native/actions.rs +++ b/cli/src/native/actions.rs @@ -1112,6 +1112,43 @@ async fn handle_launch(cmd: &Value, state: &mut DaemonState) -> Result = state + .routes + .iter() + .map(|r| json!({ "urlPattern": r.url_pattern })) + .collect(); + let _ = browser + .client + .send_command( + "Fetch.enable", + Some(json!({ "patterns": patterns })), + Some(session_id), + ) + .await; + } + } + } + return Ok(json!({ "launched": true, "provider": provider })); } Err(e) => { diff --git a/cli/src/native/providers.rs b/cli/src/native/providers.rs index d29703e55..3c5b444a1 100644 --- a/cli/src/native/providers.rs +++ b/cli/src/native/providers.rs @@ -88,10 +88,53 @@ async fn connect_browserbase() -> Result<(String, Option), Stri let api_key = env::var("BROWSERBASE_API_KEY") .map_err(|_| "BROWSERBASE_API_KEY environment variable is not set")?; + let mut session_body = json!({}); + let mut browser_settings = json!({}); + + // Enable Browserbase proxy when BROWSERBASE_PROXY=1 or BROWSERBASE_PROXY=true + if env::var("BROWSERBASE_PROXY") + .map(|v| v == "1" || v.eq_ignore_ascii_case("true")) + .unwrap_or(false) + { + session_body.as_object_mut().unwrap().insert( + "proxies".to_string(), + json!([{ "type": "browserbase" }]), + ); + } + + // Enable advanced stealth mode via BROWSERBASE_ADVANCED_STEALTH=1 + // Basic stealth is enabled by default on Browserbase; advanced uses a + // custom Chromium build that mimics human-like environmental signals. + if env::var("BROWSERBASE_ADVANCED_STEALTH") + .map(|v| v == "1" || v.eq_ignore_ascii_case("true")) + .unwrap_or(false) + { + browser_settings + .as_object_mut() + .unwrap() + .insert("advancedStealth".to_string(), json!(true)); + } + + // Set OS for stealth fingerprint via BROWSERBASE_OS (windows, mac, linux, mobile, tablet) + if let Ok(os) = env::var("BROWSERBASE_OS") { + browser_settings + .as_object_mut() + .unwrap() + .insert("os".to_string(), json!(os)); + } + + if browser_settings.as_object().map_or(false, |o| !o.is_empty()) { + session_body + .as_object_mut() + .unwrap() + .insert("browserSettings".to_string(), browser_settings); + } + let client = reqwest::Client::new(); let response = client .post("https://api.browserbase.com/v1/sessions") .header("X-BB-API-Key", &api_key) + .json(&session_body) .send() .await .map_err(|e| format!("Browserbase request failed: {}", e))?;