Repository navigation
[docs]: sync docs branch with main - #3151
Merged
Merged
Conversation
## 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.
Adds Claude native browser use through the shared CUA bridge and canonical facade. Native tool instructions remain separate from internal mount instructions, and the shared autonomy policy is injected once through the native system channel. Includes package, build, and CI registration. Retains thinking, tool-result blocks, usage presence, and screenshot evidence. API history can discard older screenshots without mutating verification events. Unmatched calls carry a missing-result failure instead of appearing successful. Diagnostic logs contain tool name/status/duration; original tool inputs stay in session evidence, and abort diagnostics are sanitized. Tab operations use the canonical visible context and readonly `page.pageId`. Keeper pages cannot enter tab inventory or be selected/closed; legitimate visible blank pages remain available. Explicit `tab_id` actions refresh active identity before executing. A first reference action without cached tab state adds one inventory call to obtain real IDs. Typed canonical session-loss errors or runner-owned telemetry stop execution; page error text alone cannot impersonate browser loss. Drag uses the SDK `dragAndDrop` primitive. Separate held-button down/up gestures and modifier clicks receive actionable unsupported errors; complete drag and ordinary clicks are supported. Partial toolset configuration preserves member defaults, literal Space is accepted, `find` text is capped, and transcript clipping preserves surrogate pairs. Validation: **72 tests pass across 8 files**, including **55 Claude SDK tests**, native eval/runner/mount tests, and the compiled facade/MCP fixture. Tests execute generated snippets through actual canonical `StagehandFacadeTools` and SDK `Page`/`BrowserContext` objects over in-memory RPC. Claude SDK and full eval typechecks, matching core/Claude SDK builds, and scoped formatting pass. Generated test artifacts under dist/.turbo/node_modules leave the task cache inputs and hash unchanged. Provider responses are scripted; these checks do not establish live browser gestures, model performance, or disconnect recovery. Stack base: `evals/consolidation-15-shared-cua-bridge`. Review this PR relative to its immediate predecessor. Reviewer entry points: - [`packages/integrations/claude-cua-sdk/src/executor.ts`](https://github.com/browserbase/stagehand/blob/ac0acaffa0d3f05f94d4eef6b8c57a9898b52f73/packages/integrations/claude-cua-sdk/src/executor.ts) - [`packages/integrations/claude-cua-sdk/src/session.ts`](https://github.com/browserbase/stagehand/blob/ac0acaffa0d3f05f94d4eef6b8c57a9898b52f73/packages/integrations/claude-cua-sdk/src/session.ts) - [`packages/evals/framework/claudeCuaRunner.ts`](https://github.com/browserbase/stagehand/blob/ac0acaffa0d3f05f94d4eef6b8c57a9898b52f73/packages/evals/framework/claudeCuaRunner.ts) Review fixes: Refresh visible tabs after coordinate and ref actions so popups appear in the same tool result while keeper tabs stay hidden. Missing page IDs now raise a typed facade error. Diagnostic tests assert member names, success status, and duration alongside secret redaction. Updated tests cover the real SDK/facade and MCP boundaries; all three review threads are resolved after passing CI. Current open stack: #2893 → #2894 → #2902 → #2903 → #2889 → #2904 → #2905 → #2906 → #2907.
Adds Gemini native computer use through the same CUA bridge and canonical facade. System instructions and cancellation use the SDK configuration; normalized coordinates map to browser coordinates. Includes package, build, CI registration, and the shared harness guide. Stores the actual model-visible tool response and screenshot against its call ID, with optional fields for older records and no duplicate per-action captures. Confirmed runner-owned browser loss or a typed core facade loss is terminal; arbitrary error text, including agent-marked errors, remains recoverable. Missing, blocked, truncated, and malformed provider responses fail as SDK errors, and partial tool calls from those responses are not executed. Every function-call batch is validated before any member executes. Arbitrary model/resource identifiers are passed to the provider, with only the optional `google/` alias removed. Drag uses the existing SDK `dragAndDrop` primitive. Hotkey arrays execute as one chord, wait honors the requested seconds, and the current scroll action uses its documented default while retaining the legacy action's default. Budgets use `EVAL_GEMINI_CUA_MAX_TURNS`. Explicit empty answers remain empty, unfinished calls remain failed, and the last model-visible image is retained when terminal capture is unavailable. That fallback is the last captured frame, not a fresh terminal screenshot. Transcript clipping preserves Unicode pairs. Validation: 72 Gemini SDK/eval tests across seven files pass, including scripted terminal-response cases and generated executor code exercised against the actual SDK Page and RPC schemas over an in-memory transport. The earlier combined Claude/Gemini/shared suite, including the compiled facade/MCP fixture, passed 101 tests across 14 files before this Gemini follow-up. Gemini SDK and full eval typechecks and the Gemini SDK build pass; parent propagation and final combined validation are separate checks. These are local contract checks; live provider performance and semantic judge compatibility remain separate gates. Stack base: `evals/consolidation-16-claude-cua`. Review this PR relative to its immediate predecessor. Reviewer entry points: - [`packages/integrations/gemini-cua-sdk/src/executor.ts`](https://github.com/browserbase/stagehand/blob/edc3c35f46976a8321d20cabbebd496027d99073/packages/integrations/gemini-cua-sdk/src/executor.ts) - [`packages/integrations/gemini-cua-sdk/src/session.ts`](https://github.com/browserbase/stagehand/blob/edc3c35f46976a8321d20cabbebd496027d99073/packages/integrations/gemini-cua-sdk/src/session.ts) - [`packages/evals/framework/harnesses/geminiCuaAdapter.ts`](https://github.com/browserbase/stagehand/blob/edc3c35f46976a8321d20cabbebd496027d99073/packages/evals/framework/harnesses/geminiCuaAdapter.ts) Current open stack: #2893 → #2894 → #2902 → #2903 → #2889 → #2904 → #2905 → #2906 → #2907.
## Stack Top-of-stack child of #2906 (`evals/consolidation-17-gemini-cua`). Review against that immediate parent, not `main`. ## Summary Port the remaining focused Codex/Stagehand facade hardening from the experimental Codex worktree without replacing the consolidation stack's newer shared runtime. - Add opt-in facade JSONL tool logging: request/session IDs, actual arguments/code, paired starts/ends, timing, errors, bounded result previews and browser readiness. Never write logs to MCP stdout; redact known credentials and omit image payloads. - Escape Unicode line separators in text tool results, addressing the stream parsing failure observed in the Hostelworld benchmark traces. - Share isolated HOME/CODEX_HOME creation between the SDK example and evals; do not inherit operator plugins/config/thread context. Preserve file-based auth. - Abort unexpected MCP servers, await observation capture, and match evidence by tool-call ID so unrelated calls/missing final captures do not shift screenshots. - Add optional bounded SDK failure artifacts and keep binary payloads out of telemetry without mutating original events. - Document the difference between Codex event logs and facade server logs, privacy limitations, authentication, and runnable logging commands. This remains the existing Codex SDK harness with the Stagehand facade, not a new native OpenAI computer-use adapter. Preserve the parent's terminal session-loss semantics, shared facade API, HardBench dataset, verifier and usage contracts. The older experimental `state`/`nodeRepl`/`reset` surface and reconnect implementation are not copied wholesale into the newer shared runtime. The original dirty worktree remains untouched. ## Validation - 220 focused tests pass across 23 files (core facade, Codex SDK, eval adapters). - 2 standalone Codex example tests pass. - Built stdio regression verifies the JSONL file is created and contains paired request IDs and error results while the MCP client remains responsive. - Integration packages and eval ESM/CLI builds; core/Codex/example/evals typechecks. - Targeted lint: no errors; warnings remain in existing patterns and diagnostic stringification. `git diff --check` passes. - No paid model or HardBenchmark rerun; no benchmark score improvement claimed. ## Operational notes Logging remains opt-in. Logs/error artifacts may contain sensitive model/page content despite best-effort redaction and must be reviewed before sharing. Unexpected-server detection aborts observed calls; it is not a security sandbox. Keychain-only login is not copied into isolated profiles. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Hardens Codex facade runs with isolated `HOME`/`CODEX_HOME` profiles, opt-in tool logging, and evidence keyed to tool-call IDs so unmatched or unrelated calls no longer misplace screenshots. **New Features** - Adds opt-in JSONL facade tool logging with request/session IDs, arguments, timing, errors, and bounded result previews; logs go only to file or stderr, never MCP stdout, with known credentials redacted and image payloads omitted. - Saves bounded SDK failure artifacts to `STAGEHAND_CODEX_DIAGNOSTICS_DIR` or `EVAL_CODEX_DIAGNOSTICS_DIR`; a failed diagnostic write never masks the original SDK failure. - Shares isolated `HOME`/`CODEX_HOME` creation between the SDK example and evals via a common helper in `@browserbasehq/stagehand-integrations-codex-sdk`; only file-based `auth.json` is copied, never plugins, config, stray `CODEX_*` env, or inherited thread context, and the example now runs in a temporary working directory and warns Codex to use only the mounted browser tools. **Bug Fixes** - Matches probe evidence by tool-call ID so missing final captures no longer shift screenshots onto the wrong step. - Aborts on unexpected MCP servers (detection only, not a sandbox). - Escapes Unicode line separators in text tool results, fixing the stream parsing failure seen in Hostelworld traces. <sup>Written for commit bdc69f2. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/2907?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. --> Current open stack: #2893 → #2894 → #2902 → #2903 → #2889 → #2904 → #2905 → #2906 → #2907.
…3084) Two fetches of the stagehand page found no Classifiers section, which would make the package invisible to every classifier-based browse and filter on `PyPI: Topic :: Internet :: WWW/HTTP :: Browsers`, `Topic :: Scientific/Engineering :: Artificial Intelligence`, `Intended Audience :: Developers`, Development Status, `Typing :: Typed`. Keywords are also thin (ai, browser, automation, web-scraping, testing), missing agent, browser-agent, computer-use, playwright, headless. And there are three PyPI identities in play: stagehand, the stale stagehand-py, and the now-archived stagehand-python repo. A developer searching PyPI for "stagehand" gets ambiguous results. Add a deprecation pointer on stagehand-py. --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
# why this PR wires the `progress` tracker into `act()`, `extract()`, `observe()`. before this PR, `act()`, `observe()`, & `extract()` had their own timeout tracking mechanism, which only checked remaining time between between major IO steps. a stalled snapshot, model request, or browser action could keep the call waiting past its timeout. nested work also did not share the caller's remaining time. # what changed - gave each call one shared deadline across snapshots, cache reads & writes, model requests, & browser work. each step gets only the time left. - carried act's deadline through page settling, supplied actions, cached replay, two-step actions, & self-healing. extract's optional screenshot & second model request share its deadline too. - made expiry reject with the caller's timeout error & prevent later steps. late model or cache responses cannot start another action or request. browser commands & model requests already sent may still finish. - cleaned up settling listeners, temporary element references, & pressed inputs when interrupted. kept snapshot scope fallback within the same budget. - kept the existing defaults: omitted timeouts & `0` remain unlimited. - removed the unused timeout guard # test plan - `service-progress.test.ts` checks expiry during snapshots, cache work, & model calls for all three services. it verifies that nested work uses the remaining budget, omitted/zero timeouts stay unlimited, & late responses cannot resume work. act cases cover cached replay, self-healing, two-step actions, interrupted fill/drag/key presses, & settling cleanup. extract cases cover screenshots, image encoding, & its second model request. - `serviceTimeouts.test.ts` uses a local browser, a controlled iframe response, & controlled model responses. it checks that readiness expiry prevents inference, full-page fallback does not restart the timeout, & late responses cannot cause clicks or a second extraction request. it also verifies that act can use the full-page fallback while time remains & that an expired supplied action stays stopped after its iframe loads. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Gives `act()`, `extract()`, and `observe()` a shared `progress` deadline so timeouts apply across snapshots, cache reads/writes, model requests, and browser actions. Before, each service checked remaining time only between major steps, so stalled work could outlive its timeout and nested work never shared the caller's budget. - One deadline now covers all work in a call; nested steps inherit the caller's remaining time. - Expiry rejects with the caller's timeout error and blocks any later steps, though already-sent browser commands and model requests may still finish. - Interruption cleans up settling listeners and temporary element references, releases held keys and a pressed mouse button exactly once (the mouse at its last dispatched position) when a drag expires mid-way, and drops held cache keys. - Omitted or `0` timeouts remain unlimited; the unused `timeoutGuard` helper is removed. - Added unit and integration coverage for expiry during each step, budget inheritance, late responses, and cleanup. <sup>Written for commit f9753f8. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3109?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 #2789 after approval by @charlypoly. Original author: @antonvishal Original PR: #2789 Approved source head SHA: `5d32c83ec49a1d1dfb1ce40d42a74593196635bc` @antonvishal, 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 Humans and coding agents need browser workflows they can understand, reuse, and combine into new jobs. These cookbooks are meant to be building blocks. ## What - Add matching runnable projects under `packages/cookbooks`. - Keep the docs focused on the workflow and make each example easy for both humans and agents to understand and adapt. - Support TypeScript, Python, and Go for the core browser workflows. ## Follow-ups - [ ] Simplify the clone/sparse-checkout setup into a one-command start - [ ] Add more cookbooks by combining existing patterns into new workflows <img width="3008" height="1656" alt="BetterShot_2026-10-03-21-28-28" src="https://github.com/user-attachments/assets/5a9d7d59-4fdf-4fa6-a755-3378fbdab194" /> <!-- external-contributor-pr:owned source-pr=2789 source-sha=5d32c83ec49a1d1dfb1ce40d42a74593196635bc claimer=charlypoly --> <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds a Cookbooks tab to the docs with five runnable browser workflow examples (persisted login, paginated catalog export, files to bucket, form submission approval, and an AI SDK research agent), each with an agent prompt, setup instructions, and source code. Reorganizes the existing example projects under `packages/examples/showcase` so cookbooks get their own directory, and updates the `justfile`, `.gitignore`, and code ownership accordingly. The new `just cookbook` command runs any cookbook from the repo root. **Migration** - `just cookbook` runs cookbooks that previously lived under `packages/examples`; the old `just cookbook <slug>` path for showcase scripts is now `just showcase-script`. - `.env` files for showcase examples now live in `packages/examples/showcase/.env` instead of `packages/examples/.env`. - The `saas-pricing-monitor` example script was removed as part of the showcase reorg; its workflow still exists under the showcase directory. <sup>Written for commit 40562dc. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3116?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: Vishal Anton <vishalanton@appexert.com> Co-authored-by: VIshal Anton <166398166+antonvishal@users.noreply.github.com> Co-authored-by: Charly Poly <charly@browserbase.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
# Summary Add a Claude Toolset integration guide to the Stagehand v4 docs. # Why Developers need setup instructions for connecting Claude to local Chrome or Browserbase through the published Stagehand Claude SDK packages. # What changed - Add TypeScript and Python installation, browser-task examples, session cleanup, Browserbase configuration, and domain-filtering limitations. - Link the guide from navigation and integration overviews, distinguishing its native toolset from the shared MCP tool contract. # Testing (if applicable) - `npx --yes mint@4.2.788 validate`: passed. - `npx --yes mint@4.2.788 broken-links --check-anchors --check-redirects --check-snippets`: passed. - `npx --yes mint@4.2.788 a11y --skip-contrast`: passed. - Python snippet syntax and `git diff --check`: passed. - Live Claude execution and published package exports have not been verified; the registry releases were placeholders when checked. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds a Claude Toolset integration guide to the Stagehand v4 docs, covering setup for the published `stagehand-claude-sdk` packages in TypeScript and Python. - Documents installation, local Chrome and Browserbase launch modes, domain restrictions, and session cleanup. - Links the guide from navigation and both integration overviews, clarifying that Claude Toolset uses a native browser toolset rather than the shared MCP tool contract. <sup>Written for commit 82243b2. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3122?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> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3122?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3122&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-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
# why - there is no golang sdk that applies here, so we can ignore the test that checks for a golang tab # what changed - omitted the cua toolset page form sdk reference test <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adjusts the SDK reference test so the Claude CUA toolset page no longer requires a Go snippet, since that toolset has no Go SDK. - Adds per-page language requirements so pages can support a subset of the standard TypeScript, Python, and Go set. - Updates the test to fail only when a page misses a language it actually supports. <sup>Written for commit 61e8e79. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3134?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/3134?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3134&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 - updated Python dependencies in the CrewAI integration, DeepAgents runner and examples, and Python SDK development environment - bumped CrewAI, crewai-tools, crewai-cli, and crewai-core from `1.15.14` to `1.15.24` - raised the CrewAI and crewai-tools minimums to `1.15.24`, which requires PyJWT `>=2.15.0` - updated ChromaDB `1.1.1` -> `1.5.9` and removed backoff and posthog transitively - updated PyJWT `2.13.0` -> `2.15.0` in CrewAI and the DeepAgents runner/local example; added `pyjwt>=2.15.0,<3` to the two DeepAgents manifests - updated urllib3 `2.7.0` -> `2.8.0` and declared `urllib3>=2.8.0,<3` in CrewAI and all three DeepAgents environments - bumped LangGraph `1.2.10/1.2.11` -> `1.2.14` in the DeepAgents runner, local example, and managed example - declared `langgraph>=1.2.14,<1.3`, which requires the patched langgraph-sdk `>=0.4.6,<0.5.0` - updated langgraph-sdk `0.4.2/0.4.3` -> `0.4.6` - updated CrewAI's multidict `6.7.1` -> `6.9.1` and OAuthlib `3.3.1` -> `4.0.0`, with explicit minimums and major-version upper bounds - bumped the Python SDK's pytest development pin `9.0.2` -> `9.0.3` - declared security minimums in project dependencies so independent resolutions enforce them; no new dependency overrides were needed <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Bumps transitive Python dependencies across the CrewAI integration, DeepAgents runner and examples, and the Python SDK development environment to pick up security fixes. - CrewAI, `crewai-tools`, `crewai-cli`, and `crewai-core` move from `1.15.14` to `1.15.24`, raising the CrewAI minimums and requiring PyJWT `>=2.15.0`. - ChromaDB bumps `1.1.1` → `1.5.9`, dropping `backoff` and `posthog` from the dependency graph. - PyJWT (`2.13.0` → `2.15.0`) and urllib3 (`2.7.0` → `2.8.0`) get explicit minimums in CrewAI and the DeepAgents manifests so independent resolutions enforce them; no new overrides were needed. - LangGraph (`1.2.10`/`1.2.11` → `1.2.14`) and `langgraph-sdk` (`0.4.2`/`0.4.3` → `0.4.6`) update across the DeepAgents environments, with `langgraph>=1.2.14,<1.3` declared to pull in the sdk authorization fix. - multidict (`6.7.1` → `6.9.1`) and OAuthlib (`3.3.1` → `4.0.0`) update in CrewAI with minimums and major-version upper bounds. - pytest dev pin bumps `9.0.2` → `9.0.3` in the Python SDK. <sup>Written for commit 814eecf. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3133?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/3133?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3133&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. -->
Mirrored from external contributor PR #3105 after approval by @miguelg719. Original author: @alanagoyal Original PR: #3105 Approved source head SHA: `b48795840bce28f4c26f48b35183bb035a1ea519` @alanagoyal, 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 this is a first step toward #2841. today, turning a bug report into a pinned fixture takes a manually built mirror. this adds a small recorder so a page state can be saved locally and used in an `extract()` or `observe()` regression. # what changed - added `fixture:record` in `packages/evals`: pass a url, output directory, and optional playwright setup script - saves `index.html` plus a manifest with the source url, capture time, viewport, and limitations - preserves computed styles, resolved links, and current form state; removes scripts and remote assets and adds a restrictive csp - rejects frames/open shadow dom and refuses to overwrite an existing fixture - documented capture, replay, refresh, and content review before: reproduce against the live site or build a mirror by hand. after: run setup to reach the relevant state, record it, and write an assertion against the saved page. this is scoped to static observations. it doesn't replay application behavior, generate assertions, or migrate the old live-site tasks mentioned in the issue, which aren't on current v4 main. proposed follow ups: 1. migrate a few representative current evals to recorded fixtures 2. add a reusable bug-report-to-fixture-and-regression-test workflow # test plan - recorder/browser tests cover form state, visibility, links, blocked resource loads, output protection, unsupported content, and the cli setup workflow - added a real stagehand extraction test using a reduced reproduction of #2624, with a deterministic model adapter and no api keys - added dom-sensitive validation through real `stagehand.observe()` calls: source and fixture prompts match, hidden controls stay hidden, the dynamic accessible name and edited form state survive, and the returned xpath resolves to the intended button - replay disables the original page and stylesheet; a negative control removes captured visibility and confirms that stagehand sees the leaked hidden control and the validation rejects the lossy fixture - confirmed both source and recorded pages fail when the historical schema-key bug is restored, then pass with the upstream fix; their extraction prompts also match after normalizing element ids the schema check validates one historical transport regression; the synthetic checkout checks dom fidelity for the supported patterns above. neither claims general site fidelity or model reasoning quality. local checks: - `just install`, `just build`, `just fmt`, `just check`, and `just test` passed - all 10 recorder/extraction/observation browser tests passed separately - 1,031 eval unit tests, 750 python tests (1 existing skip), and the go sdk/generator suites passed - an existing sdk browser smoke test hit its 10-second timeout during concurrent runs; it passed in isolation, then all typescript tasks passed with `--concurrency=1` and the final `just test` passed using those cached results. no timeout or assertion changes <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds a static observation task recorder in `packages/evals` so `extract()` and `observe()` regressions can run against a saved local page instead of the live site. - `task:record` takes a URL, output directory, and optional Playwright setup script, then writes `index.html` plus a manifest with source URL, capture time, viewport, and limitations. - Preserves computed styles, resolved links, and current form state; strips scripts and remote assets and adds a restrictive CSP. - Rejects frames and open shadow DOM; refuses to overwrite existing tasks. - Adds a real Stagehand extraction regression for the #2624 schema-key bug using a deterministic model adapter, plus an `observe()` fidelity test on a synthetic checkout page showing edited state, accessible names, and CSS-hidden controls survive replay. - Includes a negative control that detects loss of captured visibility styles, and recording tests covering form state, visibility, links, blocked resources, output protection, and CLI setup. <sup>Written for commit 503c421. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3106?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> <a href="https://www.cubic.dev/action/auto-fix/pr/browserbase/stagehand/3106?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3106&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-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> <!-- external-contributor-pr:owned source-pr=3105 source-sha=b48795840bce28f4c26f48b35183bb035a1ea519 claimer=miguelg719 --> --------- Co-authored-by: alanagoyal <alanaan@gmail.com> Co-authored-by: miguel <miguelg71921@gmail.com>
# why Sibling to #2933. That PR lets callers inject a `Browserbase` SDK instance. This PR takes the alternative approach: Stagehand keeps building the Browserbase client, and callers pass the client's HTTP settings instead. - One `apiKey` authenticates both Browserbase and the Stagehand runtime. An injected client could carry a different key. - Stagehand controls the SDK version and how the client is built. A hand-made or mismatched-version instance can't break calls like `extensions.delete` that depend on SDK-specific options. - Python can offer the same option, which #3119 does. The shared fields (`timeout`, `max_retries`, `default_headers`, `default_query`) exist in both SDKs. The options are nested under `clientOptions` rather than flattened, because `browserbase.launch()` passes unknown keys through to `SessionCreateParams`, which already has a `timeout` field (the session timeout in seconds). # what changed - `clientOptions?: BrowserbaseClientOptions` on `browserbase.launch()` and `browserbase.connect()`. The type is `Pick<ClientOptions, "timeout" | "maxRetries" | "defaultHeaders" | "defaultQuery" | "fetch">`, validated by a strict schema. `apiKey` and `baseURL` are rejected inside it. `BrowserbaseClientOptions` is exported. - In the cross-language parity test, `BrowserbaseConnectOptions.client_options` is temporarily exempt for Python, until the stacked #3119 removes the exemption, and pending for Go. Go talks to Browserbase over its own `net/http` client rather than the official SDK. - Adds docs (`configuration/browser.mdx`, TypeScript only for now) and a minor changeset for `@browserbasehq/stagehand`. # test plan - [x] `tsc --noEmit`, oxfmt, oxlint; sdk-ts unit tests and `rules/ast-grep` parity tests (31 files, 407 tests) - [x] One test builds a real `@browserbasehq/sdk` client with a spy `fetch` and checks that the request URL, `defaultQuery`, `defaultHeaders` and API key are applied - [x] Published-tarball consumer type fixture uses `BrowserbaseClientOptions` - [ ] No live Browserbase session was launched
) # why Stacked on #3119 (Python), which is stacked on #3118 (TypeScript). Those PRs add Browserbase client options to `browserbase.launch()` / `browserbase.connect()` in TS and Python. This PR adds the Go equivalent, so the three SDKs are at parity again and the parity test no longer needs a Go exemption. # what changed - New `BrowserbaseClientOptions` struct, set as `ClientOptions *BrowserbaseClientOptions` on both `BrowserbaseLaunchOptions` and `BrowserbaseConnectOptions`: - `Timeout time.Duration`: applies to each attempt; 0 keeps the 60s default. - `MaxRetries *int`: nil keeps the default of 2. - `DefaultHeaders map[string]string`, `DefaultQuery map[string]string`. - `HTTPClient *http.Client`: owned by the caller and never modified. - Go talks to Browserbase over its own `net/http` client, so the internal options it already had (HTTP client, max retries) are now exposed, plus headers and query. - The timeout is applied per attempt through the request context, both for the default client and for a client the caller passes in, and it also covers reading the response body. The default client no longer sets `http.Client.Timeout` itself. If an attempt times out, only requests that are safe to resend (retrieve, release, delete) are retried, each with a new deadline. Creates fail immediately. - Negative `Timeout` or `MaxRetries`, invalid header names, and header values containing control characters are rejected before any request is sent. - `ClientOptions` is never sent in the session-create body; a test checks the body contents. - Removes `pendingGoBrowserFields` from the cross-language parity test. - Docs: the client-options section is a TypeScript / Python / Go tab group again. - Adds a minor changeset for `@browserbasehq/stagehand-go`. This PR is the only change in the stack that releases Go. # header precedence Same rule as TS and Python: `DefaultHeaders` override Stagehand's own headers on conflict, including `X-BB-API-Key` and `User-Agent`. Both Browserbase SDKs apply caller default headers last; this was checked in their source (`@browserbasehq/sdk` `index.js` `defaultHeaders`, and the Python `_base_client`). Go still rejects invalid header names or values before sending. # test plan - [x] `go vet`; gofmt (prints nothing); `go test -race` on every package except examples; generator `--check`; `scripts/check-examples.sh` - [x] New `browserbase_client_options_test.go` uses `httptest` servers to cover: - options reaching requests, and later changes to the caller's maps having no effect; - default headers and query on POST and GET, with caller defaults overriding Stagehand's headers (mutation-checked); - `MaxRetries` set to 0 and 1, and the default; - the per-attempt timeout, including a retry getting a new deadline and the deadline covering the response body; - a caller `HTTPClient` being used and left unmodified; - invalid options failing with zero requests reaching the server, on both launch and connect; - full launch and connect through the real factory. - [x] Mutation-checked: with the per-attempt deadline removed, the timeout test fails in about 5s with a clear message. - [x] `rules/ast-grep` parity tests (Go exemption removed), docs tests, the TS suite, oxfmt, oxlint, `check-changesets` - [ ] Plain `go test ./...` fails only because `packages/sdk-go/examples` doesn't build as a single package; that was already the case. CI and the justfile exclude `/examples`. - [ ] No live Browserbase session was launched
## Summary - Replace the externally hosted DeepWiki badge with a repository-local SVG. - Use a static Ask DeepWiki badge styled to match the README badges; keep the DeepWiki destination unchanged. - Set explicit dimensions to match the neighboring 32px badges. ## Why The external badge endpoint returns HTTP 429 with a Vercel challenge, consistent with the broken image in the README. Hosting the badge locally removes that external dependency. ## Validation - git diff --check passed. - SVG XML parsing passed. - Verified the README references the local asset and preserves the DeepWiki destination. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Replaces the externally hosted DeepWiki badge in the README with a repository-local SVG at `media/deepwiki.svg`, since the hosted endpoint returns HTTP 429 with a Vercel challenge that broke the image. The new badge is styled to match the neighboring 32px badges, keeps the same DeepWiki destination, and passes `git diff --check` and SVG XML parsing. <sup>Written for commit c143ac1. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3136?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/3136?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3136&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 is an auto-generated description by cubic. --> ## Summary by cubic Disables Browserbase proxies in CI eval runs so tests use direct browser connections instead of proxied ones. <sup>Written for commit acd3b5b. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3143?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/3143?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3143&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. -->
GitHub Pages has been unreliable for the eval sites, so they now also deploy to Vercel at `https://stagehand-eval-sites.vercel.app/`. This PR swaps the host. Paths are unchanged: ``` https://browserbase.github.io/stagehand-eval-sites/sites/<name>/… https://stagehand-eval-sites.vercel.app/sites/<name>/… ``` **What changed (76 files)** - Every `browserbase.github.io/stagehand-eval-sites/` URL across evals tasks, sdk-ts tests, the TS/Python/Go examples and the docs is now the Vercel URL. `git grep 'github\.io/stagehand-eval-sites'` matches only `get_url.ts`. - `packages/evals/core/tasks/page-info/get_url.ts` stored the host as an escaped regex. Its allowlist now accepts both hosts. - oxfmt reflowed lines where the shorter URL now fits on one line. Apart from `get_url.ts`, each file matches `main` once the host is normalized and whitespace and commas are ignored. **Verified against the Vercel host** - All 114 files under `sites/` are byte-identical to Pages (sha256) with matching content types. - All 83 site directories redirect from `/sites/x` to `/sites/x/`, as on Pages. - All 59 referenced URLs return 200, and repo files outside `sites/` are not served. - In Browserbase sessions, the final URL, title, visible text length and out-of-process iframe count match Pages for every page tested. The OOPIF fixtures, whose child frames stay on `seanmcguire12.github.io`, still produce a separate-process iframe target; the same-origin iframe fixtures still don't. **Related:** browserbase/stagehand-eval-sites#80 (Vercel config) and browserbase/stagehand-eval-sites#81 (self-links made relative, so the `ionwave` URL assertion holds on either host). GitHub Pages stays up, so older commits and published examples keep working. To roll back, revert this PR. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Points eval sites at Vercel instead of GitHub Pages because Pages has been unreliable. The host changes from `https://browserbase.github.io/stagehand-eval-sites/` to `https://stagehand-eval-sites.vercel.app/`; paths under `sites/` are unchanged. **Details** - Updates every eval-sites URL across evals tasks, sdk-ts/Go/Python examples and tests, and docs. - `get_url.ts` now accepts both the old and new hosts, and lines are reflowed where the shorter URL fits. - Verified the Vercel host serves byte-identical files with matching content types, redirects, and 200s for all referenced URLs. - GitHub Pages stays up, so rollback is just reverting this PR. <sup>Written for commit 0f51333. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3141?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/3141?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3141&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. --> **Merge order:** browserbase/stagehand-eval-sites#81 must be merged and live on Vercel before this PR. `act/ionwave` clicks a link on that page and asserts the Vercel URL. Without #81, the link still points to GitHub Pages and the eval fails on every model.
#3140) # why - `localBrowser.connect()` currently loads the bundled extension even when Stagehand is already installed - the `extensionId` param was also opaque (often confused with the browserbase extension ID), & users should not need to know what the extension ID is to connect to a browser # what changed - discover the installed Stagehand extension before loading the bundle in TypeScript, Python, & Go - load the bundled extension **on local connect only** when none is installed or discovery is unsupported - keep disabled, ambiguous, & incompatible installations as errors - deprecate and ignore extension IDs on local & Browserbase connect; supplied IDs no longer select an extension or bypass discovery - keep Browserbase launch's uploaded-extension ID supported - defer Python bundle lookup & Go extraction until fallback loading, with Go cleanup on failure & shutdown # test plan - `cdpClient.test.ts`, `test_cdp_client.py`, & `cdp_client_test.go` use fake CDP responses to verify installed extensions are reused, missing extensions trigger loading, & unsupported discovery falls back only for local connections. disabled, ambiguous, malformed, & permission-error responses fail without loading. - factory tests in all three SDKs now check supplied & empty connect IDs are ignored and never forwarded to CDP. Browserbase connect always selects discovery, while launch keeps its uploaded-extension ID & client options. - Python tests verify bundle lookup is deferred & cancellation during discovery or loading closes the connection. Go tests verify extraction happens only on fallback, its directory stays available during initialization, & cleanup runs once on close, initialization failure, or cancellation. - connection tests verify discovered IDs select the correct worker & incompatible runtimes fail without loading a replacement. loading failures propagate without retrying, & cancellation prevents further loading work. - `localExtensionDiscovery.test.ts` runs against real Chrome with & without Stagehand already installed. it connects with an ignored ID, opens a page through Stagehand, & checks that the browser has exactly one Stagehand installation, preserving the existing installation's ID when reusing it <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Local connects now discover an installed Stagehand extension before falling back to the bundled one, and the `extensionId` parameter on connect calls is deprecated and ignored across all SDKs. - Reuses the installed extension in local and Browserbase connections, falling back to loading the bundled extension only for local connects when none is installed or discovery is unsupported. - Disabled, ambiguous, malformed, and permission-error extension inventories fail without loading a fallback. - `localBrowser.connect()` and `browserbase.connect()` ignore extension IDs, including empty strings, and always discover; Browserbase launch keeps its uploaded-extension ID. - TypeScript connect options accept the ignored `extensionId` at the type level, so code can pass `undefined` or an empty string without compiler errors. - Python and Go defer bundle lookup/extraction until fallback loading, with Go cleanup on failure and shutdown. - Users no longer need to know the extension ID to connect. <sup>Written for commit 1891573. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3140?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/3140?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3140&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 - unspecified type was causing TS to infer it incorrectly # what changed - specified the correct type <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Fixes a TypeScript type inference issue in the docs SDK reference test by explicitly typing the `sdkSlugs` set as `Set<string>`. <sup>Written for commit 71688c1. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3145?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/3145?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3145&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 - added docs for `onToolsAdded()` & `onToolsRemoved()` hooks - also updated the docs test to remove these events from ignored list <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds reference documentation for the `onToolsAdded` and `onToolsRemoved` hooks for TypeScript, Python, and Go, and removes the docs test exception that previously skipped coverage for these hooks. - Documents the subscription lifecycle, tool identity rules, and callback signatures for `page.onToolsAdded()` and `page.onToolsRemoved()`. - Updates the WebMCP reference page to link to the new `onToolsAdded()` docs. - Removes `page/on-tools-added` and `page/on-tools-removed` from the unreleased reference methods set so the SDK surface test now requires these headings on every language page. <sup>Written for commit a692e4d. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3148?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/3148?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3148&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 `waitForSelector()` did not include frame resolution or locator world readiness in its timeout. time spent preparing or retrying the browser wait was not deducted from its timeout. the browser helper also turned zero into a fresh 30-second wait, & could keep watching the page after the caller timed out. # what changed - gave selector waits one shared deadline across frame resolution, locator-world readiness, & the element wait. internal calls reuse their parent's remaining time without taking ownership of its progress. - calculated the browser timeout immediately before dispatch, including retries after a lost execution context. expired calls cannot start another wait. - kept the 30-second default & made explicit `0` unlimited throughout the wait. - gave each browser wait a disposable handle. completion, timeout, & failure release its observers, timers, DOM-ready listener, & remote reference. handles returned after expiry are cleaned up too; concurrent waits stay independent. - bounded cleanup & kept it in the original context. cleanup failure cannot replace the operation's error or trigger a new locator-world lookup. - fixed observer setup before the document root exists & prevented queued callbacks from installing observers after settlement # test plan - `understudy/waitForSelector.test.ts` checks the default, finite, & unlimited deadlines, inherited progress ownership, & time consumed by resolution, readiness, & context recovery. it also covers expiry before dispatch, late installation & results, failed or stalled cleanup, session closure, & separate handles for concurrent waits. - `tests/wait-for-selector.test.ts` checks all four element states, finite expiry, unlimited waits beyond 30 seconds, & cleanup happening once. cases cover early DOM readiness, queued callbacks after settlement, shadow-root scanning, partial installation failure, & disposing one wait while another continues. - the local-browser `waitForSelector.test.ts` adds a held iframe response followed by delayed element creation. it checks that both phases share a finite budget & that unlimited or longer waits succeed. existing cases retain coverage for css, xpath, iframe hops, visibility, & open/closed shadow roots; short state & timeout tests use HTTP fixtures so data-page setup does not consume their budget. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Fixes `waitForSelector()` so frame resolution, locator-world readiness, and the element wait share one timeout, and `timeout: 0` now means unlimited instead of a fresh 30-second wait. **Bug Fixes** - Frame resolution and locator-world readiness time now counts against the same deadline as the element wait. - Expired calls cannot start a new wait; retries after a lost execution context recalculate the remaining budget. - `timeout: 0` is unlimited while the default remains 30 seconds, and the Go, Python, and TypeScript SDK RPC clients now skip their response deadline when a selector wait passes an explicit `0`. - Waits dispose observers, timers, and the remote handle on failure or timeout; on success only the handle is released, and cleanup failure cannot mask the operation's error. <sup>Written for commit bcd7eeb. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/3146?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/3146?returnTo=https%3A%2F%2Fgithub.com%2Fbrowserbase%2Fstagehand%2Fpull%2F3146&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/eve@0.2.0 ### Minor Changes - [#2821](#2821) [`a237c77`](a237c77) Thanks [@shrey150](https://github.com/shrey150)! - Replace the Eve extension's browser and web tools with Stagehand V4 `run`, `snapshot`, and `screenshot`. ### Patch Changes - [#3115](#3115) [`7abca76`](7abca76) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - update the Eve peer dependency to ^0.71.2 to use upstream security fixes. Requires Eve 0.71.2 or later within the 0.71.x release line. - Updated dependencies [[`34edfa3`](34edfa3), [`a837acf`](a837acf), [`4da1a21`](4da1a21), [`5802f59`](5802f59), [`819db28`](819db28), [`0210688`](0210688), [`666b6fa`](666b6fa), [`f3543d3`](f3543d3), [`f2060a6`](f2060a6), [`1562d35`](1562d35), [`7d8dcef`](7d8dcef), [`476658b`](476658b), [`70f4e91`](70f4e91)]: - @browserbasehq/stagehand@4.2.0 ## @browserbasehq/stagehand@4.2.0 ### Minor Changes - [#3030](#3030) [`34edfa3`](34edfa3) Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Export browser pages as PDF bytes in TypeScript, Python, and Go, with configurable print settings and timeouts, and optional local file saving in TypeScript and Python. - [#3118](#3118) [`a837acf`](a837acf) Thanks [@miguelg719](https://github.com/miguelg719)! - Add `clientOptions` to `browserbase.launch()` and `browserbase.connect()`. Thanks to [@pr1m8](https://github.com/pr1m8) for the original proposal that motivated this feature. - [#3083](#3083) [`666b6fa`](666b6fa) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - expose a timeout option for page.snapshot() across all sdks, defaulting to 20 seconds. set it to 0 for unlimited execution. one budget covers the whole snapshot capture. - [#3140](#3140) [`f2060a6`](f2060a6) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - automatically discover Stagehand extensions when connecting to browsers. deprecate & ignore extension IDs passed into .connect(). - [#2916](#2916) [`476658b`](476658b) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add page level hooks for webmcp tools added and webmcp tools removed events. ### Patch Changes - [#3045](#3045) [`4da1a21`](4da1a21) Thanks [@github-actions](https://github.com/apps/github-actions)! - Keep telemetry disabled unless an OTLP traces endpoint is explicitly configured. - [#2893](#2893) [`5802f59`](5802f59) Thanks [@miguelg719](https://github.com/miguelg719)! - Bound experimental batch and RPC deadlines so callers can stop waiting without replaying actions or accepting late capture state. - [#2894](#2894) [`819db28`](819db28) Thanks [@miguelg719](https://github.com/miguelg719)! - Add configurable bounded CDP heartbeats and sanitized disconnect diagnostics with cleanup on shutdown. - [#2892](#2892) [`0210688`](0210688) Thanks [@miguelg719](https://github.com/miguelg719)! - Release a newly created Browserbase session when initial attachment fails, and support upload retries - [#2978](#2978) [`f3543d3`](f3543d3) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Fix locator failures when entering loading iframes, and correctly target iframe elements when an XPath ends at the iframe. - [#3033](#3033) [`1562d35`](1562d35) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add per-call locator timeouts across TypeScript, Python, & Go. one timeout covers frame readiness, element lookup, & execution, including typing delays & highlight duration. the default is 20 seconds. setting timeout to 0 disables it. - [#3146](#3146) [`7d8dcef`](7d8dcef) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Make selector waits include frame readiness in their timeout, support unlimited waits with `timeout: 0`, and clean up observers when the wait ends. - [#3052](#3052) [`70f4e91`](70f4e91) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Match native XPath semantics for `text()` predicates when a shadow root routes locators through the composed-tree parser ## @browserbasehq/stagehand-extension@1.1.0 ### Minor Changes - [#3030](#3030) [`34edfa3`](34edfa3) Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Export browser pages as PDF bytes in TypeScript, Python, and Go, with configurable print settings and timeouts, and optional local file saving in TypeScript and Python. - [#3083](#3083) [`666b6fa`](666b6fa) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - expose a timeout option for page.snapshot() across all sdks, defaulting to 20 seconds. set it to 0 for unlimited execution. one budget covers the whole snapshot capture. - [#2916](#2916) [`476658b`](476658b) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add page level hooks for webmcp tools added and webmcp tools removed events. ### Patch Changes - [#3045](#3045) [`4da1a21`](4da1a21) Thanks [@github-actions](https://github.com/apps/github-actions)! - Keep telemetry disabled unless an OTLP traces endpoint is explicitly configured. - [#2896](#2896) [`7919934`](7919934) Thanks [@miguelg719](https://github.com/miguelg719)! - Snapshot references remain valid across same-origin and out-of-process frame captures - [#2978](#2978) [`f3543d3`](f3543d3) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Fix locator failures when entering loading iframes, and correctly target iframe elements when an XPath ends at the iframe. - [#3033](#3033) [`1562d35`](1562d35) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add per-call locator timeouts across TypeScript, Python, & Go. one timeout covers frame readiness, element lookup, & execution, including typing delays & highlight duration. the default is 20 seconds. setting timeout to 0 disables it. - [#3146](#3146) [`7d8dcef`](7d8dcef) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Make selector waits include frame readiness in their timeout, support unlimited waits with `timeout: 0`, and clean up observers when the wait ends. - [#3052](#3052) [`70f4e91`](70f4e91) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Match native XPath semantics for `text()` predicates when a shadow root routes locators through the composed-tree parser ## @browserbasehq/stagehand-protocol@2.1.0 ### Minor Changes - [#3030](#3030) [`34edfa3`](34edfa3) Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Export browser pages as PDF bytes in TypeScript, Python, and Go, with configurable print settings and timeouts, and optional local file saving in TypeScript and Python. - [#3083](#3083) [`666b6fa`](666b6fa) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - expose a timeout option for page.snapshot() across all sdks, defaulting to 20 seconds. set it to 0 for unlimited execution. one budget covers the whole snapshot capture. - [#2916](#2916) [`476658b`](476658b) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add page level hooks for webmcp tools added and webmcp tools removed events. ### Patch Changes - [#3045](#3045) [`4da1a21`](4da1a21) Thanks [@github-actions](https://github.com/apps/github-actions)! - Keep telemetry disabled unless an OTLP traces endpoint is explicitly configured. - [#3033](#3033) [`1562d35`](1562d35) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add per-call locator timeouts across TypeScript, Python, & Go. one timeout covers frame readiness, element lookup, & execution, including typing delays & highlight duration. the default is 20 seconds. setting timeout to 0 disables it. ## @browserbasehq/stagehand-go@4.2.0 ### Minor Changes - [#3030](#3030) [`34edfa3`](34edfa3) Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Export browser pages as PDF bytes in TypeScript, Python, and Go, with configurable print settings and timeouts, and optional local file saving in TypeScript and Python. - [#3123](#3123) [`100e201`](100e201) Thanks [@miguelg719](https://github.com/miguelg719)! - Add `ClientOptions` to `LaunchBrowserbase` and `ConnectBrowserbase`. - [#3083](#3083) [`666b6fa`](666b6fa) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - expose a timeout option for page.snapshot() across all sdks, defaulting to 20 seconds. set it to 0 for unlimited execution. one budget covers the whole snapshot capture. - [#3140](#3140) [`f2060a6`](f2060a6) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - automatically discover Stagehand extensions when connecting to browsers. deprecate & ignore extension IDs passed into .connect(). - [#2916](#2916) [`476658b`](476658b) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add page level hooks for webmcp tools added and webmcp tools removed events. ### Patch Changes - [#3045](#3045) [`4da1a21`](4da1a21) Thanks [@github-actions](https://github.com/apps/github-actions)! - Keep telemetry disabled unless an OTLP traces endpoint is explicitly configured. - [#2896](#2896) [`7919934`](7919934) Thanks [@miguelg719](https://github.com/miguelg719)! - Snapshot references remain valid across same-origin and out-of-process frame captures - [#2978](#2978) [`f3543d3`](f3543d3) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Fix locator failures when entering loading iframes, and correctly target iframe elements when an XPath ends at the iframe. - [#3033](#3033) [`1562d35`](1562d35) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add per-call locator timeouts across TypeScript, Python, & Go. one timeout covers frame readiness, element lookup, & execution, including typing delays & highlight duration. the default is 20 seconds. setting timeout to 0 disables it. - [#3146](#3146) [`7d8dcef`](7d8dcef) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Make selector waits include frame readiness in their timeout, support unlimited waits with `timeout: 0`, and clean up observers when the wait ends. - [#3052](#3052) [`70f4e91`](70f4e91) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Match native XPath semantics for `text()` predicates when a shadow root routes locators through the composed-tree parser ## @browserbasehq/stagehand-python@4.2.0 ### Minor Changes - [#3030](#3030) [`34edfa3`](34edfa3) Thanks [@supremeboxlogos](https://github.com/supremeboxlogos)! - Export browser pages as PDF bytes in TypeScript, Python, and Go, with configurable print settings and timeouts, and optional local file saving in TypeScript and Python. - [#3118](#3118) [`a837acf`](a837acf) Thanks [@miguelg719](https://github.com/miguelg719)! - Add `client_options` to `browserbase.launch()` and `browserbase.connect()`. - [#3083](#3083) [`666b6fa`](666b6fa) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - expose a timeout option for page.snapshot() across all sdks, defaulting to 20 seconds. set it to 0 for unlimited execution. one budget covers the whole snapshot capture. - [#3140](#3140) [`f2060a6`](f2060a6) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - automatically discover Stagehand extensions when connecting to browsers. deprecate & ignore extension IDs passed into .connect(). - [#2916](#2916) [`476658b`](476658b) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add page level hooks for webmcp tools added and webmcp tools removed events. ### Patch Changes - [#3045](#3045) [`4da1a21`](4da1a21) Thanks [@github-actions](https://github.com/apps/github-actions)! - Keep telemetry disabled unless an OTLP traces endpoint is explicitly configured. - [#2978](#2978) [`f3543d3`](f3543d3) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Fix locator failures when entering loading iframes, and correctly target iframe elements when an XPath ends at the iframe. - [#3033](#3033) [`1562d35`](1562d35) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - add per-call locator timeouts across TypeScript, Python, & Go. one timeout covers frame readiness, element lookup, & execution, including typing delays & highlight duration. the default is 20 seconds. setting timeout to 0 disables it. - [#3146](#3146) [`7d8dcef`](7d8dcef) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Make selector waits include frame readiness in their timeout, support unlimited waits with `timeout: 0`, and clean up observers when the wait ends. - [#3052](#3052) [`70f4e91`](70f4e91) Thanks [@seanmcguire12](https://github.com/seanmcguire12)! - Match native XPath semantics for `text()` predicates when a shadow root routes locators through the composed-tree parser ## @browserbasehq/stagehand-examples@0.0.1 ### Patch Changes - Updated dependencies [[`34edfa3`](34edfa3), [`a837acf`](a837acf), [`4da1a21`](4da1a21), [`5802f59`](5802f59), [`819db28`](819db28), [`0210688`](0210688), [`666b6fa`](666b6fa), [`f3543d3`](f3543d3), [`f2060a6`](f2060a6), [`1562d35`](1562d35), [`7d8dcef`](7d8dcef), [`476658b`](476658b), [`70f4e91`](70f4e91)]: - @browserbasehq/stagehand@4.2.0 - @browserbasehq/stagehand-integrations@4.0.4 ## @browserbasehq/stagehand-integrations-claude-agent-sdk@4.0.3 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.4 ## @browserbasehq/stagehand-integrations-example-claude-code-facade@4.0.4 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.4 - @browserbasehq/stagehand-integrations-claude-agent-sdk@4.0.3 ## @browserbasehq/stagehand-integrations-claude-cua-sdk@4.0.2 ### Patch Changes - Updated dependencies [[`34edfa3`](34edfa3), [`a837acf`](a837acf), [`4da1a21`](4da1a21), [`5802f59`](5802f59), [`819db28`](819db28), [`0210688`](0210688), [`666b6fa`](666b6fa), [`f3543d3`](f3543d3), [`f2060a6`](f2060a6), [`1562d35`](1562d35), [`7d8dcef`](7d8dcef), [`476658b`](476658b), [`70f4e91`](70f4e91)]: - @browserbasehq/stagehand@4.2.0 - @browserbasehq/stagehand-integrations@4.0.4 ## @browserbasehq/stagehand-integrations-example-codex-facade@4.0.4 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.4 - @browserbasehq/stagehand-integrations-codex-sdk@4.0.3 ## @browserbasehq/stagehand-integrations-codex-sdk@4.0.3 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.4 ## @browserbasehq/stagehand-integrations@4.0.4 ### Patch Changes - Updated dependencies [[`34edfa3`](34edfa3), [`a837acf`](a837acf), [`4da1a21`](4da1a21), [`5802f59`](5802f59), [`819db28`](819db28), [`0210688`](0210688), [`666b6fa`](666b6fa), [`f3543d3`](f3543d3), [`f2060a6`](f2060a6), [`1562d35`](1562d35), [`7d8dcef`](7d8dcef), [`476658b`](476658b), [`70f4e91`](70f4e91)]: - @browserbasehq/stagehand@4.2.0 ## @browserbasehq/stagehand-integrations-example-cursor-facade@4.0.2 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.4 - @browserbasehq/stagehand-integrations-cursor-sdk@4.0.3 ## @browserbasehq/stagehand-integrations-cursor-sdk@4.0.3 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.4 ## @browserbasehq/stagehand-integrations-deepagents-sdk@4.0.3 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.4 ## @browserbasehq/stagehand-integrations-eve-sdk@4.0.3 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.4 ## @browserbasehq/stagehand-integrations-fx-sdk@4.0.3 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.4 ## @browserbasehq/stagehand-integrations-gemini-cua-sdk@4.0.2 ### Patch Changes - Updated dependencies [[`34edfa3`](34edfa3), [`a837acf`](a837acf), [`4da1a21`](4da1a21), [`5802f59`](5802f59), [`819db28`](819db28), [`0210688`](0210688), [`666b6fa`](666b6fa), [`f3543d3`](f3543d3), [`f2060a6`](f2060a6), [`1562d35`](1562d35), [`7d8dcef`](7d8dcef), [`476658b`](476658b), [`70f4e91`](70f4e91)]: - @browserbasehq/stagehand@4.2.0 - @browserbasehq/stagehand-integrations@4.0.4 ## @browserbasehq/stagehand-integrations-example-mastra-facade@4.0.4 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.4 ## @browserbasehq/stagehand-integrations-mastra-sdk@4.0.3 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.4 ## @browserbasehq/stagehand-integrations-example-pi-facade@4.0.4 ### Patch Changes - Updated dependencies [[`34edfa3`](34edfa3), [`a837acf`](a837acf), [`4da1a21`](4da1a21), [`5802f59`](5802f59), [`819db28`](819db28), [`0210688`](0210688), [`666b6fa`](666b6fa), [`f3543d3`](f3543d3), [`f2060a6`](f2060a6), [`1562d35`](1562d35), [`7d8dcef`](7d8dcef), [`476658b`](476658b), [`70f4e91`](70f4e91)]: - @browserbasehq/stagehand@4.2.0 - @browserbasehq/stagehand-integrations@4.0.4 ## @browserbasehq/stagehand-integrations-pi-sdk@4.0.3 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.4 ## @browserbasehq/stagehand-integrations-example-vercel-ai-facade@4.0.4 ### Patch Changes - Updated dependencies []: - @browserbasehq/stagehand-integrations@4.0.4 --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Miguel <36487034+miguelg719@users.noreply.github.com>
# Conflicts: # packages/docs/docs.json # packages/docs/v4/integrations/cli-agents/overview.mdx # packages/docs/v4/integrations/overview.mdx
|
Contributor
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
miguelg719
approved these changes
Oct 8, 2026
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
why
Summary by cubic
Carries all changes from
maininto the docs branch so the docs tree matches the latest SDK releases, eval harness updates, and recent documentation additions (cookbooks, CLI agent guides, and new reference pages). This is a plain branch sync with no source changes of its own.Written for commit 72c306d. Summary will update on new commits.