A REST API server that wraps Stagehand for AI-driven browser automation, with built-in Tavily web search and FireCrawl web scraping.
One server. Three capabilities:
- Browser automation — Navigate, click, extract, and run full agent workflows via Stagehand
- Web search — Find URLs and answers before navigating (Tavily)
- Web scraping — Extract structured data without spinning up a browser (FireCrawl)
# Install globally
npm install -g stagehand-plus
# Generate global config file
stagehand-plus --init
# → creates ~/.stagehand-plus/settings.json
# Edit your API keys
vim ~/.stagehand-plus/settings.json
# Start the server
stagehand-plus
# → listening on http://localhost:9090Or use npx without installing:
npx stagehand-plusstagehand-plus # Start the server
stagehand-plus --stop # Stop the running server
stagehand-plus --init # Generate ~/.stagehand-plus/settings.json
stagehand-plus --version # Show current version + check for updates
stagehand-plus --update # Self-update to latest versionRun stagehand-plus --init to create ~/.stagehand-plus/settings.json:
{
"port": 9090,
"modelName": "gpt-4o",
"modelApiKey": "sk-...",
"tavilyApiKey": "tvly-...",
"firecrawlApiKey": "fc-..."
}Set once, works everywhere. No need to create .env in every directory.
If you need different keys for a specific project, create a .env in that directory:
MODEL_API_KEY=sk-different-key- Per-request headers —
x-model-api-key,x-tavily-api-key,x-firecrawl-api-key .envfile — in the current working directory~/.stagehand-plus/settings.json— global config- Environment variables —
export MODEL_API_KEY=sk-...
GET /health
{ "status": "ok", "activeSessions": 0, "uptime": 123.45 }All browser endpoints require a session. Start one first, then use the session ID.
POST /v1/sessions/start
Header: x-model-api-key (optional, overrides env)
{
"modelName": "gpt-4o",
"systemPrompt": "You are a helpful browser assistant",
"domSettleTimeoutMs": 3000,
"selfHeal": true
}Response:
{
"success": true,
"data": { "available": true, "sessionId": "uuid-here" }
}POST /v1/sessions/:sessionId/navigate
{
"url": "https://example.com",
"options": { "waitUntil": "load", "timeout": 30000 }
}Perform an action described in natural language.
POST /v1/sessions/:sessionId/act
{
"input": "Click the Sign In button",
"options": { "timeout": 10000 }
}Find interactive elements on the page.
POST /v1/sessions/:sessionId/observe
{
"instruction": "Find all navigation links"
}Extract data from the current page.
POST /v1/sessions/:sessionId/extract
{
"instruction": "Extract all product names and prices",
"schema": {
"type": "object",
"properties": {
"products": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"price": { "type": "string" }
}
}
}
}
}
}Run a multi-step agent that autonomously completes a task.
POST /v1/sessions/:sessionId/agentExecute
{
"executeOptions": {
"instruction": "Go to Hacker News and find the top 3 stories",
"maxSteps": 10
},
"agentConfig": {
"model": "gpt-4o"
}
}POST /v1/sessions/:sessionId/end
POST /v1/search
Header: x-tavily-api-key (optional, overrides env)
{
"query": "best practices for browser automation",
"maxResults": 5,
"searchDepth": "basic",
"topic": "general",
"includeAnswer": true,
"timeRange": "month"
}| Parameter | Type | Default | Description |
|---|---|---|---|
query |
string | required | Search query |
maxResults |
number | 5 |
Number of results (1-20) |
searchDepth |
"basic" | "advanced" |
"basic" |
Search depth |
topic |
"general" | "news" | "finance" |
"general" |
Search category |
includeAnswer |
boolean | false |
Include AI-generated answer |
includeRawContent |
boolean | false |
Include full page content |
includeDomains |
string[] | [] |
Restrict to these domains |
excludeDomains |
string[] | [] |
Exclude these domains |
timeRange |
"day" | "week" | "month" | "year" |
— | Time filter |
POST /v1/scrape
Header: x-firecrawl-api-key (optional, overrides env)
{
"url": "https://example.com/article",
"formats": ["markdown"],
"onlyMainContent": true,
"waitFor": 5000
}| Parameter | Type | Default | Description |
|---|---|---|---|
url |
string | required | URL to scrape |
formats |
string[] | ["markdown"] |
"markdown", "html", "rawHtml", "links", "json" |
onlyMainContent |
boolean | true |
Strip navs, footers, ads |
includeTags |
string[] | — | CSS selectors to include |
excludeTags |
string[] | — | CSS selectors to exclude |
waitFor |
number | 0 |
Ms to wait for JS rendering |
timeout |
number | 30000 |
Request timeout in ms |
mobile |
boolean | false |
Emulate mobile device |
jsonOptions |
object | — | { prompt, schema } for structured extraction |
git clone https://github.com/ryan941/stagehand-plus.git
cd stagehand-plus
npm install
cp .env.example .env
# Fill in your API keys in .env
npm run dev # Development with hot reload
npm run build # Compile TypeScript
npm start # Run compiled versionsrc/
index.ts Express server + graceful shutdown
session-manager.ts Stagehand session lifecycle (create/get/end)
routes/
health.ts GET /health
sessions.ts POST /v1/sessions/* (browser automation)
search.ts POST /v1/search (Tavily web search)
scrape.ts POST /v1/scrape (FireCrawl web scraping)