Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
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
152 changes: 147 additions & 5 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
@@ -1,28 +1,170 @@
# This workflow is triggered when a GitHub release is created.
# It can also be run manually to re-publish to PyPI in case it failed for some reason.
# You can run this workflow by navigating to https://www.github.com/browserbase/stagehand-python/actions/workflows/publish-pypi.yml
name: Publish PyPI

on:
workflow_dispatch:
inputs:
stagehand_tag:
description: "Stagehand repo git ref to build SEA binaries from (e.g. @browserbasehq/[email protected])"
required: true
type: string

release:
types: [published]

jobs:
build_wheels:
name: build wheels (${{ matrix.binary_name }})
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
binary_name: stagehand-linux-x64
output_path: src/stagehand/_sea/stagehand-linux-x64
wheel_platform_tag: manylinux2014_x86_64
- os: macos-latest
binary_name: stagehand-darwin-arm64
output_path: src/stagehand/_sea/stagehand-darwin-arm64
wheel_platform_tag: macosx_11_0_arm64
- os: macos-13
binary_name: stagehand-darwin-x64
output_path: src/stagehand/_sea/stagehand-darwin-x64
wheel_platform_tag: macosx_10_9_x86_64
- os: windows-latest
binary_name: stagehand-win32-x64.exe
output_path: src/stagehand/_sea/stagehand-win32-x64.exe
wheel_platform_tag: win_amd64

runs-on: ${{ matrix.os }}
permissions:
contents: read

steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v5
with:
version: "0.9.13"

- name: Checkout stagehand (server source)
uses: actions/checkout@v4
with:
repository: browserbase/stagehand
ref: ${{ inputs.stagehand_tag || vars.STAGEHAND_TAG }}
path: _stagehand
fetch-depth: 1
# If browserbase/stagehand is private, set STAGEHAND_SOURCE_TOKEN (PAT) in this repo.
token: ${{ secrets.STAGEHAND_SOURCE_TOKEN || github.token }}

- name: Setup pnpm
uses: pnpm/action-setup@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "23"
cache: "pnpm"
cache-dependency-path: _stagehand/pnpm-lock.yaml

- name: Build SEA server binary (from source)
shell: bash
run: |
set -euo pipefail

if [[ -z "${{ inputs.stagehand_tag }}" && -z "${{ vars.STAGEHAND_TAG }}" ]]; then
echo "Missing stagehand ref: set repo variable STAGEHAND_TAG or provide workflow input stagehand_tag." >&2
exit 1
fi

# Ensure we only ship the binary built for this runner's OS/arch.
python - <<'PY'
from pathlib import Path
sea_dir = Path("src/stagehand/_sea")
sea_dir.mkdir(parents=True, exist_ok=True)
for p in sea_dir.glob("stagehand-*"):
p.unlink(missing_ok=True)
for p in sea_dir.glob("*.exe"):
p.unlink(missing_ok=True)
PY

pushd _stagehand >/dev/null
pnpm install --frozen-lockfile
CI=true pnpm --filter @browserbasehq/stagehand-server build:binary
popd >/dev/null

cp "_stagehand/packages/server/dist/sea/${{ matrix.binary_name }}" "${{ matrix.output_path }}"
chmod +x "${{ matrix.output_path }}" 2>/dev/null || true

- name: Build wheel
env:
STAGEHAND_WHEEL_TAG: py3-none-${{ matrix.wheel_platform_tag }}
run: uv build --wheel

- name: Upload wheel artifact
uses: actions/upload-artifact@v4
with:
name: wheel-${{ matrix.binary_name }}
path: dist/*.whl
retention-days: 7

build_sdist:
name: build sdist
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v5
with:
version: "0.9.13"

- name: Build sdist
run: uv build --sdist

- name: Upload sdist artifact
uses: actions/upload-artifact@v4
with:
name: sdist
path: dist/*.tar.gz
retention-days: 7

publish:
name: publish
needs: [build_wheels, build_sdist]
runs-on: ubuntu-latest

permissions:
contents: read
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v5
with:
version: '0.9.13'
version: "0.9.13"

- name: Publish to PyPI
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
path: dist

- name: Flatten dist directory
shell: bash
run: |
bash ./bin/publish-pypi
set -euo pipefail
mkdir -p dist_out
find dist -type f \( -name "*.whl" -o -name "*.tar.gz" \) -print0 | while IFS= read -r -d '' f; do
cp -f "$f" dist_out/
done
ls -la dist_out

- name: Publish to PyPI
env:
PYPI_TOKEN: ${{ secrets.STAGEHAND_PYPI_TOKEN || secrets.PYPI_TOKEN }}
run: |
set -euo pipefail
uv publish --token="$PYPI_TOKEN" dist_out/*
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ dist
.venv
.idea

.DS_Store
src/stagehand/_sea/stagehand-*
src/stagehand/_sea/*.exe
bin/sea/
.env
.envrc
codegen.log
Expand Down
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.1.0"
".": "0.2.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: 7
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-ed52466945f2f8dfd3814a29e948d7bf30af7b76a7a7689079c03b8baf64e26f.yml
openapi_spec_hash: 5d57aaf2362b0d882372dbf76477ba23
config_hash: 989ddfee371586e9156b4d484ec0a6cc
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase%2Fstagehand-39cd9547d16412cf0568f6ce2ad8d43805dffe65bde830beeff630b903ae3b38.yml
openapi_spec_hash: 9cd7c9fefa686f9711392782d948470f
config_hash: 1f709f8775e13029dc60064ef3a94355
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## 0.2.0 (2026-01-06)

Full Changelog: [v0.1.0...v0.2.0](https://github.com/browserbase/stagehand-python/compare/v0.1.0...v0.2.0)

### Features

* Added optional param to force empty object ([b15e097](https://github.com/browserbase/stagehand-python/commit/b15e0976bc356e0ce09b331705ccd2b8805e1bfa))
* **api:** manual updates ([5a3f419](https://github.com/browserbase/stagehand-python/commit/5a3f419522d49d132c4a75bf310eef1d9695a5a4))


### Documentation

* prominently feature MCP server setup in root SDK readmes ([d5a8361](https://github.com/browserbase/stagehand-python/commit/d5a83610cd39ccdecc1825d67a56ab2835d9651f))

## 0.1.0 (2025-12-23)

Full Changelog: [v0.0.1...v0.1.0](https://github.com/browserbase/stagehand-python/compare/v0.0.1...v0.1.0)
Expand Down
41 changes: 41 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,47 @@ Most of the SDK is generated code. Modifications to code will be persisted betwe
result in merge conflicts between manual patches and changes from the generator. The generator will never
modify the contents of the `src/stagehand/lib/` and `examples/` directories.

## Setting up the local server binary (for development)

The SDK supports running a local Stagehand server for development and testing. To use this feature, you need to download the appropriate binary for your platform.

### Quick setup

Run the download script to automatically download the correct binary:

```sh
$ uv run python scripts/download-binary.py
```

This will:
- Detect your platform (macOS, Linux, Windows) and architecture (x64, arm64)
- Download the latest stagehand-server binary from GitHub releases
- Place it in `bin/sea/` where the SDK expects to find it

### Manual download (alternative)

You can also manually download from [GitHub releases](https://github.com/browserbase/stagehand/releases):

1. Find the latest `stagehand/server vX.X.X` release
2. Download the binary for your platform:
- macOS ARM: `stagehand-server-darwin-arm64`
- macOS Intel: `stagehand-server-darwin-x64`
- Linux: `stagehand-server-linux-x64` or `stagehand-server-linux-arm64`
- Windows: `stagehand-server-win32-x64.exe` or `stagehand-server-win32-arm64.exe`
3. Rename it to match the expected format (remove `-server` from the name):
- `stagehand-darwin-arm64`, `stagehand-linux-x64`, `stagehand-win32-x64.exe`, etc.
4. Place it in `bin/sea/` directory
5. Make it executable (Unix only): `chmod +x bin/sea/stagehand-*`

### Using an environment variable (optional)

Instead of placing the binary in `bin/sea/`, you can point to any binary location:

```sh
$ export STAGEHAND_SEA_BINARY=/path/to/your/stagehand-binary
$ uv run python test_local_mode.py
```

## Adding and running examples

All files in the `examples/` directory are not modified by the generator and can be freely edited or added to.
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright 2025 Stagehand
Copyright 2026 Stagehand

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
64 changes: 50 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ and offers both synchronous and asynchronous clients powered by [httpx](https://

It is generated with [Stainless](https://www.stainless.com/).

## MCP Server

Use the Stagehand MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.

[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=stagehand-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInN0YWdlaGFuZC1tY3AiXX0)
[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22stagehand-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22stagehand-mcp%22%5D%7D)

> Note: You may need to set environment variables in your MCP client.

## Documentation

The REST API documentation can be found on [docs.stagehand.dev](https://docs.stagehand.dev). The full API of this library can be found in [api.md](api.md).
Expand All @@ -20,35 +29,62 @@ The REST API documentation can be found on [docs.stagehand.dev](https://docs.sta
pip install stagehand-alpha
```

## Running the Example

A complete working example is available at [`examples/full_example.py`](examples/full_example.py).

To run it, first export the required environment variables, then use Python:

```bash
export BROWSERBASE_API_KEY="your-bb-api-key"
export BROWSERBASE_PROJECT_ID="your-bb-project-uuid"
export MODEL_API_KEY="sk-proj-your-llm-api-key"

python examples/full_example.py
```

## Usage

The full API of this library can be found in [api.md](api.md).

## Client configuration

Configure the client using environment variables:

```python
from stagehand import Stagehand

# Configures using the BROWSERBASE_API_KEY, BROWSERBASE_PROJECT_ID, and MODEL_API_KEY environment variables
client = Stagehand()
```

Or manually:

```python
import os
from stagehand import Stagehand

client = Stagehand(
browserbase_api_key=os.environ.get(
"BROWSERBASE_API_KEY"
), # This is the default and can be omitted
browserbase_project_id=os.environ.get(
"BROWSERBASE_PROJECT_ID"
), # This is the default and can be omitted
model_api_key=os.environ.get("MODEL_API_KEY"), # This is the default and can be omitted
browserbase_api_key="My Browserbase API Key",
browserbase_project_id="My Browserbase Project ID",
model_api_key="My Model API Key",
)
```

response = client.sessions.act(
id="00000000-your-session-id-000000000000",
input="click the first link on the page",
Or using a combination of the two approaches:

```python
from stagehand import Stagehand

client = Stagehand(
# Configures using environment variables
browserbase_api_key="My Browserbase API Key", # Override just this one
)
print(response.data)
```

While you can provide a `browserbase_api_key` keyword argument,
While you can provide API keys as keyword arguments,
we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)
to add `BROWSERBASE_API_KEY="My Browserbase API Key"` to your `.env` file
so that your Browserbase API Key is not stored in source control.
so that your API keys are not stored in source control.

## Async usage

Expand Down
2 changes: 1 addition & 1 deletion api.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ from stagehand.types import (
Methods:

- <code title="post /v1/sessions/{id}/act">client.sessions.<a href="./src/stagehand/resources/sessions.py">act</a>(id, \*\*<a href="src/stagehand/types/session_act_params.py">params</a>) -> <a href="./src/stagehand/types/session_act_response.py">SessionActResponse</a></code>
- <code title="post /v1/sessions/{id}/end">client.sessions.<a href="./src/stagehand/resources/sessions.py">end</a>(id) -> <a href="./src/stagehand/types/session_end_response.py">SessionEndResponse</a></code>
- <code title="post /v1/sessions/{id}/end">client.sessions.<a href="./src/stagehand/resources/sessions.py">end</a>(id, \*\*<a href="src/stagehand/types/session_end_params.py">params</a>) -> <a href="./src/stagehand/types/session_end_response.py">SessionEndResponse</a></code>
- <code title="post /v1/sessions/{id}/agentExecute">client.sessions.<a href="./src/stagehand/resources/sessions.py">execute</a>(id, \*\*<a href="src/stagehand/types/session_execute_params.py">params</a>) -> <a href="./src/stagehand/types/session_execute_response.py">SessionExecuteResponse</a></code>
- <code title="post /v1/sessions/{id}/extract">client.sessions.<a href="./src/stagehand/resources/sessions.py">extract</a>(id, \*\*<a href="src/stagehand/types/session_extract_params.py">params</a>) -> <a href="./src/stagehand/types/session_extract_response.py">SessionExtractResponse</a></code>
- <code title="post /v1/sessions/{id}/navigate">client.sessions.<a href="./src/stagehand/resources/sessions.py">navigate</a>(id, \*\*<a href="src/stagehand/types/session_navigate_params.py">params</a>) -> <a href="./src/stagehand/types/session_navigate_response.py">SessionNavigateResponse</a></code>
Expand Down
Loading
Loading