Skip to content

Conversation

@miguelg719
Copy link
Collaborator

@miguelg719 miguelg719 commented Feb 9, 2026

why

Server-side multi-region support enabled for all Browserbase regions:

  • us-west-2 (default)
  • us-east-1
  • eu-central-1
  • ap-southeast-1

what changed

Added multi-region routing to the Stagehand API client so requests use the endpoint that matches the Browserbase session’s region. Updates OpenAPI and docs, adds tests, and fixes STAGEHAND_API_URL handling.

New Features

  • Route API calls by session region via REGION_API_URLS/getApiUrlForRegion; supports us‑west‑2 (default), us‑east‑1, eu‑central‑1, ap‑southeast‑1.
  • Store the session region in the client; remove the non–us‑west‑2 restriction.
  • Add BrowserbaseRegion schema/type; unit tests for region→URL and /v1 suffix; integration tests verify non‑default regions return available: true.
    • OpenAPI adds regional servers and shared BrowserbaseRegion schema.
  • Docs: add region/endpoint table, setup examples, mismatch error guidance, and the disableAPI option.

Bug Fixes

  • Ensure STAGEHAND_API_URL resolves to exactly one /v1.
  • Update SDK error messages to reference disableAPI.
  • Fix OpenAPI table rendering by removing blank lines between markdown table rows.

test plan


Summary by cubic

Enable multi-region routing in the Stagehand API client so requests hit the endpoint that matches the Browserbase session’s region. Updates v3 OpenAPI/docs, adds tests, and normalizes STAGEHAND_API_URL; v2 docs updates remain reverted.

  • New Features

    • Route API calls by session region; supports us-west-2 (default), us-east-1, eu-central-1, ap-southeast-1; removed the non–us-west-2 restriction.
    • Add BrowserbaseRegion schema/type and regional OpenAPI servers; v3 docs include region table, mismatch guidance, and disableAPI examples.
    • Tests validate region→URL mapping and that non‑default regions return available: true.
  • Bug Fixes

    • Normalize STAGEHAND_API_URL to include exactly one /v1; update SDK errors to reference disableAPI.
    • Fix OpenAPI docs rendering: use literal scalar for description, quote version fields, and clean table formatting.
    • Harden tests with try/finally to avoid session leaks; remove unused env scaffolding.

Written for commit 03a98c1. Summary will update on new commits. Review in cubic

# why

# what changed

# test plan

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Add multi-region routing to the Stagehand API client so requests use the
endpoint that matches the Browserbase session’s region. Updates OpenAPI
and docs (v2 and v3), adds tests, and fixes STAGEHAND_API_URL handling.

- **New Features**
- Route API calls by session region via
REGION_API_URLS/getApiUrlForRegion; supports us‑west‑2 (default),
us‑east‑1, eu‑central‑1, ap‑southeast‑1.
- Store the session region in the client; remove the non–us‑west‑2
restriction.
- Add BrowserbaseRegion schema/type; unit tests for region→URL and /v1
suffix; integration tests verify non‑default regions return available:
true.
  - OpenAPI adds regional servers and shared BrowserbaseRegion schema.
- Docs (v2 and v3) add region/endpoint table, setup examples, mismatch
error guidance, and the disableAPI option.

- **Bug Fixes**
  - Ensure STAGEHAND_API_URL resolves to exactly one /v1.
  - Update SDK error messages to reference disableAPI.
- Fix OpenAPI table rendering by removing blank lines between markdown
table rows.

<sup>Written for commit 77db79a.
Summary will update on new commits. <a
href="https://cubic.dev/pr/browserbase/stagehand/pull/1671">Review in
cubic</a></sup>

<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: Chromie Bot <chromie@browserbase.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
@changeset-bot
Copy link

changeset-bot bot commented Feb 9, 2026

🦋 Changeset detected

Latest commit: 03a98c1

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@browserbasehq/stagehand Patch
@browserbasehq/stagehand-evals Patch
@browserbasehq/stagehand-server Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Contributor

github-actions bot commented Feb 9, 2026

✱ Stainless preview builds

This PR will update the stagehand SDKs with the following commit message.

feat: Multi-region stagehand api support

Edit this comment to update it. It will appear in the SDK's changelogs.

stagehand-csharp studio · code · diff

Your SDK built successfully.
generate ⚠️build ✅lint ❗test ✅

stagehand-typescript studio · code · diff

Your SDK built successfully.
generate ✅build ✅lint ✅test ❗

npm install https://pkg.stainless.com/s/stagehand-typescript/1e8b625ea3e19f9399095db50d780a984e891ffc/dist.tar.gz
stagehand-go studio · code · diff

Your SDK built successfully.
generate ✅lint ✅test ✅

go get github.com/stainless-sdks/stagehand-go@cc551191db7bdbf7be23b437260c33a31baa343c
stagehand-php studio · code · diff

Your SDK built successfully.
generate ✅lint ✅test ✅

stagehand-python studio · code · diff

Your SDK built successfully.
generate ✅build ✅lint ✅test ✅

pip install https://pkg.stainless.com/s/stagehand-python/2f19f847fa771b4010601c87eb0cb5f9d334e289/stagehand-3.5.0-py3-none-any.whl
stagehand-openapi studio · code · diff

Your SDK built successfully.
generate ✅

stagehand-kotlin studio · code · diff

generate ✅build ✅lint ✅test ⏳

stagehand-java studio · code · diff

Your SDK built successfully.
generate ✅build ✅lint ✅test ✅

Add the following URL as a Maven source: 'https://pkg.stainless.com/s/stagehand-java/6c4e4c2ee8791a1a44517de2c063bf731c29595c/mvn'
stagehand-ruby studio · code · diff

Your SDK built successfully.
generate ✅lint ✅test ✅

⏳ These are partial results; builds are still running.


This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push.
If you push custom code to the preview branch, re-run this workflow to update the comment.
Last updated: 2026-02-10 16:35:08 UTC

@miguelg719 miguelg719 marked this pull request as ready for review February 9, 2026 22:45
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 11 files

Confidence score: 3/5

  • Potential regression in packages/core/lib/v3/api.ts: a trailing /v1/ in STAGEHAND_API_URL can normalize to /v1/v1, breaking API calls for some configs.
  • Impact is user-facing and tied to URL construction logic, so there’s some risk until the trailing-slash handling is fixed.
  • Pay close attention to packages/core/lib/v3/api.ts - URL normalization may generate a double /v1/v1 path.
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/core/lib/v3/api.ts">

<violation number="1" location="packages/core/lib/v3/api.ts:746">
P2: Bug: If `STAGEHAND_API_URL` ends with `/v1/` (trailing slash), the normalization produces a double `/v1/v1` path. Strip the trailing slash *before* checking for the `/v1` suffix.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant App as User Application
    participant SDK as StagehandAPIClient
    participant Helper as getApiUrlForRegion
    participant Env as process.env
    participant API as Regional Stagehand API

    Note over App, API: Multi-Region Initialization Flow

    App->>SDK: init(browserbaseSessionCreateParams)
    SDK->>SDK: NEW: Store session region (e.g., 'eu-central-1')
    SDK-->>App: Ready

    Note over App, API: Request Routing Flow (e.g., /sessions/start)

    App->>SDK: request(path, options)
    
    SDK->>Env: Check STAGEHAND_API_URL
    
    alt STAGEHAND_API_URL is set
        Env-->>SDK: Custom URL
        SDK->>SDK: CHANGED: Normalize URL (ensure single /v1 suffix)
    else STAGEHAND_API_URL is NOT set
        SDK->>Helper: getApiUrlForRegion(storedRegion)
        Note right of Helper: Maps region to specific endpoint:<br/>us-west-2 (default), us-east-1,<br/>eu-central-1, ap-southeast-1
        Helper-->>SDK: Regional Base URL + /v1
    end

    SDK->>API: fetch(fullUrl + path)
    
    alt Happy Path: Region Match
        API-->>SDK: 200 OK (Session Data)
        SDK-->>App: Response
    else Unhappy Path: Region Mismatch
        Note right of API: Session region 'X' != API region 'Y'
        API-->>SDK: 400 Bad Request
        SDK-->>App: Error (Instruction to route to correct endpoint)
    end

    opt disableAPI is true
        App->>SDK: constructor({ disableAPI: true })
        Note over SDK: SDK skips remote API calls<br/>runs browser automation locally
    end
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 9, 2026

Greptile Overview

Greptile Summary

This PR adds multi-region support to the v3 Stagehand API client by mapping Browserbase session regions to region-specific Stagehand API base URLs and using that mapping to build request URLs when STAGEHAND_API_URL is not set. It also introduces a shared BrowserbaseRegion schema/type, updates the OpenAPI v3 spec and generator to include regional servers and documentation, and adds unit/integration tests verifying non-default regions are accepted and URLs include the /v1 suffix.

Confidence Score: 3/5

  • This PR is close to mergeable but has a couple of correctness issues in URL normalization/tests and a brittle runtime type guard in new integration tests.
  • Core multi-region routing logic is straightforward, but there are still edge-case mismatches between TypeScript typing and intended runtime behavior (unknown region fallback) and a new integration-test helper that can throw if response shapes drift. Prior review thread about /v1 normalization should be fully resolved to avoid misrouting when STAGEHAND_API_URL includes trailing slashes.
  • packages/core/lib/v3/api.ts, packages/core/tests/api-multiregion.test.ts, packages/server/test/integration/v3/multiRegion.test.ts

Important Files Changed

Filename Overview
.changeset/lemon-cherries-appear.md Adds a changeset marking @browserbasehq/stagehand as a patch release for multi-region API endpoint routing.
packages/core/lib/v3/api.ts Introduces region→API URL mapping and stores session region to route API requests; adjusts STAGEHAND_API_URL /v1 normalization. Potential dead-code/typing mismatch in getApiUrlForRegion and env URL normalization edge cases.
packages/core/lib/v3/types/public/api.ts Adds BrowserbaseRegionSchema/type and reuses it in BrowserbaseSessionCreateParamsSchema.region.
packages/core/lib/v3/types/public/index.ts Re-exports BrowserbaseRegion type directly from Api namespace for convenience.
packages/core/lib/v3/types/public/sdkErrors.ts Updates SDK error messages to reference disableAPI instead of useApi/useAPI flags.
packages/core/tests/api-multiregion.test.ts Adds unit tests for region URL mapping and documents /v1 suffix expectations; includes a test for invalid region that depends on runtime behavior despite narrow BrowserbaseRegion typing.
packages/docs/v3/configuration/browser.mdx Documents multi-region API endpoints and adds disableAPI configuration examples and mismatch warning.
packages/server/openapi.v3.yaml Adds BrowserbaseRegion schema, updates session region fields to $ref it, and declares regional servers; extends description with multi-region documentation.
packages/server/scripts/gen-openapi.ts Registers BrowserbaseRegion schema component, adds regional servers and multi-region text to generated OpenAPI, and post-processes YAML to quote version fields and remove blank lines in markdown tables.
packages/server/test/integration/v3/multiRegion.test.ts Adds integration coverage ensuring sessions/start accepts all supported regions; type guard currently dereferences data without checking presence.
packages/server/test/integration/v3/start.test.ts Extends existing v3 sessions/start integration tests to assert non-default regions are accepted; imports BrowserbaseRegion for type assertions.

Sequence Diagram

sequenceDiagram
  participant SDK as StagehandAPIClient (packages/core/lib/v3/api.ts)
  participant Env as process.env.STAGEHAND_API_URL
  participant Map as REGION_API_URLS/getApiUrlForRegion
  participant API as Stagehand API (regional)

  SDK->>SDK: init(browserbaseSessionCreateParams)
  SDK->>SDK: store region on client
  SDK->>SDK: request(path)
  alt STAGEHAND_API_URL is set
    SDK->>Env: read STAGEHAND_API_URL
    SDK->>SDK: normalize baseUrl (ensure single /v1)
  else STAGEHAND_API_URL not set
    SDK->>Map: getApiUrlForRegion(region)
    Map-->>SDK: baseUrl + "/v1"
  end
  SDK->>API: fetchWithCookies(baseUrl + path, headers)
  API-->>SDK: HTTP response / SSE stream
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

11 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@miguelg719
Copy link
Collaborator Author

@greptileai @cubic-dev-ai

@cubic-dev-ai
Copy link
Contributor

cubic-dev-ai bot commented Feb 10, 2026

@greptileai @cubic-dev-ai

@miguelg719 I have started the AI code review. It will take a few minutes to complete.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 10, 2026

I see you've started the AI code review. I'll wait for it to complete before providing my review feedback. Let me know when you'd like me to look at specific aspects of the PR or if you have any questions about the multi-region implementation.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 11 files

Confidence score: 4/5

  • Most severe issue is a documentation formatting bug in packages/server/openapi.v3.yaml where >- folded scalars collapse table rows, which can confuse generated API docs but won’t affect runtime behavior.
  • Test quality concerns: packages/core/tests/api-multiregion.test.ts doesn’t actually exercise STAGEHAND_API_URL, and packages/server/test/integration/v3/multiRegion.test.ts can leak sessions if assertions throw, which may cause flaky tests.
  • Given the issues are doc/test-related and not production logic, this PR looks safe to merge with minimal risk.
  • Pay close attention to packages/server/openapi.v3.yaml, packages/core/tests/api-multiregion.test.ts, packages/server/test/integration/v3/multiRegion.test.ts - doc formatting and test robustness.
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/server/openapi.v3.yaml">

<violation number="1" location="packages/server/openapi.v3.yaml:19">
P1: Markdown table is broken: YAML folded scalar (`>-`) folds consecutive table rows into a single line, destroying the table structure.

The `description` uses `>-` (folded block scalar), which replaces newlines between consecutive non-empty lines with spaces. All 6 table rows get collapsed into one line, making the table unreadable in rendered OpenAPI docs.

Fix: Change `description: >-` to `description: |` (literal block scalar) which preserves all newlines. You'll then need to remove the intentional blank lines currently used as paragraph breaks (since `>-` needs them but `|` doesn't), or keep them as-is since extra blank lines in markdown just add spacing.</violation>
</file>

<file name="packages/core/tests/api-multiregion.test.ts">

<violation number="1" location="packages/core/tests/api-multiregion.test.ts:70">
P2: This test section claims to test `STAGEHAND_API_URL` env var handling but doesn't actually exercise it. The `beforeEach`/`afterEach` that save/restore `process.env.STAGEHAND_API_URL` are dead code — no test in this block sets the env var. `getApiUrlForRegion()` doesn't read `process.env.STAGEHAND_API_URL`; the actual `/v1` normalization logic is in `StagehandAPIClient.request()`. Consider either removing the misleading env-var scaffolding, or adding proper tests that set `STAGEHAND_API_URL` and verify the `/v1` suffix normalization through the request method.</violation>
</file>

<file name="packages/server/test/integration/v3/multiRegion.test.ts">

<violation number="1" location="packages/server/test/integration/v3/multiRegion.test.ts:87">
P2: Session leak: if any assertion before `endSession` throws, the session is never cleaned up. Wrap the assertion+cleanup in `try/finally` to ensure `endSession` is always called when a session was successfully created. This applies to all 6 tests in this file.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant App as User Application
    participant SDK as Stagehand SDK
    participant Client as StagehandAPIClient
    participant Env as Environment Variables
    participant API as Regional Stagehand API

    Note over App,API: Multi-Region Initialization Flow

    App->>SDK: new Stagehand({ browserbaseSessionCreateParams: { region: 'eu-central-1' } })
    SDK->>Client: NEW: init() with session params
    Client->>Client: NEW: Store region in internal state

    Note over App,API: Request Routing Logic (e.g., act, extract, observe)

    App->>SDK: page.act("click login")
    SDK->>Client: request("/act", options)

    Client->>Env: Check STAGEHAND_API_URL
    
    alt STAGEHAND_API_URL is set
        Env-->>Client: Custom URL
        Client->>Client: CHANGED: Normalize URL (ensure exactly one /v1 suffix)
    else STAGEHAND_API_URL is NOT set
        Client->>Client: NEW: getApiUrlForRegion(this.region)
        Note right of Client: Maps region (e.g. eu-central-1) <br/>to regional subdomain
    end

    Client->>API: CHANGED: fetch(RegionalEndpoint + "/v1/act")
    
    alt Happy Path: Region Match
        API-->>Client: 200 OK (Streamed SSE response)
        Client-->>App: Action Result
    else Unhappy Path: Region Mismatch
        API-->>Client: 400 Bad Request
        Note right of API: "Session is in region 'X' but <br/>this API instance serves 'Y'"
        Client-->>App: Throw Error (Reference disableAPI/routing)
    end
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

11 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +59 to +66
export function getApiUrlForRegion(
region: BrowserbaseRegion | undefined,
): string {
const baseUrl =
REGION_API_URLS[region as BrowserbaseRegion] ??
REGION_API_URLS["us-west-2"];
return `${baseUrl}/v1`;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unknown region is impossible
getApiUrlForRegion(region: BrowserbaseRegion | undefined) can only receive valid enum values (or undefined), so the REGION_API_URLS[region as BrowserbaseRegion] ?? ... fallback branch for “unknown regions” is dead code in normal usage. This is currently relied on by the unit test that passes an invalid string via @ts-expect-error. Either widen the function param to string | undefined (so runtime unknowns are handled intentionally) or remove the unreachable fallback + adjust the test.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 10, 2026

Additional Comments (1)

packages/server/test/integration/v3/multiRegion.test.ts
Type guard can throw
isSuccessResponse checks response.success && response.data.sessionId !== null, but StartErrorResponse has no data field, so if a response ever has success: true but a malformed body (or if typing drifts), this will throw at runtime. Safer guard is to additionally check 'data' in response (and typeof response.data?.sessionId === "string") before dereferencing.

1. OpenAPI YAML: Change description from >- to | literal scalar to
preserve markdown table formatting. The folded scalar was collapsing
table rows into a single line.

2. api-multiregion.test.ts: Remove misleading STAGEHAND_API_URL env var
scaffolding. The beforeEach/afterEach were dead code since no tests
actually set the env var, and getApiUrlForRegion doesn't read it.
Renamed the describe block to "URL /v1 suffix handling" to accurately
reflect what the tests verify.

3. multiRegion.test.ts: Add try/finally blocks around assertions to
ensure endSession is always called even if assertions throw. This
prevents session leaks that could cause flaky tests.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes OpenAPI docs rendering and strengthens multi‑region tests to
prevent session leaks and clarify URL behavior.

- **Bug Fixes**
- Preserve markdown table formatting by switching OpenAPI description to
a literal scalar (|).
- Always call endSession via try/finally in integration tests to prevent
leaks and flakiness.

- **Refactors**
- Remove unused STAGEHAND_API_URL env scaffolding in api-multiregion
tests.
- Rename suite to “URL /v1 suffix handling” and document that
getApiUrlForRegion always includes /v1.

<sup>Written for commit 28ffac7.
Summary will update on new commits. <a
href="https://cubic.dev/pr/browserbase/stagehand/pull/1675">Review in
cubic</a></sup>

<!-- End of auto-generated description by cubic. -->

Co-authored-by: Chromie Bot <chromie@browserbase.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants