Docs
Steerpane documentation
Steerpane gives AI agents real Chromium browsers with saved logins, a live view, and a takeover button for humans. This page walks you from zero to a session you can take over, then covers the core concepts and APIs.
API reference
Every endpoint with live examples. Requires sign-in.
Open referenceSKILL.md for agents
A compact guide your agent can read to use Steerpane well.
View SKILL.mdQuickstart
You'll need a Steerpane account and an API token. Create the token under Tokens in the dashboard — it starts with stp_live_ and inherits your role in the project.
1. Connect via MCP
Steerpane's MCP server lives at https://api.steerpane.app/mcp and speaks Streamable HTTP. Pick your client:
claude mcp add --transport http steerpane https://api.steerpane.app/mcp \ --header "Authorization: Bearer stp_live_YOUR_TOKEN"
2. Create a session
Ask your agent to "open a Steerpane session on linkedin.com", or call the API directly. Pass a profile_id to start already signed in.
curl https://api.steerpane.app/v1/sessions \
-H "Authorization: Bearer stp_live_YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"profile_id":"prf_linkedin","initial_url":"https://linkedin.com"}'The response includes the session id, a cdp_url for Playwright or Puppeteer, and a live_url you can open to watch.
3. Take over
When your agent hits a CAPTCHA or 2FA prompt it calls request_human_help. You'll see a "Needs help" badge and a notification. Click Take over in the live view — or call the endpoint below. The agent is put on hold: any commands it sends are queued, not dropped, and it receives a 409 human_in_control status if it asks.
# Take control (agent goes on hold; its commands queue) curl -X POST https://api.steerpane.app/v1/sessions/ses_8f2k1q/takeover \ -H "Authorization: Bearer stp_live_YOUR_TOKEN" # Hand back (queued commands replay in order) curl -X POST https://api.steerpane.app/v1/sessions/ses_8f2k1q/handback \ -H "Authorization: Bearer stp_live_YOUR_TOKEN"
4. Hand back
Finish the step and click Hand back. Queued commands replay in order and the agent continues from the page you left it on. Always end with stop_session so the recording is finalised and minutes stop counting.
Sessions
A session is one running Chromium instance. It moves through starting → running → stopped, and can be awaiting_help or under human_control along the way. Every session is recorded: events, console, network and a replay you can scrub.
Profiles
A profile is a saved browser state — cookies, local storage, extensions and fingerprint settings. Start a session from a profile to reuse logins; changes are written back when the session ends, unless you start it read-only.
Takeover
Takeover moves control from the agent to a person. Exactly one party controls a session at a time. While a human is in control the agent is on hold, its commands queue, and webhooks fire control.takeover and control.handback. Teams can require approval before an agent submits payments or forms on specific domains.
API tokens
Tokens authenticate MCP, REST and CDP. They inherit the permissions of the user who created them, are scoped to a project, and can be given an expiry. Send them as Authorization: Bearer <token>. Revoke a token and every connection using it closes immediately.
MCP
Tools are ordered cheapest first. Agents should try fetch_page or web_search before starting a browser.
| Tool | What it does |
|---|---|
| fetch_page | Fetch a URL as Markdown/HTML without starting a browser (cheapest — try first) |
| web_search | Search the web and return title/url/snippet results |
| screenshot_url / pdf_url | Screenshot or print a URL in one call (no session) — saved to the file store with a file_id + download url |
| map_site | List a site's URLs (sitemaps + start-page links), filtered by keyword — find the right page before fetching |
| crawl_site → get_crawl | Crawl a site in the background (same site, robots.txt respected) and page through the results |
| extract_url | Structured JSON from up to 10 URLs with an instruction (+ optional JSON schema), no session needed |
| create_session | Start a remote Chromium session, optionally from a saved profile |
| list_profiles / verify_profile_logins | Find a profile and check it is still signed in to a site (loads the site with the profile's cookies) before relying on it |
| navigate / click / type / scroll | Granular browser actions on the live page — selectors are also found inside iframes (or pass frame); use id=<exact id> for ids with dots |
| form_fields → type / select_option / upload_file | Fill a form: form_fields lists every field (incl. iframes) with label, required, options and a ready selector; select_option handles native and custom dropdowns |
| url_history | Every URL the session's tabs and iframes visited — find a one-time login link again instead of navigating away |
| get_page_text / extract / screenshot | Read the page as text, structured data or an image |
| browser_execute | Run a JS snippet in the live page and return its `result` (console logs only with include_logs: true) |
| create_upload_url → upload_file(file_id) | Attach a local file (e.g. a resume): create_upload_url, run the returned curl in your own shell, then upload_file with file_id — the bytes never pass through the model |
| download / list_files | Saved downloads get a file_id you can pass straight to upload_file |
| captcha_snapshot → captcha_click | Solve a CAPTCHA yourself: a numbered image of the challenge, then click the matching tile numbers and verify |
| solve_captcha | On a CAPTCHA: Steerpane's CAPTCHA worker solves it with its own vision model; if it can't, a human takes over. Calls wait ~45 s each — repeat per next_step until solved / solved_by_human |
| request_human_help | Pause and ask the human to take over (CAPTCHA you couldn't solve, 2FA, payment confirmation) |
| run_task | Hand a whole goal to Steerpane's hosted browser agent and get a structured result |
| stop_session | End the session (reason required). Sticky sessions: only when the user says they are done or asks you to close it. auto_close sessions: reason task_done once the task is done |
REST API
Base URL https://api.steerpane.app/v1. Click an endpoint for the equivalent curl; the full reference with request and response schemas is in the dashboard.
Webhooks
Subscribe an endpoint to events like session.started, control.help_requested, control.takeover and session.ended. Each delivery is signed with HMAC-SHA256 in the Conduit-Signature header; reject anything older than five minutes.
import crypto from "node:crypto";
export function verify(rawBody, header, secret = "whsec_YOUR_SECRET") {
const parts = header.split(",").map((p) => p.split("="));
const t = parts.find(([k]) => k === "t")?.[1];
const sigs = parts.filter(([k]) => k === "v1").map(([, v]) => v);
if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // 5 min tolerance
const expected = Buffer.from(crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex"));
// During a secret rotation the header carries one v1= per secret — accept any match.
return sigs.some((v1) => v1.length === expected.length && crypto.timingSafeEqual(expected, Buffer.from(v1)));
}Self-hosting
Steerpane ships as Docker images: the API, the session scheduler, and Chromium nodes built on kernel-images (Apache-2.0). Run them with docker compose on one machine, or deploy the same compose file on Dokploy and scale nodes independently.
# docker-compose.yml (excerpt)
services:
conduit-api:
image: ghcr.io/conduit/api:0.14
env_file: .env
ports: ["8080:8080"]
conduit-scheduler:
image: ghcr.io/conduit/scheduler:0.14
env_file: .env
chromium-node:
image: ghcr.io/conduit/chromium-node:0.14 # built on kernel-images (Apache-2.0)
deploy: { replicas: 4 }
shm_size: 2gb- Copy
.env.exampleto.envand set your database URL, object storage for recordings, and a signing secret. - Run
docker compose up -dand open port 8080 to create the first admin. - Add more Chromium nodes from Admin → Nodes; the scheduler balances sessions across them.
steerpane-api, and enable WebSocket support for live view.