Skip to content

[docs]: sync docs-production w/ main - #3272

Merged
seanmcguire12 merged 94 commits into
docs-productionfrom
update-sh-4.3.0
Oct 20, 2026
Merged

seanmcguire12 merged 94 commits into
docs-productionfrom
update-sh-4.3.0

Conversation

@seanmcguire12

@seanmcguire12 seanmcguire12 commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Summary by cubic

Brings the production docs branch up to date with main ahead of the v4.3.0 SDK release.

  • Documents page.waitForFunction(), the getExtensionArchive() helpers, and the extensionCdpUrl / headers options on localBrowser.connect().
  • Updates the WebMCP launch flag for Chromium newer than 157 and the deployment guide's extension upload flow.
  • Adds the browse cloud search provider and mode flags and the new waitForFunction() migration entries.
  • Rewrites the evals README around the v4.3.0 run experience and rewrites the CLI/skill docs for search flags.

Written for commit c81d603. Summary will update on new commits.

View guided diff Turn on auto-fix

shrey150 and others added 30 commits September 24, 2026 15:51
## What's the issue?

Browse can fail to connect to a healthy local Chrome because it trusts
an old browser connection URL saved in the profile's
`DevToolsActivePort` file. The existing check only confirms that
something is listening on the cached port; it does not confirm that the
saved browser target still exists.

For example, the file points to
`ws://127.0.0.1:9222/devtools/browser/old-id`, while the running Chrome
exposes `/devtools/browser/new-id`. Browse selects `old-id`, and the
connection fails with a 404 or connection reset.

This PR checks the cached target against Chrome's live `/json/version`
response. If they disagree, Browse discards the stale candidate and uses
its existing live-endpoint fallback. It compares URL paths so
`localhost` versus `127.0.0.1` does not invalidate a matching target,
and probes each port only once per discovery call.

## When does it happen?

1. A Chrome instance leaves a `DevToolsActivePort` file behind after
exiting.
2. A later browser instance uses the same debugging port, but has a
different browser target ID. An old profile file can therefore point to
a port now owned by another instance.
3. Browse discovers that stale file while attaching to a local browser,
such as through `browse open --auto-connect` or the discovery used by
`browse doctor`.

The port is reachable, so the old check accepts the file even though its
target is gone. A restart alone is not sufficient to trigger this: the
stale file must remain visible and its port must be reused.

## Why is it important?

Local browser attachment fails even though Chrome is running and its
debugging endpoint works. Users and agents cannot reliably reuse that
browser session, and diagnostics can select a dead endpoint. Validating
the browser target prevents leftover profile state from making a working
browser look broken.

This is a reproduced connection-correctness bug; we have not established
how frequently users encounter it.

## How was it verified?

Verification on September 23, 2026, for head `b96dea6`:

- **Real Chromium:** created an isolated stale profile file pointing at
a live browser's port, then ran both discovery APIs before and after the
fix. Main `fbcdf6169` selected the stale target and failed with 404 /
connection reset. The patch selected the live target, completed both
WebSocket upgrades with HTTP 101, and successfully called
`Browser.getVersion` (`Chrome/153.0.8010.12`). This was a Linux Chromium
smoke test; the temporary browser and profile were cleaned up.
- **401 CLI tests passed across 29 files**, including six regressions
covering stale and fresh caches, host spelling, fallback discovery,
probe deduplication, and no live browser.
- **Build and lint passed**, including formatting, ESLint, and
TypeScript checks.

The diff contains the discovery fix, its regression tests, and a Browse
patch changeset. The PR targets `main`.
# why
SDK changes must include documentation, but merging those docs into
`main` should not publish unreleased APIs to the public site

## what changed
- Add Mintlify previews for docs PRs targeting `main` and a persistent
preview updated by docs pushes to `main`. Report the URL and wait for
deployment success.
- Run docs reference tests and Mintlify validation independently of SDK
path filters, including on docs-only PRs and production backports.
- Include Go SDK source in the docs test cache inputs.
- Add explicit `main`-only guards to SDK publishing jobs, including the
reusable Python publisher.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Separates docs previews from production publishing so unreleased API
docs aren't published to the public site.

- Adds Mintlify previews for docs PRs targeting `main` and persistent
previews for docs pushes to `main`, reporting the URL and waiting for
deployment success.
- Runs docs reference tests and Mintlify validation on every PR,
including docs-only PRs and backports.
- Includes Go SDK source in the docs test cache inputs.
- Adds `main`-only guards to SDK publishing jobs.

<sup>Written for commit 6fd167a.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3042?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# why
- clean up copy & test the editorial docs change workflow


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Cleans up the introduction copy by removing redundant phrasing and tests
the editorial docs change workflow.

<sup>Written for commit aff9504.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3048?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
Mirrored from external contributor PR #2738 after approval by
@miguelg719.

Original author: @abhinavkr26104
Original PR: #2738
Approved source head SHA: `e77c269fcc7ab33d2b76f213f26da62b77b1e826`

@abhinavkr26104, please continue any follow-up discussion on this
mirrored PR. When the external PR gets new commits, this same internal
PR will be marked stale until the latest external commit is approved and
refreshed here.

## Original description
# why

The v4 init schema supplied `https://example.com/v1/traces` whenever
callers omitted telemetry. The extension treated that placeholder as an
intentional OTLP destination, creating guaranteed-failing background
exports and possible shutdown delays for otherwise default Stagehand
instances.

Fixes #2732

# what changed

- Make `stagehand.init` telemetry optional instead of injecting a
placeholder endpoint.
- Leave extension tracing inert when no telemetry configuration is
supplied while preserving explicit OTLP export behavior.
- Regenerate Python and Go protocol models and the embedded Go extension
bundle.
- Keep Go's existing value-style public telemetry option while omitting
its zero value from the wire.
- Document that telemetry export is disabled by default and add
protocol/runtime/SDK regression coverage.
- Add patch Changesets for the extension and SDKs.

# test plan

- Protocol unit suite: 26 files passed, 359 tests passed.
- Extension unit suite: 45 files passed, 334 tests passed, 10 existing
TODOs.
- Focused TypeScript SDK create tests passed, including omitted and
explicit telemetry.
- Python focused tests: 200 passed, 1 skipped; generated-model
freshness, Ruff format, and Ruff lint checks passed.
- Full Python suite attempted: 455 passed, 2 skipped; only the two
pre-existing Windows path assertions tracked by #2733 failed.
- Go SDK suite excluding the intentionally separate examples package
passed.
- Protocol type-check and extension production build passed.
- Targeted Oxfmt, Oxlint, Changesets validation, and `git diff --check`
passed.
- The full JavaScript unit run was attempted; unrelated
Windows/environment failures remain in SDK path assertions,
package-manager spawning, and file metadata handling.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Makes telemetry export opt-in so omitted telemetry no longer injects a
placeholder endpoint that caused guaranteed-failing exports and shutdown
delays. `stagehand.init` no longer defaults to
`https://example.com/v1/traces`; omitting telemetry leaves tracing
inert, while explicit telemetry keeps OTLP export.

- Protocol: `stagehand.init.telemetry` is now optional with no default;
schema, integrity, and wire-casing tests updated.
- Extension: `createStagehandTracing.configure` accepts `undefined` and
skips runtime creation; flush/shutdown become no-ops when telemetry is
absent.
- SDKs: TypeScript omits `telemetry` from the wire when unset; Go's
`StagehandInitParams.Telemetry` is now `*TelemetryConfig` and omits the
zero value via `optionalTelemetry`, while `CreateOptions.Telemetry`
stays value-style; Python marks `telemetry` as `Optional` with the
placeholder default removed.
- Release: Patch changesets added for the five affected packages.

**Migration**
- No action needed; placeholder export errors and shutdown delays
disappear.
- Set `telemetry.traces.endpoint` to an OTLP collector (ending in
`/v1/traces`) with required headers to enable export.
- Go: pass `nil` to omit telemetry or set a non-empty endpoint/headers
to enable; direct `StagehandInitParams` construction now requires
`*TelemetryConfig`.

<sup>Written for commit fecc5a6.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3045?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

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

<!-- external-contributor-pr:owned source-pr=2738
source-sha=e77c269fcc7ab33d2b76f213f26da62b77b1e826 claimer=miguelg719
-->

---------

Co-authored-by: Abhinav Kumar Singh <abhinav.kr.singh.2610@gmail.com>
Co-authored-by: miguel <miguelg71921@gmail.com>
Co-authored-by: Miguel <36487034+miguelg719@users.noreply.github.com>
thanks @mikhail-koviazin for the contribution here!

## why

The composed-tree XPath parser evaluates `text()` and `.` through the
same helper, `element.textContent`. In XPath these are not the same
thing: `.` is the string-value of the element, so it covers the whole
subtree, while `text()` is the node-set of the element's **direct child
text nodes**.

This parser is not a rare path. It takes over whenever the document
contains a shadow root anywhere, so a single unrelated web component on
the page changes what a locator matches, silently and with no error.

Measured against `document.evaluate()` on a build of `main`
(`a73da68b`), fixture served over http. The only difference between a
run that matches native and a run that does not is one unrelated
`attachShadow()` call elsewhere in the same document:

| XPath | `document.evaluate()` | Stagehand |
| --- | --- | --- |
| `//button[text()='Save']` | 1 | 2 |
| `//div[text()='a']` | 1 | 0 |
| `//div[contains(text(),'b')]` | 0 | 1 |
| `//div[@id='split'][text()='y']` | 1 | 0 |
| `//div[@id='split'][contains(text(),'y')]` | 0 | 1 | |
`//div[@id='split'][normalize-space(text())='x']` | 1 | 0 | |
`//button[.='Save']` | 2 | 2 (control: `.` is already correct) |

Fixture: `<button id="wrapped"><span>Save</span></button>` before
`<button id="direct">Save</button>`, plus `<div
id="mixed">a<span>b</span></div>` and `<div id="split">x<br/>y</div>`.

The count is not the worst part. The button whose label sits inside a
`<span>` comes first in document order, so `//button[text()='Save']`
returns it first and `.first().click()` clicks the wrong button. Nothing
throws, nothing logs, and the run continues on the wrong element. The
other direction is a silent zero on markup as ordinary as
`a<span>b</span>`.

## what changed

`text()` now reads its own node-set, and `.` keeps exactly the meaning
it has today:

- `text()='v'` is true when **any** direct child text node equals `v`.
Comparing a node-set to a string is existential in XPath.
- `contains(text(),'v')` and `normalize-space(text())='v'` read the
string-value of the **first** node, because both functions take a
string, so the node-set collapses.
- `.='v'`, `contains(.,'v')` and `normalize-space(.)='v'` keep reading
the string-value of the element, unchanged.

Mechanically, in `packages/extension/dom/locatorScripts/xpathParser.ts`:
the three patterns that accepted `(?:text\(\)|\.)` now capture which
token they matched, and `textEquals` / `textContains` carry a `source:
"self" | "text"` field that `evaluatePredicate` reads. The field is
optional and absent means `self`, so predicates constructed anywhere
else keep their current behavior. `and`, `or` and `not` carry it through
without changes.

## test plan

`packages/extension/tests/xpath-text-predicates.test.ts` (new, unit):
the parser keeps `text()` and `.` apart for `=`, `contains()` and
`normalize-space()`, and carries the source through `or` and `not`.

`packages/sdk-ts/tests/integration/locatorXPathTextPredicates.test.ts`
(new, integration): the table above against real Chrome. It has to be
served over http, since `data:` URLs stay on the native engine and never
reach this parser at all. Registered in `scripts/test-integration.ts`
next to the other locator groups.

Both are red on `main` and green with the change. On `main` the
wrong-button case fails with `expected 2 to be 1` and the silent-zero
case with `expected +0 to be 1`.

Context: #1679 consolidated the parser copies and #1683 taught this one
`text()`, `contains()` and `normalize-space()`. This is the same layer,
one step further in.


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes the composed-tree XPath parser so `text()` reads only direct child
text nodes. Previously it read `element.textContent` (same as `.`),
causing diverging matches and wrong clicks on pages with any shadow
root.

- Old: `text()` behaved like `.`. New: `text()` evaluates direct child
text nodes; `.` still reads the element's subtree string-value. This
aligns with `document.evaluate()`.
- If a locator relied on `text()` to match nested text, use `.` instead.
- `text()='v'` is existential across child text nodes;
`contains(text(),'v')` and `normalize-space(text())='v'` collapse to the
first text node.
- Adds unit and integration tests; integration runs over http and is
registered in `scripts/test-integration.ts`.

<sup>Written for commit 482e0a9.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3052?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

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

---------

Co-authored-by: Mikhail Koviazin <mikhail.koviazin@gmail.com>
# why

Add the extension-side PDF implementation separately from exposing a new
SDK operation, so capture behavior can be reviewed on its own.

This is **PR1 of 2**. Follow-up #3030 adds the public protocol/RPC
registration, TypeScript/Python/Go SDK wiring, generated models,
documentation, release notes, and final extension archive.

# what changed

- Add internal Understudy `Page.pdf()` using native CDP request/response
types; keep the result base64-encoded for the later transport layer.
- Share the existing capture queue with screenshots, including a
configurable 30-second deadline, late-response recovery, and prevention
of expired queued work.
- Preserve the original timeout in a typed recovery error and its safe
diagnostic message.
- Add focused capture tests for serialization, failures, timeouts,
queued expiry, and independent pages.
- Refresh only the embedded extension snapshot required by the
repository's artifact-drift check. PR2 regenerates it again when the
public wiring lands.

No PDF RPC is registered here. No public SDK methods, protocol schemas,
generated models, or documentation are changed.

# test plan

- `pnpm check`: **36 tasks passed**.
- Extension, SDK, protocol, documentation, parity, and discovery
regressions: **975 passed** across 102 files (10 existing TODOs).
- Local Chromium screenshot integration: **7 passed**.
- Go SDK tests and generated-model/archive consistency checks passed.
- Python generated-model consistency check passed.
- Formatting and `git diff --check` passed.
# why

Expose PDF rendering through the existing Stagehand SDK conventions
after the internal extension implementation is in place.

This is **PR2 of 2**, stacked directly on #3034
(`amel/pdf-render-extension`). Merge the parent first and follow the
repository's stacked-PR handoff rules when moving this PR to `main`.

# what changed

- Register the `page.pdf` protocol operation and connect the extension
router, controller, and runtime to the internal implementation from
#3034. Replace its temporary native-CDP signature with the canonical
protocol types.
- Add TypeScript and Python `page.pdf()` and Go `Page.PDF()`, returning
PDF bytes. TypeScript and Python optionally write a local file using
their existing screenshot conventions.
- Add typed print options and matching SDK response deadlines: 30
seconds for capture by default, with `timeout: 0` disabling the
deadline. Preserve error causes and include computed timeout durations
in diagnostics.
- Regenerate the protocol document, Python and Go models, and the final
embedded extension ZIP. Keep the public API documentation and release
changeset with the SDK exposure.
- Add wire/tracing, SDK, file-output, and local Chrome integration
coverage. Fix integration-test discovery and validate its mapping
against repository files.

The capture implementation and recovery tests are reviewed in #3034, not
repeated in this diff. The complete stack's Git tree is identical to the
previously reviewed implementation at `2b416e172`; this split changes
review boundaries, not behavior.

# test plan

- Complete-stack local Chromium PDF and screenshot integration: **9
passed**. Verify PDF bytes and file equality, page count, CSS
dimensions, tags, page ranges, and captures after a rejected print.
- Extension, TypeScript SDK, protocol, reference documentation, SDK
parity, and integration discovery: **989 passed** across 102 files (10
existing TODOs).
- `pnpm check`: **36 tasks passed**. Generated Go extension matches the
final extension build; `git diff --check` passes.
- The identical final tree was also verified with **235 Python tests**,
Ruff/type checks, Go SDK tests, `go vet`, and generated-artifact checks.
- Parent #3034 was independently verified with **975 regressions**, **7
screenshot integration tests**, all **36 repository checks**, and
Go/Python generated-artifact checks.
## Summary

Make the integrations overview a general directory for connecting
Stagehand to agents, frameworks, and application workflows. Organize the
overview and sidebar into Agent Frameworks, CLI Agents, and Automations.

- Add dedicated overviews for Agent Frameworks and CLI Agents. Cover
framework connections separately from MCP adapter setup for coding
agents, with Pi documented as a native extension.
- Update navigation and security links, and replace the removed MCP
best-practices entry with the CLI Agents guide.
- Add Stripe under Automations, documenting the Checkout sample from
stripe-samples/webmcp#5, its setup, WebMCP flow,
and final Pay click.
- Pin the Stripe sample commit while the upstream PR is open and explain
its spending limit and result-handling limitations.

## Validation

- `mint validate`
- `mint broken-links --check-anchors --check-redirects --check-snippets`
- `mint a11y --skip-contrast`
- Formatting check for `docs.json` and `git diff --check`

All passed using Node.js 24. Checkout was not executed; the Stripe guide
was verified against the upstream sample source.

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
# why
- example.com changed, this broke some smoke tests in our ci
# what changed
- swapped it to a hosted eval site that is similar to example.com


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes failing CI smoke tests by replacing `https://example.com` with a
hosted eval site that mirrors example.com across the Go, Python, and
TypeScript SDK examples and the TypeScript Browserbase smoke test.

<sup>Written for commit dfd525e.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3069?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

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

* Before Browserbase had secrets support, `functions init` would install
a playwright template. But now we support secrets so we can update the
starter template to showcase Stagehand.
* There were some rough edges around the `functions publish` command
related to pnpm 11. Added a few updates so that the functions CLI works
out of the box.

# what changed

# test plan

It works if nothing in this path errors:
1. [in stagehand repo] `pnpm build && cd packages/cli`
2. `alias browse-dev="node $HOME/[your dev
path]/stagehand/packages/cli/bin/run.js"` to set a local version of the
`browse` cli called `browse-dev`
3. `cd [your dev path, _not_ in stagehand repo] && browse-dev functions
init branch-test && cd branch-test`
4. `browse-dev cloud extensions upload
node_modules/@browserbasehq/stagehand/dist/assets/stagehand-extension.zip`
and then replace `your-extension-id` in `index.ts`
5. `browse-dev cloud secrets create BROWSERBASE_API_KEY --env
BROWSERBASE_API_KEY` to store your secret API key for use in the
deployed function
6. `browse-dev functions dev index.ts`
7. (in a new terminal) `curl -X POST
http://127.0.0.1:14113/v1/functions/my-function/invoke -H 'Content-Type:
application/json' --data '{}'` to make sure it works locally
8. `npm_config_min_release_age=0 browse-dev functions publish index.ts`
9. `browse-dev functions secrets attach <functionId> <secretId>`
10. `browse-dev functions invoke <functionId>` to make sure you got the
same result as (7) above
11. Success!



<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Swaps the Playwright starter in `functions init` for a Stagehand one,
and fixes `functions init` and `functions publish` on pnpm 11 and
private npm registries.

- Local dev now sends an empty `secrets` object to invocations, matching
production, so the starter's `context.secrets.BROWSERBASE_API_KEY`
lookup needs no null check and falls back to
`process.env.BROWSERBASE_API_KEY`.
- `functions init` installs `@browserbasehq/stagehand` instead of
`playwright-core`, pins zod to Stagehand's version so schemas pass type
checks, and writes a Stagehand starter that extracts Hacker News top
stories through the Model Gateway.
- The starter connects with `browserbase.connect` into
`Stagehand.create` and expects you to upload the Stagehand extension and
paste its ID into `index.ts`.
- `functions init` writes `pnpm-workspace.yaml` so pnpm 11 allows
esbuild's build script, and its next steps use `browse` commands.
- `functions publish` builds `package-lock.json` from the uploaded files
(so local `file:` dependencies resolve), omits registry-resolved URLs
for private registries, checks for an existing lockfile, and prints npm
output when generation fails.

<sup>Written for commit b630e73.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3055?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

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

* The release of Function Secrets enables us to support Stagehand
deployments on Browserbase. This PR showcases that in the new deployment
guide

# what changed

# test plan

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Updates the Stagehand deployment guide to recommend Browserbase
Functions with encrypted project secrets as the primary deployment path
instead of Vercel.

- Adds setup, extension upload, Function development, local testing,
publishing, secret attachment, invocation, and troubleshooting steps.
- Uses the Model Gateway in the example, so no model provider setup is
needed.
- Moves the Vercel guide under "Other deployment options" and adds a
Features section.
- Clarifies the introduction's description of Stagehand's control
layers.

<sup>Written for commit 83c9e20.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3056?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
Release Browse independently of the Stagehand SDKs. Merging this PR
publishes the CLI from the merged commit.

## 0.11.1

### Patch Changes

- [#3055](#3055)
[`8308d8d`](8308d8d)
Thanks [@akeimach](https://github.com/akeimach)! - `functions init` now
scaffolds a Stagehand project. It installs `@browserbasehq/stagehand`
instead of `playwright-core`, installs the zod version that Stagehand
uses, and writes a Stagehand starter function.

- [#3055](#3055)
[`8308d8d`](8308d8d)
Thanks [@akeimach](https://github.com/akeimach)! - Fix Functions builds
that failed because of how `functions publish` generated
`package-lock.json` or how `functions init` set up pnpm:

- `functions publish` now generates `package-lock.json` without registry
URLs, so private npm registries work.
- `functions publish` now resolves local `file:` dependencies by
building `package-lock.json` from the uploaded files rather than just
`package.json`.
- `functions publish` now prints npm's error output when it can't
generate `package-lock.json`.
- `functions init` now writes a `pnpm-workspace.yaml` that allows the
esbuild build script, required by pnpm 11+.

- [#2542](#2542)
[`514970e`](514970e)
Thanks [@shrey150](https://github.com/shrey150)! - Fix local browser
discovery (`--auto-connect`, `browse doctor`) trusting a stale cached
debugging port after a different Chrome process later reuses that same
port.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
# why

Fixing a prose issue surfaced in another PR, and while in there, added
clarity about the functions starter code and what could be replaced

# what changed

* Updates docs prose from "we recommend" to "Browserbase recommends"
* Specifies which node version
* Adds a note about the template code and what must stay vs be replaced

# test plan


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes prose in the deployment guide and clarifies that the Functions
template is starter code you replace.

- Changes "we recommend" to "Browserbase recommends" and specifies
Node.js 22.18 or later.
- Explains that the template contains a starter Function to replace, and
notes to keep the `defineFn` call and update the function name
consistently.

<sup>Written for commit 1f6ff65.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3077?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# why
Three links in the v3 docs are broken, and two Go code samples were
rewritten into links, so they no longer show valid Go.

# what changed
- `v3/sdk/go.mdx`: restore `param.Override[T](value)` and
`param.Override[stagehand.FooParams](12)`. Both had been turned into
links to non-existent files (`stagehand-go/blob/main/value` and `/12`).
The restored text matches the stagehand-go README.
- `v3/sdk/java.mdx`: the OkHttp logging interceptor link pointed at
`square/okhttp/tree/master`. That repo's default branch is `main`, and
`master` no longer resolves.
- `v3/basics/evals.mdx`: `evals.config.json` moved to
`packages/evals/evals.config.json`. The link used the old top-level
path.

# test plan
Checked each new target on GitHub (`packages/evals/evals.config.json` on
main, `okhttp-logging-interceptor` on okhttp main) and compared the Go
snippets against the stagehand-go README. Docs-only change, no Changeset
needed per CONTRIBUTING.md.


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes three broken links in the v3 docs.

- Go: the `param.Override[T](value)` and
`param.Override[stagehand.FooParams](12)` code samples were accidentally
converted into links to non-existent files and are now back to valid Go.
- Java: the OkHttp logging interceptor link now uses `main` instead of
`master`.
- Evals: the `evals.config.json` link now points to
`packages/evals/evals.config.json`.

<sup>Written for commit c427fb1.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3076?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# why
a `locator` action needs one timeout covering all of its downstream code
(eg, checking frame readiness, finding the element, & taking the
action). if setup uses three seconds of a five-second timeout, the
action should have two seconds left

this pr adds the shared timeout helper. later PRs will connect it to
locator methods & add public timeout options.

# what changed
- added `locatorOperation.ts` to track the time remaining for one call.
`runLocatorOperation()` creates it once & all nested steps share it
  - passing `0` disables the timeout
- added `run()` to check the deadline before starting a step & stop
waiting when time runs out. the error names the operation & the step
that was still waiting.
- added `delay()` so pauses between steps use the same timeout.
- added `cleanup()` to attempt cleanup after a timeout, with a
one-second limit on waiting. cleanup errors do not replace the original
error.
- added an optional callback to release temporary resources that arrive
too late to use. commands already sent to the browser may still finish

# test plan
added tests in `locatorOperation.test.ts` that control time & hold
responses open
to verify:
- nested steps keep the original deadline after success or failure, &
timing out one call does not stop another.
- zero disables the timeout, changing the system clock does not change
the time remaining, & invalid timeout or delay values are rejected.
- an expired call cannot start another step. a late response or error
cannot resume the action.
- resources arriving after timeout are released once; resources returned
in time remain available to the caller.
- delays stop at the deadline. long timeouts & delays are not shortened
by the underlying timer's size limit.
- timers & listeners are removed after success, failure, or timeout.
timeout errors identify a step that is still waiting.
- cleanup failures preserve the original error, & stalled cleanup
neither delays the timeout response nor waits longer than its one-second
allowance

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds a shared locator operation context so a single timeout spans all
steps of a locator action (frame checks, element lookup, and the action
itself), replacing separate per-step deadlines.

- `runLocatorOperation()` creates the context once and nested steps
share its remaining budget; passing `0` disables the timeout.
- `run()` checks the deadline before each step, `delay()` pauses within
the same budget, and cleanup of late resources is attempted for one
second after expiry.
- Expiry stops waiting and may release late-arriving resources, but the
timeout error always wins, even if a late command rejects.

<sup>Written for commit 5800073.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3013?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# why
resolving a the node/object ID that a `locator` points to can involve
crossing iframes, waiting for browser helpers, & looking up the element.
these steps need to share the caller's deadline so each frame or retry
cannot restart the timeout.

this pr connects that deadline to node/object ID resolution. the next PR
in this stack will connect `locator` actions & reads to these helpers.
public parameters for setting timeouts will come in a later PR.

### note:
this PR also renames `LocatorOperation` to `Progress` for clarity

# what changed
- renamed `locatorOperation.ts` to `progress.ts`, `LocatorOperation` to
`Progress`, & `runLocatorOperation()` to `runWithProgress()` because it
will be used by callers beyond locators.
- passed the same optional progress through frame traversal, element
lookup, & browser helper readiness. callers without progress keep their
existing behavior for now.
- made readiness waits, retries, & browser commands use the remaining
time. readiness can exceed the old fixed limits when the caller allows
it. passing in `0` disables the deadline.
- preserved timeout errors through retries, fallback setup, & cleanup.
closed connection or session errors stop resolution, while frame
movement & temporary browser context loss can still recover before
expiry.
- released temporary browser references after timeout, including late
results. callers waiting for shared helper setup have independent
deadlines.

# test plan
added tests in `locatorResolution.test.ts` using controlled time &
browser responses to verify:
- multiple frame hops share one budget, & polling stops when it expires.
- readiness can finish beyond the old limits with a longer or disabled
timeout.
- short readiness attempts fit the remaining time & detect a frame's new
session.
- stalled commands time out; late responses cannot resume resolution &
temporary references are released. listeners & timers are removed after
expiry.
- one caller timing out does not cancel shared helper setup for another
caller.
- errors or cleanup finishing after the deadline produce a timeout, even
before the timeout timer fires. ordinary lookup failures retain their
existing behavior before expiry.
- closed connections & sessions surface their errors. recovery from a
changed session or missing browser context works only while the call is
still active.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds a shared deadline to `locator` resolution so iframe hops, readiness
waits, and element lookup all share the caller's timeout instead of each
restarting it. Also fixes locator failures when entering still-loading
iframes and correctly resolves XPaths that end at an iframe element.

**What changed**
- Renames `LocatorOperation` to `Progress` and `runLocatorOperation()`
to `runWithProgress()`; callers beyond locators now use it, and a
temporary `runLocatorStep()` adapter lets callers without `Progress`
keep current behavior.
- Threads an optional `Progress` through frame traversal and element
lookup; `0` disables the deadline.
- Readiness waits and browser commands use remaining time; timeout
errors survive retries, fallback setup, and cleanup, while closed
connection or session errors stop resolution immediately.
- Releases temporary browser references after expiry, including late
results and earlier element matches replaced by a later lookup.
- Recovered contexts and frame restarts are honored only while the call
is active.

**Bug fixes**
- Waits for the locator world when a deep XPath crosses a loading iframe
instead of failing on a missing execution context.
- Keeps a trailing `iframe[n]` in the parent frame as the target element
instead of descending into the child document.

<sup>Written for commit 0f263bc.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3023?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# why
pr #3023 made locator resolution respect the caller's deadline. the
action or read that follows also needs to use the remaining time.
otherwise, a stalled browser command can keep the call waiting after its
timeout.

# what changed
- passed the same progress through direct, deep, & frame-scoped locator
methods, from finding the target through executing the action/read.
- bounded browser commands for `click()`, `hover()`, `selectOption()`,
`scrollTo()`, `sendClickEvent()`, `centroid()`, `backendNodeId()`,
counts, & element reads.
  - counts also pass progress through their separate selector helpers
- preserved timeout & closed connection/session errors in catches that
previously ignored errors or returned zero. ordinary lookup failures
keep their existing handling.
- used bounded cleanup for temporary browser references. cleanup
failures cannot replace the action's error, & cleanup crossing the
deadline cannot turn the call into success.
- kept click events in their existing order, without waiting for each
response before sending the next event. expiry prevents further
dispatch.

### note: 
progress remains optional during migration. fill, typing, highlighting,
& uploads come in a subsequent PR

# test plan
added tests in `locatorActions.test.ts` using shared setup, controlled
time, & held browser responses to verify:
- delegates, actions, reads, & counting helpers receive the same
progress.
- time spent resolving the target leaves only the remaining budget for
execution.
- stalled commands reject at the deadline; late responses cannot resume
actions. an already-expired call sends no action commands.
- click events retain their order & are sent before earlier responses
arrive. dispatch stops if the deadline passes during the sequence.
- timeout & closure errors propagate through scrolling & counting. valid
empty reads still return false, zero, or an empty string.
- cleanup failures preserve the action error, cleanup crossing the
deadline reports a timeout, & stalled cleanup cannot hold the outer
caller past expiry.
- timing out one call leaves a concurrent unlimited call on the same
locator free to finish.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Makes locator actions and reads respect the caller's timeout so a
stalled browser command can no longer hold a call past its deadline.

- Threads the same progress through direct, deep, and frame-scoped
locator methods, from target resolution through execution.
- Bounds browser commands for click, hover, selectOption, scrollTo,
sendClickEvent, centroid, backendNodeId, count, and element reads;
counts also pass progress through their selector helpers.
- Preserves timeout and closed connection/session errors in catches that
previously ignored them or returned zero.
- Bounds cleanup of temporary browser references so cleanup failures
can't replace the action's error, and cleanup crossing the deadline
can't turn the call into success; cleanup is no longer awaited when an
action is expiring.
- Keeps click events in their existing order without waiting for each
response; expiry stops further dispatch.
- Progress remains optional during migration; fill, typing,
highlighting, and uploads come in a later PR.

<sup>Written for commit e4cef1d.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3024?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

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

# why
`fill()`, `type()`, `highlight()`, & `setInputFiles()` perform multiple
steps within one call. those steps need to share the caller's deadline,
including typing fallbacks, intentional delays, & file preparation.
otherwise, they can continue sending browser commands after the call
times out

# what changed
- passed the progress object downstream through `fill()`, `type()`,
`highlight()`, `setInputFiles()`, & their existing delegates
- made both fill fallbacks reuse the original deadline. timeout or
closed connection/session errors prevent fallback to typing. each
browser reference is released once, including when an early release
stalls.
- bounded text preparation & keyboard commands. typing delays use the
remaining budget & stop on expiry.
- bounded highlight setup, drawing, duration, & refresh waits.
successful `durationMs: 0` calls still leave the highlight visible.
timeout or failure triggers removal, including another removal attempt
if a draw finishes late.
- combined overlay removal & reference release into one bounded cleanup
wait. cleanup failures cannot replace the action error.
- included file normalization & encoding in the budget, with another
check before injection. synchronous encoding can finish after expiry,
but cannot trigger an upload afterward. clearing a file input follows
the same path.

# test plan
extended `locatorActions.test.ts` using shared setup, controlled time, &
held browser responses to verify:
- delegates & nested calls receive the same progress; both fill
fallbacks get only the remaining time & stop on expiry or closure.
- prepared fill inserts text or clears the field correctly, & stalled
early cleanup does not release the same reference twice.
- typing stops during a delay or stalled keyboard command without
sending more characters. unlimited typing can finish.
- highlight duration consumes the budget; zero-duration highlights
remain visible on success. ordinary refresh failures can recover, while
closure stops refreshes.
- late highlight draws are removed. stalled cleanup does not add
sequential waits, & cleanup failures preserve the original error.
- expiry during normalization or encoding prevents file injection.
stalled normalization cannot resume the upload after timeout.
- upload injection respects finite & unlimited budgets; file contents &
metadata are preserved, & an empty file list still clears the input.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes `fill()`, `type()`, `highlight()`, and `setInputFiles()` so every
step in a multi-step call shares the caller's deadline, preventing
browser commands from being sent after the call has timed out.

- Both `fill()` fallbacks reuse the original deadline; timeout or closed
connection errors stop fallback to typing.
- Typing delays use the remaining budget, and highlight refresh waits
and duration consumption are bounded.
- Zero-duration highlights stay visible on success; timeout or failure
triggers removal, including a retry if a draw finishes late.
- File normalization and encoding count against the budget, with a check
before injection; clearing a file input follows the same path.
- After a failed or timed-out action, cleanup runs without blocking the
caller and cannot replace the original error, even when cleanup itself
stalls.
- Extended `locatorActions.test.ts` with controlled time and held
browser responses to cover each deadline path.

<sup>Written for commit 013a3f3.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3026?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# why
this PR adds the `timeout` param to the protocol, & exposes it publicly
in ts. the default timeout is 20 seconds

# what changed
- added optional timeout settings to all 17 terminal locator methods,
including reads. typescript callers can use `click({ timeout: 5000 })`,
`fill("hello", { timeout: 5000 })`, or `count({ timeout: 0 })`.
- started one deadline before frame resolution & passed it through the
whole call. frame readiness, element lookup, typing delays, highlight
duration, & extension-side upload preparation all share that budget.
- aligned typescript response waits with the execution timeout plus
delivery grace. zero disables that response deadline too. long timeouts
avoid the JS timer limit, & timeout errors retain their name & message.
- made the compatibility facade pass its remaining budget to native
locator calls, including zero, instead of dropping timeout options

# test plan
- `locator-timeouts.test.ts` checks every registered locator method
accepts zero & positive timeouts, rejects invalid values, preserves
omission, & keeps existing options working. timeout settings stay
separate from locator identity.
- `runtime-locator-timeouts.test.ts` uses controlled time to verify
every entry point starts its deadline before resolution, applies the
default or override, rejects stalled work, & leaves zero unlimited.
- wrapper, rpc, & package tests cover option forwarding, the public
options type, response deadlines & delivery grace, long timers, &
timeout error details. facade tests check remaining-budget forwarding
for ordinary & frame locators.
- `iframeLocatorReadiness.test.ts` runs against real chrome with
same-process frames & frames in a separate process. it verifies nested
frame readiness & typing share one budget, explicit timeouts can exceed
the old readiness cap, zero waits successfully, & loading a frame after
expiry does not cause a late click.
- `locatorActions.test.ts` exercises highlight & upload cleanup through
the runtime: stalled cleanup preserves an earlier action error & does
not delay timeout rejection.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds a `timeout` option to all terminal locator methods across the
protocol and the TypeScript, Python, and Go SDKs, and updates the v4
docs. The default is 20 seconds, and `{ timeout: 0 }` disables the
deadline.

**What changed**
- One deadline starts before frame resolution and covers frame
readiness, element lookup, typing delays, highlight duration, and upload
preparation; SDK file reading and request delivery happen before that
budget starts.
- Each SDK sets its RPC response deadline to the execution timeout plus
a delivery grace, with `0` disabling it; long timeouts work around
per-language timer limits.
- The Playwright compatibility facade forwards its remaining budget to
native locator calls, including zero.
- Go's `SetInputFiles` now takes a file-input slice, and Python rejects
non-finite timeout values.
- Timeout errors retain the `TimeoutError` name and message.

<sup>Written for commit 0d7d1ec.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3033?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
…#3081)

# why
`screenshot()` timeouts could stop the caller waiting while downstream
functions (eg, preparation & mask lookup) continued without a shared
deadline. `pdf()` also used separate timeout handling. this PR makes
both `screenshot()` & `pdf()` use the `progress` tracker.
# what changed
- used shared progress for screenshots & pdfs, starting before queueing.
nested calls reuse their parent's remaining time.
- passed screenshot progress through preparation, mask lookup, tab
activation, & capture. mask lookup & its paint delay consume the same
budget.
- the timeout/deadline are checked before starting further browser
commands, including when the timeout timer has not fired yet.
already-issued commands can still finish.
- the page is kept unavailable until pending work & restoration finish.
stalled preparation or cleanup does not block other tabs; activation &
capture remain serialized across the browser.
- registered restoration before setup starts & released all resolved
mask nodes, including nodes skipped after expiry. cleanup cannot replace
an earlier capture error.
- preserved defaults: screenshots are unlimited, pdfs use 30 seconds, &
zero disables either timeout

# test plan
- `screenshotUtils.test.ts` checks that queued requests cannot start
after expiry, stalled browser commands cannot trigger later steps, &
captures stay blocked until recovery finishes. it also checks that
stalled page setup or cleanup leaves other tabs usable.
- `pdf.test.ts` checks shared queue ordering, time spent queueing
counting toward the deadline, inherited deadlines, defaults, & zero.
late print or screenshot responses cannot release the page before
pending work finishes.
- added preparation tests in `pdf.test.ts` for mask lookup consuming the
screenshot budget, late mask measurements being restored, skipped nodes
being released, & cleanup preserving the original capture error. further
tests prevent animation changes or style insertion after expiry,
including before the timer fires.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Makes `screenshot()` and `pdf()` use the shared `progress` tracker so
their deadline applies across every downstream step, nested calls
inherit the parent's remaining budget, and a timed-out capture can no
longer leave scheduled work running or free the page early.

- The deadline is checked before each browser command, including before
the timeout timer fires; commands already issued still finish.
- Late CDP responses, stalled setup, and stalled cleanup keep the page
lock held, blocking subsequent captures while leaving other tabs usable.
- Mask lookup and its paint delay consume the same budget as the capture
itself, and all resolved mask nodes are released even when skipped after
expiry.
- Cleanup cannot overwrite an earlier capture error.
- Defaults preserved: screenshots are unlimited, pdfs use 30 seconds,
and zero disables either timeout.

<sup>Written for commit ad86581.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3081?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
## Summary
- Move the observability documentation change out of #3045.
- Document that omitting telemetry disables export and remove the
placeholder-endpoint TODO.

Stacked on #3045; this PR contains only the documentation change. Merge
after #3045.

## Validation
- git diff --check passes.
- Verified #3045 no longer changes packages/docs.
- Verified the combined branches reproduce the original tree exactly.
- No runtime tests run for this docs-only split.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Documents opt-in telemetry behavior in the observability config docs:
omitting the `telemetry` option now disables export, and the outdated
placeholder-endpoint TODO comment is removed.

<sup>Written for commit 13b02f1.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3054?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

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

See browserbase/stagehand-website#199

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
# why
`page.snapshot()` had no timeout param, nor did some of its internal
helpers. the helpers that it calls are also called by other functions in
the codebase that require timeout handling. this PR wires the `progress`
object through the shared downstream helpers, and also exposes a user
facing `timeout` param in `page.snapshot()`

# what changed
- added a snapshot timeout in milliseconds to typescript, python, & go.
omission or `0` keeps snapshots unlimited.
- made one deadline cover frame readiness, element lookup, document &
accessibility tree reads, & frame traversal
- allowed internal snapshot calls to reuse a caller's remaining time &
timeout error instead of starting a new budget.
- stopped retries, fallback reads, & further frame traversal after
expiry. temporary element references are released, including those
returned after timeout. already-issued browser commands can still
finish.
- updated sdk response waits to allow the requested timeout plus
delivery grace, with no response deadline for unlimited snapshots

# test plan
- `capture.test.ts` checks public & inherited deadlines, unlimited
snapshots, expiry preventing further reads or fallback, & cleanup of
ignored elements.
- `domTree.test.ts` & `a11yTree.test.ts` check that expired reads cannot
retry or fall back, including when the deadline timer has not fired yet.
- `focusSelectors.test.ts` checks that both selector lookup paths
release element references returned after timeout. focused accessibility
tests also check reference cleanup after successful reads.
- protocol & sdk tests cover omitted, zero, positive, & invalid
timeouts, option forwarding in all three sdks, & response waits. the
typescript package test checks that the published snapshot options
include the new field.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds an optional `timeout` param to `page.snapshot()` so callers can
bound the entire snapshot operation. Omitted timeouts now default to 20
seconds instead of running unlimited.

- Exposes `timeout` in the TypeScript, Python, and Go SDKs; passing `0`
keeps snapshots unlimited.
- Uses one deadline for frame readiness, element lookup,
DOM/accessibility tree reads, and frame traversal, and lets snapshots
reuse the caller's remaining time instead of starting a new budget.
- Stops retries, fallback reads (including focus-scope and
ignore-locator fallback), and further frame traversal after expiry,
releasing temporary element references even when they return after the
timeout.
- SDK response waits now add delivery grace to the requested timeout and
skip the deadline entirely for unlimited snapshots.

<sup>Written for commit 4054cdb.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3083?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
Browse 0.10.0 uploaded successfully in [the Release
workflow](https://github.com/browserbase/stagehand/actions/runs/35798682312/job/106985029323),
but the following tag step saw a temporary npm 404 and returned
`unpublished`. The job finished green without pushing the release tag.

Push the validated local tag that Changesets creates after a successful
upload without requiring immediate registry visibility. When no local
tag exists, retain the registry check and original version-bump commit
guard for recovery.

Validation: reproduced the failure with a real HTTP server returning 404
and a bare Git remote, then verified the fix; all 67 release tests,
tooling typecheck, targeted lint/format, and diff checks pass. The diff
changes only the helper and its existing regression test.

The current `browse@0.10.0` tag has been repaired separately to the
exact commit verified in npm provenance. No npm upload or package
version change is part of this PR.


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes the release workflow so an existing local Browse tag is pushed
without waiting for npm registry reads to converge. Previously a
temporary 404 from npm during propagation made the tag step return
`unpublished`, finishing green without creating the release tag. When no
local tag exists, the registry check and the version-bump-commit guard
still run as before.

<sup>Written for commit 345a953.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3015?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>

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

# why

Eve agents need an installable Browserbase extension with persistent
browser state and predictable cleanup. This adds the native Stagehand V4
integration as `@browserbasehq/eve` 0.2.

# what changed

- Add `browserbase__run`, `browserbase__snapshot`, and
`browserbase__screenshot` through Eve's native extension API.
- Share one Browserbase session across calls, recover unhealthy
sessions, and release owned resources on explicit close. The next call
can start a fresh session.
- Bundle the shared browser facade, including the cleanup hook and
sanitized errors used by Eve's session owner, and add package build,
release, and Changeset configuration.
- Support Eve 0.68.x, resolve environment credentials when the browser
starts, and inherit Browserbase proxy defaults unless explicitly
overridden.

The [build
script](https://github.com/browserbase/stagehand/blob/ab25295e96476ee3c13c19a8e936348491da0e04/packages/integrations/eve/scripts/stage-facade.mjs)
copies four shared Core files byte-for-byte into Eve's generated,
gitignored source directory. `runtime.ts`, `contract.ts`, and
`redact.ts` are unchanged from the PR base. `tools.ts` adds the host
cleanup hook and error handling; the Eve tool wrappers adapt the
existing Stagehand example.

The [previous implementation in
browserbase/integrations](https://github.com/browserbase/integrations/tree/b7bc81c6fd4e089ab0c0df2b82529b200739e458/packages/eve-browserbase)
already uses Stagehand V4. This PR keeps its npm package identity but
changes the tool API and session lifecycle; none of the 17 tracked Eve
package files is byte-identical to that implementation. The main
implementation review areas are session ownership/recovery, the shared
cleanup/error changes, and packaging/release wiring. Eve's built-in
`web_search` and `web_fetch` remain available;
[#2822](#2822) adds
optional Browserbase replacements. The separate MCP lifecycle change is
in [#3078](#3078); this
native extension does not depend on it. Documentation is in
[#3079](#3079). Merge that
PR before publishing 0.2 so the npm package includes the updated README.

# test plan

Checked after the `main` update at
[`ab25295e9`](ab25295).

Refreshed against current `main`, preserving upstream dependencies and
Eve’s named catalog. The URL-matching test now resolves Playwright Core
through its declared Playwright dependency, so the new examples’ MCP
dependency cannot change which version it tests.

| Command / flow | Observed output | Coverage |
| --- | --- | --- |
| Shared facade build, typecheck and unit tests; Pi
build/typecheck/tests | 136 facade tests and 3 Pi tests passed | Shared
hook/error changes and existing native consumer |
| `CHROME_PATH=<Chrome binary> pnpm --filter
@browserbasehq/stagehand-integrations test:browser` | 6 tests passed |
Browser compatibility against local fixtures |
| Eve package typecheck and `test:unit` | Typecheck passed; 39 tests
passed | Native session ownership, credentials and tool behavior |
| Fresh tarball, strict `publint`, external Eve 0.68.0 consumer | All
passed; `eve build` passed with `BROWSERBASE_API_KEY` unset |
Installable package and credential-free builds |
| Installed SDK and browser extension compared with fresh local build |
Byte-identical; Eve resolves the same SDK | Smoke tests cover the SDK
and browser extension from this branch |
| Packed lifecycle probe and real `eve eval --strict --skip-report
--timeout 300000` | 8/8 gates passed; persistent state, error recovery,
snapshot-ID navigation, 193,444-byte PNG and close/reopen passed |
Native tools with real Browserbase sessions on public Example
Domain/IANA pages |
| Independent session audit | All 5 sessions `COMPLETED`, including the
preliminary harness run; no fallback release needed | Owned-session
cleanup |
Adds [Amel Bajramovic](https://github.com/bosniankicks) to the
contributors list in the README Acknowledgements section.
…2893)

Bounds capture and RPC/batch waits. Two consecutive capture deadlines
are recoverable; a third latches terminal session loss, while a
successful tool call resets the counter. Late completion cannot
overwrite newer snapshot IDs.

Terminal loss rejects queued calls without dispatch. Actions are never
automatically replayed. Regressions cover bounded timeout inputs, late
completion, counter reset, screenshot transport and first-loss handling.

`experimentalBatch` keeps its single `timeout` option (the callback
deadline the browser-side executor enforces). The client bounds the
whole round trip at `timeout` plus a 15-second batch grace
(`CALLBACK_BATCH_CLIENT_GRACE_MS`), because the executor's timeout is
cooperative and can be reported late. A batch that gets no response by
then rejects with `StagehandBatchTimeoutError`; RPC response deadlines
throw `RPCResponseTimeoutError`. Earlier revisions also exposed that
local deadline as a `clientTimeoutMs` option. Nothing passed it, so it
is removed; the default it produced is unchanged.

The facade now calls `page.snapshot()` with `timeout: 0`. Snapshot
gained a 20-second default on main, which fired before the facade's
120-second capture deadline, so a slow snapshot failed as an ordinary
tool error and never counted toward terminal session loss.

Preserves provider/session/age/timeout diagnostics through the host,
checks screenshot byte limits before decoding, and isolates failures in
diagnostic observers. The typed RPC timeout error lives in a focused
public module, keeping internal RPC helpers outside the SDK public-field
contract.

Validation: 120 focused tests and 47 SDK AST/release guards,
SDK/core/eval typechecks, SDK build/publint, and merged
ownership/capture regression checks. At `b14e4ec95`: 345 SDK unit tests
and 156 facade unit tests pass, with SDK and facade typechecks and the
format check clean.

Stack base: `main`. Review this PR relative to its immediate
predecessor.

Reviewer entry points:

-
[`packages/integrations/core/src/facade/tools.ts`](https://github.com/browserbase/stagehand/blob/b14e4ec95e40a44fb9c0ec87383b060a10d4fab6/packages/integrations/core/src/facade/tools.ts)
-
[`packages/sdk-ts/src/batch.ts`](https://github.com/browserbase/stagehand/blob/b14e4ec95e40a44fb9c0ec87383b060a10d4fab6/packages/sdk-ts/src/batch.ts)
-
[`packages/integrations/core/tests/facade-tools.test.ts`](https://github.com/browserbase/stagehand/blob/b14e4ec95e40a44fb9c0ec87383b060a10d4fab6/packages/integrations/core/tests/facade-tools.test.ts)


The CLI startup fix is now included in the parent (#2892), so this PR
focuses on capture/RPC deadlines and recovery. Current main is
incorporated, preserving both the timeout exports and the
runtime-compatibility exports.


Readiness: CI is running on `b14e4ec95e`; it last passed on `65d9c911b7`
([run](https://github.com/browserbase/stagehand/actions/runs/36969426716)).
The one cubic comment (snapshot timeout) is fixed and resolved. Human
review status is unchanged.










Current open stack: #2893 → #2894 → #2902 → #2903 → #2889 → #2904 →
#2905 → #2906 → #2907.
seanmcguire12 and others added 22 commits October 18, 2026 13:26
# why
the protocol now lets the worker ask an SDK to make an HTTP request. the
TS SDK needs an implementation that can receive that request, send it
over HTTP, & return the response while the original Stagehand call is
still waiting

this PR adds that transport using native `fetch` & the existing RPC
connection

# what changed
- added a connection snapshot that resolves the bb key, session, & API
endpoint using existing browser-factory precedence, regions, & URL
overrides
- added an executor for Gateway, cache read, & cache write requests. it
adds the bb headers, sends the supplied body, & returns the complete
response.
- kept each execution to one HTTP attempt. HTTP errors & redirects are
returned to the worker; retry decisions remain with the worker.
- carried cancellation & the remaining timeout through response body
buffering.
- added RPC handler registration & disposal. cancellation targets one
request, disconnects stop pending work, & disposal removes handlers
without closing the shared RPC connection.

# test plan
- shared fixtures verify endpoint selection, connection precedence, &
headers.
- local HTTP tests cover request bodies, compressed & empty responses,
redirects, HTTP/network failures, cancellation, & timeouts during body
delivery.
- RPC tests verify a reverse request completes while a Stagehand call is
pending, equal request IDs on separate connections stay independent, &
cleanup stops active HTTP work.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds an HTTP transport to the TS SDK so the worker can ask the SDK to
make Browserbase Gateway and cache requests while the original Stagehand
call is still pending.

- Resolves the Browserbase connection from existing browser-factory
precedence, region, and API URL overrides, and snapshots it per
connection.
- Executes `gateway.responses`, `cache.get`, and `cache.set` over native
`fetch`, adds the Browserbase headers, and returns the response without
retrying.
- Carries cancellation and the remaining timeout through body buffering;
the worker owns retry decisions.
- Registers RPC request and cancel-notification handlers and aborts
active HTTP on disposal without closing the shared RPC connection.

<sup>Written for commit d05a8d5.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3205?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3205?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3205&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# why
the protocol now lets the worker ask an SDK to make an HTTP request. the
python SDK needs an implementation that can receive that request, send
it over HTTP, & return the response while the original Stagehand call is
still waiting

this PR adds the python implementation of #3205 using the SDK's existing
`httpx` dependency & RPC connection

# what changed
- added a connection snapshot with the same browser-factory precedence,
regional endpoints, & API URL override behavior as the TypeScript
implementation
- added one HTTP attempt per Gateway, cache read, or cache write
request. the executor applies bb headers & returns the buffered status,
headers, & body, including HTTP errors & redirects.
- used the caller's remaining timeout through body buffering, without
adding an `httpx` default timeout or a second retry loop
- added request & cancellation handlers to the existing RPC connection.
explicit request cancellation, task cancellation, disconnect, & disposal
stop the corresponding HTTP work & release its resources

# test plan
- shared fixtures & connection tests cover endpoint selection,
precedence, & snapshots remaining unchanged after caller inputs are
mutated.
- local HTTP tests cover header precedence, response decoding,
redirects, network failures, & deadlines before headers and during body
delivery.
- RPC tests cover requests during a pending batch call, cancellation,
duplicate IDs, independent connections, & handler disposal

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds the Python SDK implementation of the Browserbase HTTP transport,
letting a worker ask the SDK to make HTTP requests over the RPC
connection while the original Stagehand call is still pending.

- Resolves a Browserbase connection snapshot (API key, API URL, session
ID) with the same precedence, regional endpoints, and override behavior
as the TypeScript SDK.
- Executes one `httpx` request per Gateway, cache read, or cache write,
returning the buffered status, headers, and body — including HTTP errors
and redirects — with no retry loop or `httpx` default timeout.
- Uses the caller's remaining timeout through body buffering, without
adding a second deadline.
- Adds request and cancellation handlers to the RPC connection;
cancellation, task cancellation, disconnect, and disposal stop in-flight
HTTP work and release resources.

<sup>Written for commit 9997de8.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3206?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3206?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3206&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# why
the protocol now lets the worker ask an SDK to make an HTTP request. the
golang SDK needs an implementation that can receive that request, send
it over HTTP, & return the response while the original Stagehand call is
still waiting

this PR adds the python implementation of #3205 using Go's standard
`net/http` package

# what changed
- added a connection snapshot that preserves browser-factory precedence,
regional endpoints, & API URL overrides.
- added an executor for Gateway, cache read, & cache write requests. it
applies bb headers & returns the buffered HTTP response, including
errors & redirects
- prevented automatic replay of these POST requests so the worker
continues to own retry decisions.
- carried context cancellation & the remaining timeout through response
body reads, & closed response bodies and idle connections during
cleanup.
- added RPC registration & cancellation by request ID. cancellation
notifications are handled directly, so a busy log callback cannot delay
them

# test plan
- shared fixtures & connection tests cover endpoint selection, header
precedence, & independent connection snapshots.
- local HTTP tests cover gzip/text decoding, empty bodies, redirects,
network failures, & cancellation or timeout while reading a response.
- transport tests verify a dropped connection does not replay a received
POST & that response bodies are closed.
- RPC tests cover concurrent requests, matching IDs on separate
connections, disconnects, disposal, & cancellation while log delivery is
blocked; race checks exercise the lifecycle paths.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds HTTP transport to the Go SDK so the Browserbase worker can request
HTTP calls while the original Stagehand call is still waiting, matching
the Python SDK implementation.

**New Features**
- Snapshots connection settings, including worker-claimed API key
precedence, regional endpoints, and API URL overrides.
- Handles Gateway responses plus cache get and set operations, returning
buffered responses with headers, errors, and redirects preserved.
- Prevents automatic replay of POST requests so the worker keeps retry
decisions.
- Propagates context cancellation and remaining timeouts through
response body reads and closes bodies and idle connections on cleanup.
- Registers RPC handlers per request ID, applies cancellation
notifications directly without waiting on busy log callbacks, and drops
responses issued during or after disposal and disconnect.

<sup>Written for commit 880517f.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3207?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3207?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3207&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

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

# why
this PR connects the worker's model gateway & cache clients to the new
RPC transport. aisdk continues to build gateway requests, interpret
responses, & decide when to retry

# what changed
- added a worker adapter that sends `browserbase.request` & reconstructs
a native `Response` or the corresponding transport error for existing
callers
- added cancellable RPC sends using the existing request ID, including
cleanup on abort, disconnect, & late replies
- routed Gateway requests through the adapter when initialization
selects client transport. automatic model selection, explicit headers, &
AI SDK retry behavior remain in the worker
- routed cache reads & writes through the same adapter. each cache
request keeps one five-second budget across serialization, RPC, & HTTP
response buffering
- preserved direct-provider inference, custom LLM callbacks, batch
overrides, & cache failure fallback

# test plan

- response-adapter tests cover HTTP status & headers, empty bodies,
transport errors, cancellation ordering, disconnects, & late replies.
- Gateway tests exercise both transports against the same header,
response, retry, & backoff expectations.
- cache tests cover hits, misses, read/write failures, & the shared
timeout budget without adding retries
- runtime tests cover ordinary & batch calls, custom callbacks, model
overrides, close/drain behavior, & disconnects during inference

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Connects the worker's Browserbase Model Gateway and cache clients to the
new RPC transport, so inference and cache HTTP requests are sent by the
connected SDK instead of direct HTTP from the worker.

- Adds a worker adapter that sends `browserbase.request` over RPC and
reconstructs a native `Response` or the matching transport error for
existing callers.
- Makes RPC sends cancellable via the existing request ID, with cleanup
on abort, disconnect, and late replies.
- Routes Gateway requests through the adapter when initialization
selects client transport; AI SDK retry and backoff behavior, explicit
headers, and automatic model selection stay in the worker.
- Routes cache reads and writes through the same adapter, keeping one
shared five-second budget per request across serialization, RPC, and
response buffering.
- Preserves direct-provider inference, custom LLM callbacks, batch
overrides, and cache failure fallback.
- Rebuilds the extension assets bundle, removes duplicated gateway
tests, and updates the client/server version compatibility tests.

<sup>Written for commit 015eaf9.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3208?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3208?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3208&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# why
this PR wires the HTTP transport into sdk initialization, so that
gateway & cache requests are sent by the connected TS, python, or Go
client

# what changed
- registered bb request handlers before worker initialization in all
three SDKs, so requests can run during initialization, ordinary calls,
batch, & close
- resolved bb connection settings in the SDK. worker initialization now
sends transport availability & browser session metadata; public
connection options remain accepted & validated by each SDK
- preserved browser-factory precedence, regional endpoints, API URL
overrides, direct-provider model configuration, & custom callback
registration
- kept handlers available while the worker finishes active calls, then
disposed them on close or failed initialization

### note: 
the client transports return redirect responses to the worker instead of
following them automatically. the previous worker transport followed
redirects

# test plan
- SDK lifecycle tests exercise requests before initialization completes,
during batch, & while close is pending, plus cleanup after
initialization failure.
- real Chromium tests in each SDK cover ordinary & batch Gateway calls,
cache hits, custom callbacks, per-call model overrides, & cache failure
fallback.
- direct-provider configuration is covered alongside a cache hit that
skips inference.
- local HTTP fixtures verify operation counts, endpoint selection, &
session settings without requiring live bb or model services.
- compatibility tests cover rejecting a worker that predates this
transport & the transitional worker continuing to accept older clients.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Routes Browserbase Model Gateway and cache HTTP requests through the
connected TypeScript, Python, and Go SDK clients instead of the worker,
so the client's connection is used during initialization, ordinary
calls, batch, and close.

**Behavior changes**
- Each SDK now resolves and validates Browserbase connection settings;
worker init receives transport availability and browser session metadata
instead of the API key and URL.
- Browser-factory key precedence, regional endpoints, API URL overrides,
direct-provider model configuration, and custom callbacks are preserved.
- Browserbase request handlers stay registered while the worker finishes
active calls and are disposed on close or failed initialization.
- Client transports return redirect responses to the worker instead of
following them; the previous worker transport followed redirects.
- API URLs must use an HTTP or HTTPS scheme, include no query string or
fragment, and omit a trailing `/v1`.

**Compatibility**
- Clients now require protocol 2.2.0; older workers are rejected, while
a 2.2.0 worker still accepts older clients.

<sup>Written for commit fb4a78c.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3209?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3209?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3209&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# why
this PR makes the connected SDK the only HTTP transport

# what changed
- removed the worker's direct Gateway/cache HTTP execution & the
endpoint helper used by that path
- simplified Gateway & cache setup around the client request adapter,
removing transport-selection branches & unused context fields
- removed top-level `apiKey` & `apiUrl` from worker initialization. the
public TypeScript, Python, & Go constructor options still accept them &
resolve them in the SDK

# test plan
- schema & actual RPC initialization tests reject the removed fields
while accepting client transport, direct-provider models, & custom model
references.
- Gateway/cache tests cover client routing, retries, cancellation, cache
budgets, & unavailable or disconnected transport without falling back to
worker HTTP.
- SDK tests verify public connection options remain accepted &
incompatible protocol majors are rejected.
- cross-SDK Chromium tests exercise the final route with the regenerated
extension; generated-model & bundled-asset checks verify the artifacts
match.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Makes the connected SDK the only HTTP transport for Browserbase Model
Gateway and cache requests by removing the worker's direct HTTP
execution path.

- Removes the worker's direct Gateway/cache HTTP execution and its
endpoint helper, along with top-level `apiKey` and `apiUrl` from worker
initialization.
- Simplifies Gateway and cache setup around the client request adapter
by removing transport-selection branches and unused context fields.
Regenerates the Go SDK extension bundle and updates SDK parity checks.
- Public TypeScript, Python, and Go constructor options still accept
`apiKey` and `apiUrl` and resolve them in the SDK.

**Breaking Changes**
- Worker protocol now rejects `apiKey` and `apiUrl` init options and
bumps to protocol 3.0.0, which incompatible clients and workers reject
with `protocol-major-mismatch`.

<sup>Written for commit ef3892a.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3210?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3210?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3210&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# why
to address comments on earlier PRs in this stack

# what changed
- aligned request-header handling across SDKs. HTTP clients supply host
& transfer headers; SDKs supply the Browserbase key & Gateway session
header. ordinary application headers remain supported. malformed headers
fail before HTTP dispatch, so Go no longer reports them as retryable
network failures.
- preserved non-ASCII response header bytes in Python so the worker can
reconstruct the response without rejecting its headers.
- cancelled pending TypeScript Browserbase requests when the browser
closes, including when the socket does not deliver another close event.
- reused Python HTTP connections across requests on the same RPC
connection, closing the pool after pending requests are cancelled during
cleanup.
- skipped cache request bodies larger than 25 MB (25,000,000 UTF-8
bytes) before sending them over RPC. normal execution continues. an
oversized read reports `payload_too_large` & skips the later write; an
independently oversized write is skipped without replacing the read's
metadata.
- reported cache read deadlines as `timeout`, keeping `read_failed` for
other failures & preserving cancellation of the user's operation.

# test plan

- shared header fixtures & local HTTP tests cover filtering, malformed
input, preserved application headers, & Python response header decoding.
- lifecycle tests cover explicit browser close, cancellation, Python
connection reuse, disconnects, & pool cleanup.
- cache tests cover the exact size boundary, multibyte UTF-8, skipped
reads/writes, normal execution after a skip, timeouts, & caller
cancellation.
- protocol & SDK tests cover valid initialization, missing browser
metadata, removed init fields, & rejection before dispatch. generator
checks verify the validation survives regeneration

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Aligns Browserbase HTTP transport behavior across the Go, Python, and
TypeScript SDKs so header validation, connection handling, cancellation,
and cache error semantics are consistent. Malformed request headers now
fail before HTTP dispatch instead of surfacing as retryable network
failures, and client Browserbase init params now require browser
metadata and reject `api_key` and `api_url` since the browser handle's
connection supplies those.

**What changed**
- SDKs validate request headers and strip host, content-length,
hop-by-hop, and forwarding headers; they supply `x-bb-api-key`, and for
`gateway.responses` also `x-bb-session-id` and a default
`Authorization`.
- Python preserves non-ASCII response header bytes as Latin-1 so the
worker can reconstruct the response without rejecting its headers.
- TypeScript cancels pending Browserbase requests when the browser or
context closes, including when the socket never emits a close event;
Python reuses one HTTP connection per RPC connection and closes the pool
during cleanup.
- Cache requests whose serialized body exceeds 25,000,000 UTF-8 bytes
are skipped with `payload_too_large`; an independently oversized write
is skipped without replacing the read metadata, and cache read timeouts
are reported as `timeout` rather than `read_failed`.

<sup>Written for commit 1900e78.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3229?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3229?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3229&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

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

Stagehand's extension opens its own CDP connection to the browser, and
it is handed the URL the Python client connected with. That only works
when the client and the browser can use the same address.

Sometimes they can't. Our case: the client runs in a server process and
reaches a sandboxed Chrome through an authenticated gateway,
`wss://<gateway>/.../cdp?api_key=...`. The extension, running inside
that Chrome, should dial the browser's local endpoint
(`ws://127.0.0.1:<port>/devtools/browser/<id>`). Using the gateway URL
would hand the gateway's credentials to the browser, which loads
arbitrary pages, and send every extension command out and back in
through the gateway. Today the only workaround is overriding the private
`Stagehand._worker_init_params`.

## What

```python
browser = await local_browser.connect(
    cdp_url="wss://gateway/cdp?api_key=...",
    extension_cdp_url="ws://127.0.0.1:9300/devtools/browser/<id>",
)
stagehand = await Stagehand.create(browser=browser)
```

- `local_browser.connect` takes an optional `extension_cdp_url`, which
must be a `ws://` or `wss://` URL with a host.
- It is carried on the claimed browser's worker metadata, and
`Stagehand.create` sends it as the init param `browser_cdp_url` in place
of the client's URL.
- When it is unset, behaviour is unchanged.
- Python SDK only, with a minor changeset. The TypeScript SDK has the
same assumption and could take the same option; happy to follow up.

## Tests

- New tests cover the init param, connect carrying the value through,
the default, and rejection of non-WebSocket URLs.
- `ruff format --check`, `ruff check`, `ty check` and `generate.py
--check` pass.
- `pytest`: 793 passed.
`test_official_api_routes_through_and_never_closes_a_caller_http_client`
fails with and without this change in my checkout, because it needs the
extension built in `packages/extension/dist`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds an optional `extension_cdp_url` to `local_browser.connect` in the
Python SDK so Stagehand's extension can dial a different CDP WebSocket
than the client's, when the client reaches Chrome through a proxy or
gateway the extension cannot use.

- When set, `Stagehand.create` sends it as the init param
`browser_cdp_url` in place of the client's URL; when unset, behavior is
unchanged.
- The value must be a `ws://` or `wss://` URL with a host; invalid
schemes, ports (including 0), or missing hostnames raise a validation
error.
- Python SDK only, with a minor changeset; the TypeScript SDK could take
the same option in a follow-up.
- New tests cover the init param, metadata carrying the value through,
the default, and rejection of invalid URLs. `pytest` reports 793 passed;
`test_official_api_routes_through_and_never_closes_a_caller_http_client`
fails with and without this change because it needs the extension built
in `packages/extension/dist`.

<sup>Written for commit 48a3789.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3252?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3252?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3252&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

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

---------

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
Co-authored-by: Sydney Runkle <sydney@langchain.dev>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ect()` in TS (#3253)

# why
- this allows users to specify a CDP url that the extension will use for
its loopback/in-browser connection
# what changed
- exposed `extensionCdpUrl` on `localBrowser.connect()`
# test plan
- added unit tests ensuring the URL gets correctly propagated through
the protocol

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds an optional `extensionCdpUrl` param to `localBrowser.connect()` so
callers can tell Stagehand's extension which CDP WebSocket to dial.
Previously the extension always dialed the same URL the client connected
with, which could hand gateway credentials to the browser and route
extension traffic through the gateway.

When unset, behavior is unchanged. The value must be a `ws://` or
`wss://` URL with a host and a port between 1 and 65535; invalid values
are rejected with a validation error before any connection is attempted.

<sup>Written for commit 9bf9abf.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3253?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3253?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3253&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

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

# why
- this allows users to specify a CDP url that the extension will use for
its loopback/in-browser connection
# what changed
- exposed `ExtensionCDPURL` in `LocalBrowserConnectOptions`
# test plan
- added unit tests ensuring the URL gets correctly propagated through
the protocol

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds an optional `ExtensionCDPURL` field to `LocalBrowserConnectOptions`
in the Go SDK, letting users set the CDP WebSocket URL the extension
uses for its in-browser connection independently of the client's CDP
URL. When empty, the client's CDP URL is used as before.

- Validates `ExtensionCDPURL` is a `ws://` or `wss://` URL with a valid
host and port before connecting (including rejecting port `0`).
- Propagates the URL to the extension init; falls back to the client's
CDP URL when unset.
- Includes unit tests for validation and propagation.

<sup>Written for commit 32ce206.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3254?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3254?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3254&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# why
- before this, if a stagehand instance was closed, then recreated, and a
CDP url was provided in `localBrowser.connect()`, the provided CDP url
would not get used: the extension would keep using the old one
# what changed
- the extension now stores the CDP URL associated with the extension’s
browser connection
- the extension will replace the connection when initialization supplies
a different URL
- it will reuse reuse a connection when the URL matches or is omitted
# test plan
- added a test that initializes with URL A, closes the Stagehand
instance, then initializes with URL B and verifies the old connection
closes before the new one opens.
- added a test that omits the URL on reinitialization and verifies the
existing connection is reused.
- added a test that makes connection replacement fail, verifies the
runtime stays idle with no connection, then retries successfully.
- updated the active-instance test to supply a different URL and verify
reinitialization is still rejected

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Fixes the extension keeping a stale browser connection when a Stagehand
instance is closed and recreated with a different CDP URL in
`localBrowser.connect()`.

- The runtime now stores the CDP URL for the active browser connection
and, on re-initialization, replaces the connection when the URL differs
and reuses it when the URL matches or is omitted.
- When replacement fails, the runtime stays idle so re-initialization
can be retried.
- Adds a changeset and updates the bundled extension assets.

<sup>Written for commit 6fe991e.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3257?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3257?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3257&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# what changed
- adds an extension cdp url example in browser configuration page

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Documents the `extensionCdpUrl` browser option in the configuration page
with TypeScript, Python, and Go examples, showing how to give the
extension its own CDP WebSocket URL when the client connects through a
proxy or gateway. The examples use a token-based gateway URL, and the
docs also cover validation rules and the fallback behavior when the
option is omitted.

<sup>Written for commit 60b0380.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3259?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3259?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3259&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

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

changes pulled in from #3224 , thanks @sydney-runkle for the contrib!
## Why

`local_browser.connect` takes only a URL. To reach a CDP endpoint behind
an authenticated gateway, the credentials have to go in the query
string. URLs leak easily: into exception messages, tracebacks and proxy
logs. So callers end up redacting them by hand. Playwright solves this
with `connect_over_cdp(..., headers=...)`.

## What

```python
browser = await local_browser.connect(
    cdp_url="https://gateway/.../cdp",
    headers={"X-Api-Key": "..."},
)
```

- `headers` are sent with the `/json/version` request and with the CDP
WebSocket handshake (`websockets`' `additional_headers`).
- They follow the advertised `webSocketDebuggerUrl` only when it's on
the same host and port as `cdp_url`, so a gateway can't redirect
credentials elsewhere. They're never passed to the extension.
- Names must be RFC 9110 tokens, and values may only contain visible
characters, spaces and tabs, so CR/LF injection is rejected.
`LocalBrowserConnectOptions` sets `hide_input_in_errors` so a rejected
credential isn't echoed in the `ValidationError`.
- When `headers` is unset, nothing changes: `CDPClient.connect` isn't
even passed the argument.
- Python SDK only, with a minor changeset. Independent of #3223; the two
compose.

## Tests

- New tests cover headers on `/json/version`, resolve passing them
through, the same-host rule (6 cases), connect forwarding them only when
given, and rejection of unsafe names and values without echoing them.
- The existing `test_cdp_client` fakes now accept the new keyword
argument.
- `ruff format --check`, `ruff check`, `ty check` and `generate.py
--check` pass.
- `pytest`: 798 passed.
`test_official_api_routes_through_and_never_closes_a_caller_http_client`
fails with and without this change, because it needs the built extension
in `packages/extension/dist`.
- **Live:** against a LangSmith browser sandbox's CDP gateway,
`/json/version` with an `X-Api-Key` header returned a credential-free
WebSocket URL, the header-authenticated WebSocket reached Chrome
(`Browser.getVersion`), and the same WebSocket without the header was
refused.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds optional `headers` to `local_browser.connect` in the Python SDK so
callers can authenticate against CDP gateways without putting
credentials in the URL.

- Headers go to the `/json/version` request and the CDP WebSocket
handshake, and only to endpoints on the same host and port as `cdp_url`;
redirects off-host or to insecure endpoints are refused rather than
followed. Headers are never passed to the extension.
- Header names and values are validated against RFC 9110 rules, and
validation errors never echo header values since they may be
credentials.
- Discovery that returns 401 or 403 now fails immediately with a message
pointing at gateway credentials instead of retrying.
- When `headers` is unset, nothing changes: the keyword argument isn't
passed to `CDPClient.connect`, and redirect behavior is unchanged.

<sup>Written for commit 564690c.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3260?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3260?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3260&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

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

---------

Co-authored-by: Sydney Runkle <sydney@langchain.dev>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
## why

port the Python support from #3260 to TypeScript so callers can
authenticate against CDP gateways without putting credentials in the URL

## what

```typescript
const browser = await localBrowser.connect({
  cdpUrl: "https://gateway/.../cdp",
  headers: { "X-Api-Key": "..." },
});
```

Headers are sent with HTTP discovery and the client’s CDP WebSocket
handshake. They only reach endpoints on the same host and effective
port, without downgrading TLS, and are never passed to the extension.
Unsafe HTTP redirects are rejected; Node’s WebSocket transport already
rejects redirects.

Header validation rejects unsafe names, non-ASCII values, and leading or
trailing whitespace without exposing credentials in errors. Discovery
fails immediately on HTTP 401/403, and optional debug logging explains
when headers are withheld. Includes a minor changeset.

## test plan

- Network tests cover HTTP discovery and WebSocket header forwarding,
allowed HTTP redirects, blocked redirects, and connections with omitted
or empty headers.
- Regression tests cover header validation and error redaction,
host/port/TLS boundaries, safe diagnostics, immediate 401/403 failures,
and retries for transient failures.
- Browser factory tests verify headers stay out of extension
initialization metadata.
- All 159 targeted tests, TypeScript type checking, and lint checks
pass.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds a `headers` option to TypeScript `localBrowser.connect()`, porting
the existing Python support so CDP gateways can be authenticated without
putting credentials in the URL.

**New Features**
- Headers are sent with HTTP discovery and the CDP WebSocket handshake;
they only reach endpoints on the same host and effective port, without
downgrading transport security.
- Unsafe HTTP and WebSocket redirects are rejected, and gateway
responses with HTTP 401/403 fail fast with instructions to check
credentials.
- Header validation rejects invalid names, non-ASCII values, and
leading/trailing whitespace. The map is snapshotted once before parsing,
so throwing getters and proxy traps never leak header content into
validation errors.
- Headers are never passed to the extension initialization metadata.

<sup>Written for commit 6359b7e.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3263?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3263?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3263&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
## why
port the Python support from #3260 to Go so callers can authenticate
against CDP gateways without putting credentials in the URL

## what

```go
browser, err := stagehand.ConnectLocalBrowser(ctx, stagehand.LocalBrowserConnectOptions{
    CDPURL:  "https://gateway/.../cdp",
    Headers: map[string]string{"X-Api-Key": "..."},
})
```

Headers are sent with HTTP discovery and the client’s CDP WebSocket
handshake. They only reach endpoints on the same host and effective
port, without downgrading TLS, and are never passed to the extension.
Both HTTP and WebSocket redirects are guarded using a copy of the HTTP
client, preserving the caller’s settings.

Header validation rejects unsafe names, non-ASCII values, and leading or
trailing whitespace without exposing credentials in errors. Discovery
fails immediately on HTTP 401/403, and debug logging explains when
headers are withheld. Includes a minor changeset.

## test plan

- Network tests cover discovery and WebSocket header forwarding, allowed
and blocked redirects, redirect limits, and connections with nil or
empty headers.
- Regression tests cover validation, error redaction, host/port/TLS
boundaries, safe diagnostics, immediate 401/403 failures, and retries
for transient HTTP failures.
- Factory tests verify headers are copied from the caller’s map and kept
out of extension initialization metadata. Redirect tests verify the
caller’s HTTP client and redirect policy are preserved.
- Targeted tests pass with the race detector, and `go vet .` passes. The
broader `go test ./...` command hits duplicate declarations in the
standalone examples directory.

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds `Headers` to `LocalBrowserConnectOptions` so Go callers can
authenticate against CDP gateways without putting credentials in the
URL.

- Ports the Python support from #3260 to Go, sending headers with HTTP
discovery and the client's CDP WebSocket handshake.
- Headers only reach endpoints on the same host and effective port,
never downgrading TLS, and are not passed to the extension.
- Redirects are guarded using a copy of the HTTP client, preserving
caller settings, and URLs are re-validated even if the caller's redirect
callback rewrites them; duplicate header names ignoring case are
rejected.
- 401/403 discovery failures fail immediately, and validation rejects
unsafe names, non-ASCII values, and whitespace trim issues without
exposing credentials in errors.

<sup>Written for commit b1b9938.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3265?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3265?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3265&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# what changed
- adds documentation for headers passed into `localBrowser.connect()`

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds documentation for passing authentication headers to
`localBrowser.connect()` (TypeScript and Python) and
`ConnectLocalBrowser` (Go).

- Shows how to pass headers without putting credentials in the
connection URL.
- Documents that headers are sent with HTTP discovery and the WebSocket
connection, only forwarded to the same host and port, and never passed
to the extension.
- Promotes the "Connecting over CDP" heading so the extension CDP URL
anchor link resolves correctly.

<sup>Written for commit 0a68a53.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3266?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3266?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3266&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

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

Add browser-side function waiting without repeatedly evaluating over the
SDK transport.

This is PR1 of the `waitForFunction()` stack. Follow-up #3183 targets
this branch to register the RPC and expose it in TypeScript, Python, and
Go.

# what changed

- Poll an expression in the main world immediately, then on animation
frames or a positive interval; await asynchronous predicates without
overlapping calls.
- Return a detached JSON value and surface predicate/serialization
errors directly.
- Reuse the selector-wait handle lifecycle through one shared
browser-wait helper, including disposal and late-result cleanup.
- Keep one Progress deadline across navigation retries. Timeout zero
remains unlimited, but closed pages/transports stop retries.
- Distinguish browser predicate exceptions from transient CDP errors so
a matching error message never triggers accidental retries.
- Refresh the required embedded extension ZIP. No protocol/RPC or public
SDK API changes.

Reviewed with the requested Thermo-Nuclear Code Quality Review skill:
shared resource ownership replaces duplicated cleanup, and browser-side
polling stays out of the transport and SDK layers.

# test plan

- 79 focused extension tests passed, including the existing
selector-wait regressions.
- Covers async predicates, errors, invalid polling, timeout/late
cleanup, context/root-frame replacement, and closure during
readiness/retry with timeout zero.
- Extension build/typecheck, embedded ZIP regeneration, formatting, and
`git diff --check` passed.
- Public real-Chrome integration coverage is in the SDK follow-up.

---------

Co-authored-by: miguel <miguelg71921@gmail.com>
# why

Expose browser-side predicate waiting consistently across Stagehand
SDKs, without transport polling.

This is PR2 of 2, stacked directly on #3179
(`amel/wait-for-function-extension`). Polling, navigation recovery, and
cleanup live in the parent; merge it first using the repository’s
stacked-PR handoff rules.

# what changed

- Register `page.wait_for_function` and connect the extension
controller/runtime to the internal implementation.
- Add TypeScript `waitForFunction(expression, arg?, options?)`, Python
`wait_for_function(expression, *, arg, polling, timeout)`, and Go
`WaitForFunction`. As in Playwright, an expression that evaluates to a
function is invoked on each poll and receives the optional JSON `arg`.
- Preserve JSON result keys through opaque wire metadata, with roundtrip
coverage for own `toString`, `constructor`, and `hasOwnProperty` keys in
nested payloads. No browser-handle API is introduced.
- Provide RAF/interval polling and no deadline by default in all three
SDKs; pass `timeout` to bound a wait. An omitted or zero timeout also
drops the client response deadline.
- Derive internal wait options from the canonical protocol contract.
Reuse the TypeScript argument serializer. Model Go’s string-or-number
polling option through its existing typed-union generator extension
point.
- Regenerate protocol/models/final ZIP and include docs plus minor
release entries for all five packages.

Reviewed with the requested Thermo-Nuclear Code Quality Review skill,
including an independent cross-review of SDK boundaries. No SDK polling
loops, duplicated serializer, broad generator abstraction, or new
1,000-line file crossing.

# test plan

- 9 real-Chrome tests passed, including main-world access, async
predicates, custom intervals, error propagation, navigation recovery,
concurrent waits, and timeout-zero closure.
- 79 extension/selector tests and 788 protocol/docs/SDK/architecture
guards passed.
- 184 Python tests plus Ruff/type checks passed; Go SDK package tests
passed.
- Follow-up review: 26 wire tests passed; canonical option types emit
unchanged JavaScript, and the rebuilt extension ZIP remains identical.
- Extension/SDK/protocol typechecks, dependency-ordered build,
generated-model/ZIP checks, formatting, lint, and `git diff --check`
passed.

---------

Co-authored-by: miguel <miguelg71921@gmail.com>
# why
- to give users a stable contract for getting the extension archive,
instead of reaching into the internals of stagehand & relying on brittle
file paths that may change across releases
# what changed
added an extension archive getter in all three SDKs: 
- TypeScript: await getExtensionArchive() → Uint8Array
- Python: get_extension_archive() → bytes
- Go: ExtensionArchive() → []byte
# test plan
- added tests covering archive contents, extraction, repeatability, and
independent buffer


<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Adds a public getter for the bundled Stagehand extension archive across
all three SDKs, so users no longer need to reach into internal file
paths.

- TypeScript: `getExtensionArchive()` returns a `Uint8Array`; Python:
`get_extension_archive()` returns `bytes`; Go: `ExtensionArchive()`
returns `[]byte`.
- Tests verify the archive is a valid ZIP, extractable, repeatable, and
that mutating a returned copy doesn't corrupt later calls.

<sup>Written for commit 6769580.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3267?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3267?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3267&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
# what changed
- adds docs for `getExtensionArchive()`, `get_extension_archive()`,
`ExtensionArchive()`

<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Documents the new extension ZIP export helpers and updates the
deployment guide to use them instead of the hardcoded `node_modules`
path.

- Adds a new "Exporting the Stagehand extension" section covering
`getExtensionArchive()`, `get_extension_archive()`, and
`ExtensionArchive()`, including upload and local Chrome installation
examples.
- Updates the deployment guide to export `stagehand-extension.zip` via
the SDK helper before uploading.

<sup>Written for commit fd9b57b.
Summary will update on new commits.</sup>

<a
href="https://cubic.dev/pr/browserbase/stagehand/pull/3268?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<a
href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3268?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3268&source=description"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"><img
alt="Turn on auto-fix"
src="https://www.cubic.dev/buttons/turn-on-auto-fix-light.svg"></picture></a>

<!-- End of auto-generated description by cubic. -->
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @browserbasehq/stagehand@4.3.0

### Minor Changes

- [#3267](#3267)
[`cb9a1d1`](cb9a1d1)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add
extension archive getter

- [#3253](#3253)
[`6bf4146`](6bf4146)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add
optional `extensionCdpUrl` to `localBrowser.connect` to allow
configuring the in-browser CDP url

- [#3263](#3263)
[`ecb2a6b`](ecb2a6b)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add
`headers` to `localBrowser.connect` so CDP gateways can be authenticated
without credentials in the URL

- [#3183](#3183)
[`901eb27`](901eb27)
Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Add
`page.waitForFunction()` to wait until a predicate in the page returns a
truthy value.

### Patch Changes

- [#3229](#3229)
[`c6b6f27`](c6b6f27)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - skip
caching for request bodies larger than 25 MB.

- [#3198](#3198)
[`10418f9`](10418f9)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - enable
WebMCP by default for local chromium versions newer than 157

- [#3210](#3210)
[`1c40ba7`](1c40ba7)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Require
client transport for Browserbase Model Gateway and cache requests.

- [#3209](#3209)
[`17de6ea`](17de6ea)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Route
Browserbase Model Gateway and cache requests through the connected SDK.
## @browserbasehq/eve@0.2.2

### Patch Changes

- Updated dependencies
[[`c6b6f27`](c6b6f27),
[`cb9a1d1`](cb9a1d1),
[`10418f9`](10418f9),
[`1c40ba7`](1c40ba7),
[`17de6ea`](17de6ea),
[`6bf4146`](6bf4146),
[`ecb2a6b`](ecb2a6b),
[`901eb27`](901eb27)]:
  - @browserbasehq/stagehand@4.3.0
## @browserbasehq/stagehand-protocol@3.0.0

### Major Changes

- [#3210](#3210)
[`1c40ba7`](1c40ba7)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Require
client transport for Browserbase Model Gateway and cache requests.

### Minor Changes

- [#3208](#3208)
[`4a7c637`](4a7c637)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Support
routing Browserbase Model Gateway and cache requests through the
connected SDK.

- [#3183](#3183)
[`901eb27`](901eb27)
Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Add the
`page.wait_for_function` method.
## @browserbasehq/stagehand-extension@1.2.0

### Minor Changes

- [#3208](#3208)
[`4a7c637`](4a7c637)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Support
routing Browserbase Model Gateway and cache requests through the
connected SDK.

- [#3183](#3183)
[`901eb27`](901eb27)
Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Add the
`page.wait_for_function` method.

### Patch Changes

- [#3229](#3229)
[`c6b6f27`](c6b6f27)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - skip
caching for request bodies larger than 25 MB.

- [#3257](#3257)
[`113ad81`](113ad81)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - honour a
changed extension CDP WS URL when creating a new Stagehand instance
after closing the previous one

- [#3210](#3210)
[`1c40ba7`](1c40ba7)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Require
client transport for Browserbase Model Gateway and cache requests.
## @browserbasehq/stagehand-go@4.3.0

### Minor Changes

- [#3267](#3267)
[`cb9a1d1`](cb9a1d1)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add
extension archive getter

- [#3265](#3265)
[`a31e2da`](a31e2da)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add
`Headers` to `LocalBrowserConnectOptions` so CDP gateways can be
authenticated without credentials in the URL

- [#3254](#3254)
[`9eac212`](9eac212)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add
optional `ExtensionCDPURL` to `LocalBrowserConnectOptions` to allow
configuring the in-browser CDP url.

- [#3183](#3183)
[`901eb27`](901eb27)
Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Add
`Page.WaitForFunction` to wait until a predicate in the page returns a
truthy value.

### Patch Changes

- [#3229](#3229)
[`c6b6f27`](c6b6f27)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - skip
caching for request bodies larger than 25 MB.

- [#3198](#3198)
[`10418f9`](10418f9)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - enable
WebMCP by default for local chromium versions newer than 157

- [#3210](#3210)
[`1c40ba7`](1c40ba7)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Require
client transport for Browserbase Model Gateway and cache requests.

- [#3209](#3209)
[`17de6ea`](17de6ea)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Route
Browserbase Model Gateway and cache requests through the connected SDK.
## @browserbasehq/stagehand-python@4.3.0

### Minor Changes

- [#3260](#3260)
[`2859fd5`](2859fd5)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add
`headers` to `local_browser.connect` so CDP gateways can be
authenticated without credentials in the URL

- [#3267](#3267)
[`cb9a1d1`](cb9a1d1)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add
extension archive getter

- [#3252](#3252)
[`21e0363`](21e0363)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add
`extension_cdp_url` to `local_browser.connect` for clients that reach
Chrome through a proxy the extension cannot use

- [#3183](#3183)
[`901eb27`](901eb27)
Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Add
`page.wait_for_function()` to wait until a predicate in the page returns
a truthy value.

### Patch Changes

- [#3229](#3229)
[`c6b6f27`](c6b6f27)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - skip
caching for request bodies larger than 25 MB.

- [#3198](#3198)
[`10418f9`](10418f9)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - enable
WebMCP by default for local chromium versions newer than 157

- [#3210](#3210)
[`1c40ba7`](1c40ba7)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Require
client transport for Browserbase Model Gateway and cache requests.

- [#3209](#3209)
[`17de6ea`](17de6ea)
Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Route
Browserbase Model Gateway and cache requests through the connected SDK.
## @browserbasehq/stagehand-examples@0.0.3

### Patch Changes

- Updated dependencies
[[`c6b6f27`](c6b6f27),
[`cb9a1d1`](cb9a1d1),
[`10418f9`](10418f9),
[`1c40ba7`](1c40ba7),
[`17de6ea`](17de6ea),
[`6bf4146`](6bf4146),
[`ecb2a6b`](ecb2a6b),
[`901eb27`](901eb27)]:
  - @browserbasehq/stagehand@4.3.0
  - @browserbasehq/stagehand-integrations@4.0.6
## @browserbasehq/stagehand-integrations-claude-agent-sdk@4.0.5

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.6
##
@browserbasehq/stagehand-integrations-example-claude-code-facade@4.0.6

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.6
  - @browserbasehq/stagehand-integrations-claude-agent-sdk@4.0.5
## @browserbasehq/stagehand-integrations-claude-cua-sdk@4.0.4

### Patch Changes

- Updated dependencies
[[`c6b6f27`](c6b6f27),
[`cb9a1d1`](cb9a1d1),
[`10418f9`](10418f9),
[`1c40ba7`](1c40ba7),
[`17de6ea`](17de6ea),
[`6bf4146`](6bf4146),
[`ecb2a6b`](ecb2a6b),
[`901eb27`](901eb27)]:
  - @browserbasehq/stagehand@4.3.0
  - @browserbasehq/stagehand-integrations@4.0.6
## @browserbasehq/stagehand-integrations-example-codex-facade@4.0.6

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.6
  - @browserbasehq/stagehand-integrations-codex-sdk@4.0.5
## @browserbasehq/stagehand-integrations-codex-sdk@4.0.5

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.6
## @browserbasehq/stagehand-integrations@4.0.6

### Patch Changes

- Updated dependencies
[[`c6b6f27`](c6b6f27),
[`cb9a1d1`](cb9a1d1),
[`10418f9`](10418f9),
[`1c40ba7`](1c40ba7),
[`17de6ea`](17de6ea),
[`6bf4146`](6bf4146),
[`ecb2a6b`](ecb2a6b),
[`901eb27`](901eb27)]:
  - @browserbasehq/stagehand@4.3.0
## @browserbasehq/stagehand-integrations-example-cursor-facade@4.0.4

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.6
  - @browserbasehq/stagehand-integrations-cursor-sdk@4.0.5
## @browserbasehq/stagehand-integrations-cursor-sdk@4.0.5

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.6
## @browserbasehq/stagehand-integrations-deepagents-sdk@4.0.5

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.6
## @browserbasehq/stagehand-integrations-eve-sdk@4.0.5

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.6
## @browserbasehq/stagehand-integrations-fx-sdk@4.0.5

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.6
## @browserbasehq/stagehand-integrations-gemini-cua-sdk@4.0.4

### Patch Changes

- Updated dependencies
[[`c6b6f27`](c6b6f27),
[`cb9a1d1`](cb9a1d1),
[`10418f9`](10418f9),
[`1c40ba7`](1c40ba7),
[`17de6ea`](17de6ea),
[`6bf4146`](6bf4146),
[`ecb2a6b`](ecb2a6b),
[`901eb27`](901eb27)]:
  - @browserbasehq/stagehand@4.3.0
  - @browserbasehq/stagehand-integrations@4.0.6
## @browserbasehq/stagehand-integrations-example-mastra-facade@4.0.6

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.6
## @browserbasehq/stagehand-integrations-mastra-sdk@4.0.5

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.6
## @browserbasehq/stagehand-integrations-example-pi-facade@4.0.6

### Patch Changes

- Updated dependencies
[[`c6b6f27`](c6b6f27),
[`cb9a1d1`](cb9a1d1),
[`10418f9`](10418f9),
[`1c40ba7`](1c40ba7),
[`17de6ea`](17de6ea),
[`6bf4146`](6bf4146),
[`ecb2a6b`](ecb2a6b),
[`901eb27`](901eb27)]:
  - @browserbasehq/stagehand@4.3.0
  - @browserbasehq/stagehand-integrations@4.0.6
## @browserbasehq/stagehand-integrations-pi-sdk@4.0.5

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.6
## @browserbasehq/stagehand-integrations-example-vercel-ai-facade@4.0.6

### Patch Changes

- Updated dependencies []:
  - @browserbasehq/stagehand-integrations@4.0.6

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@seanmcguire12
seanmcguire12 requested a review from a team as a code owner October 20, 2026 00:46
@changeset-bot

changeset-bot Bot commented Oct 20, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: c81d603

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@mintlify

mintlify Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
stagehand 🟢 Ready View Preview Oct 20, 2026, 12:46 AM

💡 Tip: Enable Automations to automatically generate PRs for you.

@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedpypi/​deepagents@​0.7.8 ⏵ 0.7.2698100100100100

View full report

@seanmcguire12
seanmcguire12 merged commit f491784 into docs-production Oct 20, 2026
62 checks passed
@seanmcguire12
seanmcguire12 deleted the update-sh-4.3.0 branch October 20, 2026 00:53

This branch was successfully deployed

1 active deployment
staging - packages/docs — c81d6032 Deployed Oct 20, 2026 by mintlify[bot]
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.

8 participants