Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
feac39d
fix(client): preserve hardcoded query params when merging with user p…
stainless-app[bot] Apr 8, 2026
9463fa4
feat: Bedrock auth passthrough
stainless-app[bot] Apr 8, 2026
078ab5c
feat: [STG-1798] feat: support Browserbase verified sessions
stainless-app[bot] Apr 8, 2026
3c04086
feat: Revert "[STG-1573] Add providerOptions for extensible model aut…
stainless-app[bot] Apr 9, 2026
b870657
fix: ensure file data are only sent as 1 parameter
stainless-app[bot] Apr 11, 2026
69d396f
perf(client): optimize file structure copying in multipart requests
stainless-app[bot] Apr 18, 2026
9bc61e1
chore(internal): more robust bootstrap script
stainless-app[bot] Apr 23, 2026
852600a
fix: use correct field name format for multipart file arrays
stainless-app[bot] Apr 28, 2026
b1c6127
feat: support setting headers via env
stainless-app[bot] Apr 28, 2026
57f0c9b
codegen metadata
stainless-app[bot] Apr 30, 2026
4b22fce
[STG-1808] Prefer STAGEHAND_API_URL env fallback
monadoid Apr 30, 2026
97016ef
codegen metadata
stainless-app[bot] May 1, 2026
05f8a76
Deprecate browserbase project ID (#91)
monadoid May 6, 2026
03f4dbe
chore(internal): reformat pyproject.toml
stainless-app[bot] May 6, 2026
f11a102
feat: [feat]: add `ignoreSelectors` to `extract()`
stainless-app[bot] May 6, 2026
bfe505c
feat: [STG-1808] Deprecate Browserbase project ID
stainless-app[bot] May 6, 2026
92ed1e1
feat: remove experimental requirement on agent variables (#2079)
stainless-app[bot] May 6, 2026
6ceba63
release: 3.20.0
stainless-app[bot] May 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
BROWSERBASE_API_KEY=bb_live_your_api_key_here
BROWSERBASE_PROJECT_ID=your-bb-project-uuid-here
MODEL_API_KEY=sk-proj-your-llm-api-key-here
MODEL_API_KEY=sk-proj-your-llm-api-key-here
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "3.19.5"
".": "3.20.0"
}
6 changes: 3 additions & 3 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 8
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-b969ce378479c79ee64c05127c0ed6c6ce2edbee017ecd037242fb618a5ebc9f.yml
openapi_spec_hash: a24aabaa5214effb679808b7f2be0ad4
config_hash: 0cc516caf1432087f40654336e0fa8cd
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-6f6bfb81d092f30a5e2005328c97d61b9ea36132bb19e9e79e55294b9534ce20.yml
openapi_spec_hash: f3fc1e3688a38dc2c28f7178f7d534e5
config_hash: 1fb12ae9b478488bc1e56bfbdc210b01
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
# Changelog

## 3.20.0 (2026-05-06)

Full Changelog: [v3.19.5...v3.20.0](https://github.com/browserbase/stagehand-python/compare/v3.19.5...v3.20.0)

### Features

* [feat]: add `ignoreSelectors` to `extract()` ([f11a102](https://github.com/browserbase/stagehand-python/commit/f11a102884344ddefd2dd0b98f22fea687a12e6e))
* [STG-1798] feat: support Browserbase verified sessions ([078ab5c](https://github.com/browserbase/stagehand-python/commit/078ab5c76f13beee16e44d7eed5e3018f1cc5bd8))
* [STG-1808] Deprecate Browserbase project ID ([bfe505c](https://github.com/browserbase/stagehand-python/commit/bfe505cb1c3c1c6a85d7873ee05860476d71a9d6))
* Bedrock auth passthrough ([9463fa4](https://github.com/browserbase/stagehand-python/commit/9463fa49cb839abbb2c6a1adb0d053e5006216a7))
* remove experimental requirement on agent variables ([#2079](https://github.com/browserbase/stagehand-python/issues/2079)) ([92ed1e1](https://github.com/browserbase/stagehand-python/commit/92ed1e1d43e89d92ffc4c3aa30c7f1a521f5d0e6))
* Revert "[STG-1573] Add providerOptions for extensible model auth ([#1822](https://github.com/browserbase/stagehand-python/issues/1822))" ([3c04086](https://github.com/browserbase/stagehand-python/commit/3c0408675154c9f7d241c4e92e9cb82f0419d6b3))
* support setting headers via env ([b1c6127](https://github.com/browserbase/stagehand-python/commit/b1c61276ff9cecf89c078e1d97a6b927d8d308e1))


### Bug Fixes

* **client:** preserve hardcoded query params when merging with user params ([feac39d](https://github.com/browserbase/stagehand-python/commit/feac39d88a841ff710d672b622f3280037589f66))
* ensure file data are only sent as 1 parameter ([b870657](https://github.com/browserbase/stagehand-python/commit/b8706575ab0f95b9e6781ee3685f9b79e0fe6036))
* use correct field name format for multipart file arrays ([852600a](https://github.com/browserbase/stagehand-python/commit/852600a4c6169df6497fc4d77a06abae8812e375))


### Performance Improvements

* **client:** optimize file structure copying in multipart requests ([69d396f](https://github.com/browserbase/stagehand-python/commit/69d396fa404d0ad3905786dcf6f56be8be7ab9b2))


### Chores

* **internal:** more robust bootstrap script ([9bc61e1](https://github.com/browserbase/stagehand-python/commit/9bc61e12f1599b14dd8b2a0c38a50c089512e9c7))
* **internal:** reformat pyproject.toml ([03f4dbe](https://github.com/browserbase/stagehand-python/commit/03f4dbe5ef6e230f3e96302ba8e5f4064edda10f))

## 3.19.5 (2026-04-03)

Full Changelog: [v3.19.4...v3.19.5](https://github.com/browserbase/stagehand-python/compare/v3.19.4...v3.19.5)
Expand Down
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,8 @@ Python 3.9 or higher.

Set your environment variables (from `examples/.env.example`):

- `STAGEHAND_API_URL`
- `MODEL_API_KEY`
- `BROWSERBASE_API_KEY`
- `BROWSERBASE_PROJECT_ID`

```bash
cp examples/.env.example examples/.env
Expand Down Expand Up @@ -139,7 +137,6 @@ def main() -> None:
with Stagehand(
server="remote",
browserbase_api_key=os.environ.get("BROWSERBASE_API_KEY"),
browserbase_project_id=os.environ.get("BROWSERBASE_PROJECT_ID"),
model_api_key=os.environ.get("MODEL_API_KEY"),
) as client:
session = client.sessions.start(
Expand Down Expand Up @@ -234,7 +231,6 @@ from stagehand import AsyncStagehand

client = AsyncStagehand(
browserbase_api_key="My Browserbase API Key",
browserbase_project_id="My Browserbase Project ID",
model_api_key="My Model API Key",
)
```
Expand All @@ -255,9 +251,11 @@ See this table for the available options:
| Keyword argument | Environment variable | Required | Default value |
| ------------------------ | ------------------------ | -------- | ----------------------------------------- |
| `browserbase_api_key` | `BROWSERBASE_API_KEY` | true | - |
| `browserbase_project_id` | `BROWSERBASE_PROJECT_ID` | true | - |
| `browserbase_project_id` | - | false | - |
| `model_api_key` | `MODEL_API_KEY` | true | - |
| `base_url` | `STAGEHAND_BASE_URL` | false | `"https://api.stagehand.browserbase.com"` |
| `base_url` | `STAGEHAND_API_URL` | false | `"https://api.stagehand.browserbase.com"` |

`browserbase_project_id` is deprecated, accepted for backwards compatibility, and ignored. `STAGEHAND_BASE_URL` remains supported as a deprecated fallback when `STAGEHAND_API_URL` is unset.

Keyword arguments take precedence over environment variables.

Expand Down Expand Up @@ -662,7 +660,7 @@ import httpx
from stagehand import Stagehand, DefaultHttpxClient

client = Stagehand(
# Or use the `STAGEHAND_BASE_URL` env var
# Or use the `STAGEHAND_API_URL` env var, with `STAGEHAND_BASE_URL` as a fallback
base_url="http://my.test.server.example.com:8083",
http_client=DefaultHttpxClient(
proxy="http://my.test.proxy.example.com",
Expand Down
2 changes: 0 additions & 2 deletions examples/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
STAGEHAND_API_URL=https://api.stagehand.browserbase.com
MODEL_API_KEY=sk-proj-your-llm-api-key-here
BROWSERBASE_API_KEY=bb_live_your_api_key_here
BROWSERBASE_PROJECT_ID=your-bb-project-uuid-here
4 changes: 1 addition & 3 deletions examples/act_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

Required environment variables:
- BROWSERBASE_API_KEY: Your Browserbase API key
- BROWSERBASE_PROJECT_ID: Your Browserbase project ID
- MODEL_API_KEY: Your OpenAI API key
"""

Expand Down Expand Up @@ -45,10 +44,9 @@ async def main() -> None:
load_example_env()
load_example_env()
# Create client using environment variables
# BROWSERBASE_API_KEY, BROWSERBASE_PROJECT_ID, MODEL_API_KEY
# BROWSERBASE_API_KEY and MODEL_API_KEY
async with AsyncStagehand(
browserbase_api_key=os.environ.get("BROWSERBASE_API_KEY"),
browserbase_project_id=os.environ.get("BROWSERBASE_PROJECT_ID"),
model_api_key=os.environ.get("MODEL_API_KEY"),
) as client:
# Start a new browser session
Expand Down
1 change: 0 additions & 1 deletion examples/agent_execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

Required environment variables:
- BROWSERBASE_API_KEY
- BROWSERBASE_PROJECT_ID
- MODEL_API_KEY

Optional:
Expand Down
2 changes: 0 additions & 2 deletions examples/byob_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

Required environment variables:
- BROWSERBASE_API_KEY
- BROWSERBASE_PROJECT_ID
- MODEL_API_KEY

Usage:
Expand Down Expand Up @@ -52,7 +51,6 @@ async def main() -> None:
load_example_env()
async with AsyncStagehand(
browserbase_api_key=os.environ.get("BROWSERBASE_API_KEY"),
browserbase_project_id=os.environ.get("BROWSERBASE_PROJECT_ID"),
model_api_key=os.environ.get("MODEL_API_KEY"),
) as client, async_playwright() as playwright:
browser = await playwright.chromium.launch(headless=True)
Expand Down
5 changes: 0 additions & 5 deletions examples/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
from pathlib import Path

REQUIRED_KEYS = {
"STAGEHAND_API_URL",
"MODEL_API_KEY",
"BROWSERBASE_API_KEY",
"BROWSERBASE_PROJECT_ID",
}


Expand Down Expand Up @@ -44,9 +42,6 @@ def load_example_env() -> None:
+ " (from examples/.env)"
)

# Normalize for SDKs that expect STAGEHAND_BASE_URL
os.environ.setdefault("STAGEHAND_BASE_URL", os.environ["STAGEHAND_API_URL"])

# Use the repo-local SEA binary when available (avoid global installs).
sea_binary = env_path.parent.parent / "bin" / "sea" / "stagehand-darwin-arm64"
if sea_binary.exists():
Expand Down
4 changes: 1 addition & 3 deletions examples/full_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

Required environment variables:
- BROWSERBASE_API_KEY: Your Browserbase API key
- BROWSERBASE_PROJECT_ID: Your Browserbase project ID
- MODEL_API_KEY: Your OpenAI API key
"""

Expand Down Expand Up @@ -47,10 +46,9 @@ async def main() -> None:
load_example_env()
load_example_env()
# Create client using environment variables
# BROWSERBASE_API_KEY, BROWSERBASE_PROJECT_ID, MODEL_API_KEY
# BROWSERBASE_API_KEY and MODEL_API_KEY
async with AsyncStagehand(
browserbase_api_key=os.environ.get("BROWSERBASE_API_KEY"),
browserbase_project_id=os.environ.get("BROWSERBASE_PROJECT_ID"),
model_api_key=os.environ.get("MODEL_API_KEY"),
) as client:
# Start a new browser session (returns a session helper bound to a session_id)
Expand Down
11 changes: 3 additions & 8 deletions examples/local_browser_playwright_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@
Environment variables required:
- MODEL_API_KEY
- BROWSERBASE_API_KEY (can be any value in local mode)
- BROWSERBASE_PROJECT_ID (can be any value in local mode)

Optional:
- STAGEHAND_BASE_URL (defaults to http://127.0.0.1:3000)
- STAGEHAND_API_URL or STAGEHAND_BASE_URL (defaults to http://127.0.0.1:3000)
"""

from __future__ import annotations
Expand Down Expand Up @@ -82,11 +81,8 @@ def main() -> None:
sys.exit("Set the MODEL_API_KEY environment variable to run this example.")

bb_api_key = os.environ.get("BROWSERBASE_API_KEY")
bb_project_id = os.environ.get("BROWSERBASE_PROJECT_ID")
if not bb_api_key or not bb_project_id:
sys.exit(
"Set BROWSERBASE_API_KEY and BROWSERBASE_PROJECT_ID to run this example."
)
if not bb_api_key:
sys.exit("Set BROWSERBASE_API_KEY to run this example.")

try:
from playwright.sync_api import sync_playwright # type: ignore[import-not-found]
Expand All @@ -102,7 +98,6 @@ def main() -> None:
with Stagehand(
server="local",
browserbase_api_key=bb_api_key,
browserbase_project_id=bb_project_id,
model_api_key=model_api_key,
local_ready_timeout_s=30.0,
) as client:
Expand Down
1 change: 0 additions & 1 deletion examples/local_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

Required environment variables:
- BROWSERBASE_API_KEY (can be any value in local mode)
- BROWSERBASE_PROJECT_ID (can be any value in local mode)
- MODEL_API_KEY (read by this example and passed explicitly to the client)


Expand Down
11 changes: 3 additions & 8 deletions examples/local_server_multiregion_browser_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@
Environment variables required:
- MODEL_API_KEY
- BROWSERBASE_API_KEY
- BROWSERBASE_PROJECT_ID

Optional:
- STAGEHAND_BASE_URL (defaults to http://127.0.0.1:3000 when server="local")
- STAGEHAND_API_URL or STAGEHAND_BASE_URL (defaults to http://127.0.0.1:3000 when server="local")
"""

from __future__ import annotations
Expand Down Expand Up @@ -53,11 +52,8 @@ def main() -> None:
sys.exit("Set the MODEL_API_KEY environment variable to run this example.")

bb_api_key = os.environ.get("BROWSERBASE_API_KEY")
bb_project_id = os.environ.get("BROWSERBASE_PROJECT_ID")
if not bb_api_key or not bb_project_id:
sys.exit(
"Set BROWSERBASE_API_KEY and BROWSERBASE_PROJECT_ID to run this example."
)
if not bb_api_key:
sys.exit("Set BROWSERBASE_API_KEY to run this example.")

try:
from playwright.sync_api import sync_playwright # type: ignore[import-not-found]
Expand All @@ -73,7 +69,6 @@ def main() -> None:
with Stagehand(
server="local",
browserbase_api_key=bb_api_key,
browserbase_project_id=bb_project_id,
model_api_key=model_api_key,
local_ready_timeout_s=30.0,
) as client:
Expand Down
2 changes: 0 additions & 2 deletions examples/logging_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

Required environment variables:
- BROWSERBASE_API_KEY: Your Browserbase API key
- BROWSERBASE_PROJECT_ID: Your Browserbase project ID
- MODEL_API_KEY: Your OpenAI API key
"""

Expand All @@ -23,7 +22,6 @@ async def main() -> None:
# Create client using environment variables
async with AsyncStagehand(
browserbase_api_key=os.environ.get("BROWSERBASE_API_KEY"),
browserbase_project_id=os.environ.get("BROWSERBASE_PROJECT_ID"),
model_api_key=os.environ.get("MODEL_API_KEY"),
) as client:
# Start a new browser session with verbose logging enabled
Expand Down
11 changes: 3 additions & 8 deletions examples/playwright_page_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@
Environment variables required:
- MODEL_API_KEY
- BROWSERBASE_API_KEY
- BROWSERBASE_PROJECT_ID

Optional:
- STAGEHAND_BASE_URL (defaults to https://api.stagehand.browserbase.com)
- STAGEHAND_API_URL or STAGEHAND_BASE_URL (defaults to https://api.stagehand.browserbase.com)
"""

from __future__ import annotations
Expand Down Expand Up @@ -52,11 +51,8 @@ def main() -> None:
sys.exit("Set the MODEL_API_KEY environment variable to run this example.")

bb_api_key = os.environ.get("BROWSERBASE_API_KEY")
bb_project_id = os.environ.get("BROWSERBASE_PROJECT_ID")
if not bb_api_key or not bb_project_id:
sys.exit(
"Set BROWSERBASE_API_KEY and BROWSERBASE_PROJECT_ID to run this example."
)
if not bb_api_key:
sys.exit("Set BROWSERBASE_API_KEY to run this example.")

try:
from playwright.sync_api import sync_playwright # type: ignore[import-not-found]
Expand All @@ -72,7 +68,6 @@ def main() -> None:
with Stagehand(
server="remote",
browserbase_api_key=bb_api_key,
browserbase_project_id=bb_project_id,
model_api_key=model_api_key,
) as client:
print("⏳ Starting Stagehand session...")
Expand Down
9 changes: 3 additions & 6 deletions examples/pydoll_tab_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@
Environment variables required:
- MODEL_API_KEY
- BROWSERBASE_API_KEY
- BROWSERBASE_PROJECT_ID

Optional:
- STAGEHAND_BASE_URL (defaults to https://api.stagehand.browserbase.com)
- STAGEHAND_API_URL or STAGEHAND_BASE_URL (defaults to https://api.stagehand.browserbase.com)

Notes:
- This example requires Python 3.10+ because `pydoll-python` requires Python 3.10+.
Expand Down Expand Up @@ -121,9 +120,8 @@ async def main() -> None:
sys.exit("Set the MODEL_API_KEY environment variable to run this example.")

bb_api_key = os.environ.get("BROWSERBASE_API_KEY")
bb_project_id = os.environ.get("BROWSERBASE_PROJECT_ID")
if not bb_api_key or not bb_project_id:
sys.exit("Set BROWSERBASE_API_KEY and BROWSERBASE_PROJECT_ID to run this example.")
if not bb_api_key:
sys.exit("Set BROWSERBASE_API_KEY to run this example.")

try:
from pydoll.browser.chromium import Chrome # type: ignore[import-not-found]
Expand All @@ -138,7 +136,6 @@ async def main() -> None:
async with AsyncStagehand(
server="remote",
browserbase_api_key=bb_api_key,
browserbase_project_id=bb_project_id,
model_api_key=model_api_key,
) as client:
print("⏳ Starting Stagehand session...")
Expand Down
11 changes: 3 additions & 8 deletions examples/remote_browser_playwright_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@
Environment variables required:
- MODEL_API_KEY
- BROWSERBASE_API_KEY
- BROWSERBASE_PROJECT_ID

Optional:
- STAGEHAND_BASE_URL (defaults to https://api.stagehand.browserbase.com)
- STAGEHAND_API_URL or STAGEHAND_BASE_URL (defaults to https://api.stagehand.browserbase.com)
"""

from __future__ import annotations
Expand Down Expand Up @@ -54,11 +53,8 @@ def main() -> None:
sys.exit("Set the MODEL_API_KEY environment variable to run this example.")

bb_api_key = os.environ.get("BROWSERBASE_API_KEY")
bb_project_id = os.environ.get("BROWSERBASE_PROJECT_ID")
if not bb_api_key or not bb_project_id:
sys.exit(
"Set BROWSERBASE_API_KEY and BROWSERBASE_PROJECT_ID to run this example."
)
if not bb_api_key:
sys.exit("Set BROWSERBASE_API_KEY to run this example.")

try:
from playwright.sync_api import sync_playwright # type: ignore[import-not-found]
Expand All @@ -74,7 +70,6 @@ def main() -> None:
with Stagehand(
server="remote",
browserbase_api_key=bb_api_key,
browserbase_project_id=bb_project_id,
model_api_key=model_api_key,
) as client:
print("⏳ Starting Stagehand session...")
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "stagehand"
version = "3.19.5"
version = "3.20.0"
description = "The official Python library for the stagehand API"
dynamic = ["readme"]
license = "MIT"
Expand Down
Loading
Loading