tenant_user and is gated by that user’s Account Kit (browser must be enabled). Enable or disable it per kit, and optionally require human approval for autonomous signup.
CLI First
How it works
| Capability | What it does | Cost |
|---|---|---|
session create | Open a live cloud browser scoped to allowed_domains | 0 credits (time floor at close) |
navigate | Go to a URL (allowlist + SSRF enforced) | 10 credits |
act | Natural-language action (click/fill/scroll); returns the page url after the action | 10 credits |
extract | Pull structured data (visible text) from the page (read-only) | 10 credits |
links | Read anchor hrefs + the current URL via a DOM read (read-only) | 10 credits |
observe | List candidate elements/actions (read-only) | 10 credits |
screenshot | Capture the page (short-lived signed URL) | 10 credits |
signup | Autonomous account creation + credential vaulting | 40 credits |
login | Autonomous re-authentication from the vault | 30 credits |
Reading URLs & links
extract reasons over the page’s accessibility tree — the same semantic view a screen
reader sees. That tree carries roles and visible text, but not raw DOM attributes like a
link’s href or window.location. So asking extract for “the LinkedIn URL” or “the current
page URL” returns visible text (or a fabricated-looking guess), never the real target. Two
purpose-built reads cover URLs:
links — link targets
links(session_id, { contains?, limit? }) does a direct DOM read and returns
{ url, links: [{ text, href }] }. This is the reliable way to capture real hrefs
(LinkedIn / GitHub / profile links). Filter with contains (matches href or text) and cap
with limit (default 300, max 1000).act / navigate — the current URL
act and navigate both return the page url after the step runs — the way to learn
where a click landed, including SPA route changes that put an opaque token in the path (e.g.
/applicants/<token>), which no page-content read can reconstruct.links is read-only and, on a logged-in (context-backed) saved-login session, is
capability-gated (--allow-extract) and output-redacted exactly like extract.
Autonomous signup & login
This is the core workflow: an agent that needs an account on a third-party service can create one and reuse it later, without ever handling the password itself.Signup
signup opens a scoped, write-enabled session, fills the registration form with the user’s identity (email + name) and a strong generated password, submits, and stores { email, password } in the user’s encrypted Vault under the key login:<service>. The password is never returned to the agent or sent to the model.Approval (optional)
Because signup creates a real account under the user’s identity, it is approval-gated by default. When gated, the call returns
status: "pending_approval" (HTTP 202) and runs only after a human approves it. Toggle this per Account Kit.Secrets never reach the model. The password is filled via Stagehand variable substitution (
%password% is a placeholder; the real value is substituted locally and is never logged or sent to the LLM). Signup uses the tenant user’s profile email as the account email — point it at a provisioned inbox so verification emails can be received. Set it with the profile primitive (client.forUser(id).profile.setEmail(...), or profile.set_email from the agent toolset).If you already have a working email/password for the service, store it with saveCredential (POST .../browser/credentials) instead of typing it via act; a later login then pulls it from the Vault server-side.Saved logins (Tier B)
For services where a human must log in once (SSO, 2FA, CAPTCHAs), open ahuman_login session, complete the login in the dashboard live view, then save_login to persist it as a reusable, encrypted vendor-side context. naive stores only an opaque pointer — never the cookies or credentials. Later sessions reopen already-logged-in by name (--context-name), gated by a human-created grant (default-deny; an agent can use a saved login but never create the grant or revoke it).
Live view
From the dashboard, open a user’s Browser tab to see their sessions. For an active session you can watch it stream in real time and click Take control to interact directly — this is how a human completes the one-time login for a saved-login context, or steps in to solve a CAPTCHA.Safety
- Domain allowlist (default-deny). Every session must pass
allowed_domains; pass['*']to browse unrestricted (not recommended — no DNS-rebinding protection). An SSRF denylist (private/loopback/metadata hosts, non-http(s) schemes) always applies. - Writes are gated. Destructive/submit actions are rejected unless the session was opened with
allow_writes. - No secrets in instructions. Never put passwords in an
act/extractinstruction — the autonomous signup/login flow handles credentials server-side. - Read-restricted saved logins. On a logged-in (context-backed) session,
extract/observe/screenshotare disabled unless a human opened it withallow_extract, and their output is redacted.