← All guides
INTEGRATIONS · 5 MIN READ

Browserbase Custom Proxy Setup: Bring Your Own Route

Attach an external proxy to a Browserbase session, verify the browser path, and compare external routing with a built-in identity.

Browserbase gives you a remote browser, but the browser’s network identity is still part of your workload. If a job needs a particular country, an existing proxy contract or a route you can audit, configure the external proxy at the Browserbase session boundary and test the resulting page. A browser session that starts successfully is not proof that the destination saw the route you intended.

Decide who owns the route

Use Browserbase’s built-in identity when the session only needs a standard remote-browser connection and you do not need to select a separate supplier. Bring your own proxy when you need to control the network endpoint, keep route policy outside the browser application, or compare a proxy supplier against the default path. The Browserbase proxy documentation is the authority for the current configuration surface and any plan or product restrictions.

Keep the decision tied to a workload. Write down the target origin, region, session duration, request volume and success condition. “The page loaded” is too weak for a price observation or a localized QA check. A useful record includes the final URL, status, expected field count and the route identifier supplied by your own test endpoint.

Configure a session without putting credentials in page code

The current Browserbase proxy shape is an external proxy object in the session’s proxies array. Keep the server, username and password in server-side secrets. Stagehand can attach to the created session with browserbaseSessionID, while Browserbase owns the remote browser process.

import { Browserbase } from "@browserbasehq/sdk";
import { Stagehand } from "@browserbasehq/stagehand";

const apiKey = process.env.BROWSERBASE_API_KEY!;
const proxy = {
  type: "external" as const,
  server: process.env.PROXY_SERVER!,
  username: process.env.PROXY_USERNAME!,
  password: process.env.PROXY_PASSWORD!,
};

const bb = new Browserbase({ apiKey });
const session = await bb.sessions.create({ proxies: [proxy] });
const stagehand = new Stagehand({
  env: "BROWSERBASE",
  apiKey,
  browserbaseSessionID: session.id,
});

await stagehand.init();
try {
  const page = stagehand.context.pages()[0];
  if (!page) throw new Error("Browserbase session has no page");
  const response = await page.goto(
    process.env.ROUTE_CHECK_URL ?? "https://example.com/",
    { waitUntil: "domcontentloaded", timeoutMs: 20_000 },
  );
  const marker = process.env.EXPECTED_MARKER ?? "Example Domain";
  const body = await page.locator("body").innerText();
  const status = response?.status() ?? null;
  const validOutput = status !== null && status < 400 && body.includes(marker);

  console.log(JSON.stringify({
    sessionId: session.id,
    finalUrl: page.url(),
    status,
    validOutput,
  }));
  if (!validOutput) throw new Error("route-check output failed validation");
} finally {
  await stagehand.close();
}

The same proxy object can be passed through Browserbase’s documented session creation parameters when Stagehand creates the session itself. The important boundary is still the session: browserbaseSessionID attaches Stagehand to an existing Browserbase session, and proxies: [proxy] selects the external route. Keep the API key and proxy values out of browser code and logs.

Use a route-check page before the real job

Create a harmless endpoint you operate, or use an IP-check endpoint you explicitly trust. Make it return only the information needed for the check. Run one Browserbase session with the external proxy and one baseline session, then save the observations separately:

Observation What it proves What it does not prove
Session creation succeeds Browserbase accepted the request The proxy authenticated or the target permits it
Route-check response arrives The browser reached the check endpoint The target will return useful data
Expected region is observed The selected route produced that result at that time Locale, timezone, cookies and device match the region
Required record fields exist The workflow produced usable output Every page request used the same route

This separation keeps an origin block from looking like a Browserbase failure. A 401 or 403 from the destination is different from a proxy authentication failure. Record the phase that failed and remove credentials from error messages before storing them.

Keep resource blocking and request interception off for the route check, or hold the exact same rules in the baseline and external runs. A blocked script or XHR can remove the field you use to validate the result and make a healthy route look broken. Browserbase’s domain routing rules are a separate, ordered policy: record the matching domainPattern when a job uses them.

Browserbase versus an external proxy

The choice is easier when the two options are measured against one job. For a remote browser task that needs interaction, keep Browserbase as the browser layer and compare the default identity with your external route. For a fetch-and-parse job that does not need a browser, a direct HTTP client plus a proxy may have less session overhead. That is a workflow decision, not a claim that one product is universally cheaper or more reliable.

Do not use a proxy to bypass a destination’s access rules. Check the target’s terms, robots guidance where relevant, personal-data obligations and rate limits. A proxy controls a network path; it does not grant permission to collect or reuse a page.

A capacity and acceptance worksheet

Before you move a Browserbase job to production, fill these fields for one bounded sample and one expected peak:

target_origin: https://example.com
required_regions: <country or city list>
monthly_pages: <planned page loads>
peak_concurrency: <simultaneous sessions>
session_policy: <one session / new session per task>
estimated_transfer_gb: <measured GB for the sample, then forecast>
browser_minutes: <measured minutes>
external_proxy_cost: <supplier cost for the sample>
valid_tasks: <records passing the success condition>
cost_per_valid_task: <total cost / valid_tasks, if valid_tasks > 0>
capacity_evidence: <provider limit or measured ceiling>
sourcing_audit: <route ownership and supplier evidence>
abuse_controls: <rate and access controls>
sla_requirement: <required availability and response>
contract_status: <confirmed / open>
failure_phase: <session / proxy / TLS / target / parser>
next_action: <keep route / change scope / stop>

Empty capacity, sourcing or SLA fields remain unknown. A provider’s browser capability does not prove upstream proxy capacity, sourcing or an SLA. Include transfer, retries and manual debugging time in the comparison, and do not divide by zero when the sample has no valid tasks.

For context-specific browser configuration, see the Playwright proxy guide. If the Browserbase session returns a 407, use the proxy authentication guide and test the proxy host separately from the destination.

Sources and further reading

Sign in ↗

Keep reading

Amazon Scraper API vs Proxy: Choose a Product Data Source

Distinguish authorized Amazon APIs, licensed product data and proxy-based page checks by record quality and access rights.

Read guide →

Apify Custom Proxy Setup: Use Your Own Residential Route

Connect a buyer-owned proxy to an Apify Actor, keep the session boundary clear, and validate records instead of counting requests.

Read guide →

Australia Residential Proxies: Verify the AU Exit and State-Level Result

Separate Australian egress from en-AU content, AUD pricing, GST display, postcode validation and the state delivery context.

Read guide →