# runnerID runnerID by Torchrunner is cross-platform agent identity: one identity that follows the operator across tools. A browser agent has two halves. The hands click and type. The identity gets it past the login wall and lets it act. runnerID is the identity half, for any browser agent. It logs the agent in, catches the code, keeps the session, and asks the owner before anything risky. The agent never sees a password. This service is the v1 login kit: a vault, authenticator codes, an inbox, saved sessions, owner approvals, and an append-only event log. The API is https://api.runnerid.torchrunner.ai and also https://runnerid.onrender.com. ## What it does - Stores a username and password and types them into the matching page over CDP. The fill response names the fields. It does not include the password. - Stores a TOTP seed and types the current 6 digit code into the page. The code is not in that response. - Gives each identity an inbox address. It can wait for an email code or a magic link, type the code, or open the link when the link host matches the site. - Saves and restores cookies and localStorage for one site, over the same CDP address as fill: http, https, ws or wss, including Browserbase and Steel connect URLs. A saved session stays until it is saved over, deleted, or the identity is revoked. - Stores a per-identity policy: allowed sites, trusted subdomains, and actions that need the owner to approve. Approval is an email link. - Records an append-only event log. Revoke marks the identity unusable, deletes saved sessions, expires pending approvals, and invalidates outstanding secret tokens. ## What works with which agents - A browser runnerID can reach, such as a hosted browser (Browserbase, Steel) or one on your own server: runnerID connects to it and types the password itself. This is the strongest mode. Pass the browser's CDP address to fill_login or a helper. - A browser on your own laptop: the helper's local route types the password. It passes through your own code once and never reaches the model. - Hosted agents whose browser runnerID cannot reach: they get authenticator and emailed codes returned over MCP, and approvals and the log work the same. Typing a password into the page needs the runnerID helper next to the browser (Stagehand, Playwright or Browser Use), on a laptop or in a cloud container. runnerID does not claim support for, or an integration with, any named agent product. ## What it does not do It does not provide burner identities, SMS verification for strangers, captcha solving, or business stand-up steps such as fax, postal mail, or EIN. It does not issue phone numbers or payment cards, hold passkeys, sign bot traffic, or assign a fixed IP. It does not let one agent use logins across several customers' accounts. Phase 2 items in the product brief are not in this service. Server fill keeps the secret in runnerID. SDK fill (POST /v1/identities/{id}/secret-token, then POST /v1/redeem) returns the secret once to a caller that cannot pass a CDP address. That path is weaker because the secret enters the caller process. Prefer server fill. Hosted MCP tool results never include a password or seed. Only get_email_code and get_authenticator_code return a code, and each release is logged. ## Your data Your data is yours. We never use your content to train AI models: not your records, documents, emails, passwords, codes, or anything on the pages your agents visit. We do learn from how tasks get done, such as which steps a sign-in needs or where a site asks for a code, with your content and personal details removed, so agents get better at the work. You can turn this off any time in your settings, and we never sell it or share it for anyone else to train on. Your history is yours too. Download every event as CSV or JSON from the console (History and feed), or read it in pages from GET https://api.runnerid.torchrunner.ai/v1/events?cursor=&since=&limit= (oldest first, up to 500 a page; pass next_cursor back as cursor). Set a feed address in the console and each event is POSTed there as it happens as {"type":"event","event":{...}}, with a runnerid-signature header t=,v1= keyed by the whsec_ secret shown once. A send that fails is retried three times; anything missed can be read back from /v1/events. The same address also gets action notices as their own top-level types (approval.requested, run.done, run.failed, run.waiting) with the fields needed to act on them. Branch on the top-level type: "event" is the complete history record, the others are prompts to act, so the same moment can arrive once as each. ## Auth Authenticated routes expect an Authorization header: Bearer, then the API key. The key is shown once when the account is created and is stored only as a sha256 hash. A missing or revoked key returns 401 with error code unauthorized. Each API key can make 60 requests per minute to /v1 and /mcp on this process. The next request returns 429, error code rate_limited, and a Retry-After header. JSON bodies are limited to 64 KB. The Resend webhook body is limited to 256 KB. A larger body returns 413, error code payload_too_large. A revoked identity returns 403 identity_revoked on vault and inbox routes, and 409 identity_revoked on session, policy, and approval creation. A site outside the identity allow list returns 403 site_not_allowed. If the owner turned off agent saves for an identity, save_login and save_authenticator return 403 agent_save_disabled; use request_login instead. Creating an identity past the plan's limit (Solo 1, Builder 5, Team 25, no plan 1) returns 403 plan_limit. After a cancelled plan's paid month ends, every change returns 403 plan_inactive; reading, exporting and revoking still work, and data is kept for 30 days. If the page moves before a secret is typed, the call returns 409 page_navigated and types nothing. A magic link whose host is not the requested site, or a trusted subdomain of that site, returns 422 link_host_mismatch and the browser is not navigated. These routes do not use an API key: GET /, GET /health, GET /ready, GET /openapi.json, GET /llms.txt, and GET and POST /approve/{token}. The approval token in the path is the credential for that page. POST /v1/webhooks/resend uses Svix signature headers, not an API key. ## Plans and API keys Buy a plan to get an account. Monthly through Stripe, cancel any time, same features on every plan. An identity is one set of logins, codes, inbox, sessions and rules that your agents use. - Solo: $12 a month, 1 identity. - Builder: $29 a month, 5 identities. - Team: $99 a month, 25 identities. Plans and checkout: https://runnerid.torchrunner.ai/#pricing. After payment the buyer gets an emailed sign-up link that shows the API key once. An agent should not buy a plan on its own; ask the person first. ## Owner console https://api.runnerid.torchrunner.ai/console The owner signs in with an emailed link. From there the owner creates and revokes identities, adds logins and authenticator keys (never shown back), sets site rules, approves or denies requests, rotates or revokes API keys, and reads the activity log. ## MCP Hosted MCP endpoint: POST https://api.runnerid.torchrunner.ai/mcp The transport is stateless Streamable HTTP. Send the same Bearer API key, or sign in: Claude, ChatGPT and other MCP clients that support OAuth get a 401 pointing at /.well-known/oauth-protected-resource/mcp and sign the owner in through the console (OAuth 2.1, PKCE, dynamic client registration). A directory can list the tools without a key at /mcp/discover; every tool call needs a key or a sign-in. GET and DELETE /mcp return 405. Tools call the REST handlers in this process. Omit identity_id when the account has exactly one identity. - get_identity: Read one identity, including its inbox address. The result has no secrets. - save_login: Store a site login. The secret is encrypted and is not returned. - request_login: Ask the owner for a login runnerID does not have. The owner gets a secure one-time link and types it there; the password never passes through the agent. Returns request_id. - wait_for_login: Wait until the owner has typed the requested login (default 120 seconds, at most 300). Then call fill_login. - fill_login: Type the saved username and password into the matching page over CDP. The password is not returned. - fill_code: Type the current authenticator code into the matching page over CDP. The code is not returned. - wait_for_email_code: Wait until an email code arrives. The code is consumed and is not returned. - fill_email_code: Wait for an email code and type it into the matching page over CDP. The code is not returned. - get_email_code: Wait for an email code and return it, for agents whose browser runnerID cannot reach (hosted agents). The code is consumed and the release is logged as code.released. - save_authenticator: Store an authenticator (TOTP) seed for a site. The seed is encrypted and is not returned. - get_authenticator_code: Return the current six-digit authenticator code for a site, for hosted agents. The seed is never returned. The release is logged as code.released. - open_magic_link: Wait for a magic link whose host is the site, or a trusted subdomain, and open it. The link is not returned. - save_session: Save cookies and localStorage for one site from the browser. Cookie values are not returned. - restore_session: Restore a saved session into the browser. Cookie values are not returned. - request_approval: Ask the account owner to approve an action. Returns approval_id and status. The email token is not returned. - wait_for_approval: Wait until an approval is no longer pending, or the timeout elapses. - handoff_task: Hand runnerID a step you cannot finish. runnerID does it as this identity in its own browser, asks the owner before anything risky, and returns the result. Returns run_id at once. - get_run: Read a handoff: status, the result when done, or why it failed or what it is waiting for. Can wait up to 120 seconds for a change. - cancel_run: Cancel a handoff that has not finished. - list_events: List recent events for an identity, newest first. Event data does not include secrets. Example client config, for Claude, Cursor and any MCP client: {"mcpServers": {"runnerid": {"type": "http", "url": "https://api.runnerid.torchrunner.ai/mcp", "headers": {"Authorization": "Bearer rid_YOUR_KEY"}}}} ## Helpers and the local server - Stagehand: npm install @runnerid/stagehand - Playwright: npm install @runnerid/playwright - Browser Use (Python): pip install runnerid - Local MCP server, for an agent whose browser runnerID cannot reach (for example a hosted agent's own cloud machine): npx -y @runnerid/mcp-local. It needs RUNNERID_API_KEY and a Chrome started with a debugging port, and types the password, authenticator code or emailed code into the open tab without returning it. Machines that cannot reach npm can download it with the API key from https://api.runnerid.torchrunner.ai/v1/downloads/runnerid-mcp-local.tgz. Set RUNNERID_BASE_URL to https://api.runnerid.torchrunner.ai for the helpers. ## Documents OpenAPI 3.1 document: /openapi.json (https://api.runnerid.torchrunner.ai/openapi.json). It lists every route, auth, request body, and response. Quickstart (docs/quickstart.md): Plans start at $12 a month: https://runnerid.torchrunner.ai/#pricing. After payment the buyer gets an emailed sign-up link that shows the API key once. Save a password with POST /v1/identities/{id}/logins and a TOTP seed with POST /v1/identities/{id}/totp. For an email code, give the site the identity inbox address from GET /v1/identities/{id}. Connect Claude or Cursor to POST /mcp with the Bearer key. Ask the agent to call fill_login with the site and the browser CDP URL, then fill_code or fill_email_code. The password and the code are typed into the page and are not in the tool result. A hosted agent whose browser runnerID cannot reach calls get_authenticator_code or get_email_code and types the code itself; passwords are never returned to an agent. The Stagehand helper reads the CDP URL after init and posts it to the fill routes. Security (docs/security.md): A password or TOTP seed is encrypted with AES-256-GCM under a per-identity data key. The data key is wrapped by the master key. AES-GCM additional data is the identity id, the table name, and the site, so ciphertext copied to another identity or site does not decrypt. Server fill types the secret into the matching page and the HTTP response does not include it. SDK fill returns it once through /redeem. Logs and the event table record names and ids, not passwords, seeds, API keys, tokens, or email bodies. A code in an email subject is replaced with [code] before the inbox row is stored. API keys, secret tokens, and sign-up links are stored as sha256 hashes. Revoke does not print the secrets it drops. Approval details may be at most 4 KB and must not contain keys that look like a password, secret, token, otp, code, cookie, session, or key. CDP URLs must be http, https, ws, or wss. Loopback, private, link-local, and metadata addresses are rejected unless RUNNERID_ALLOW_PRIVATE_CDP=1, which is for local development only. A secret saved for a site is typed only into that host (a leading www. is ignored) or a trusted subdomain. The page URL is read again immediately before typing. Inbox waits stop at 120 seconds. Approval waits stop at 300 seconds. Both stop when the client disconnects. Inbound mail is deduplicated by the provider email id. ## Pages - runnerID for people, with plans: https://runnerid.torchrunner.ai - How it compares: https://runnerid.torchrunner.ai/compare - The new agents and their logins: https://runnerid.torchrunner.ai/agents - Agent identity kits compared: https://runnerid.torchrunner.ai/compare/agent-identity-kits ## Guides - All guides: https://runnerid.torchrunner.ai/guides - Log a cloud browser agent into sites: https://runnerid.torchrunner.ai/guides/cloud-browser-agent-logins - Authenticator (2FA) codes for AI agents: https://runnerid.torchrunner.ai/guides/authenticator-codes-ai-agents - Keep an AI agent signed in between runs: https://runnerid.torchrunner.ai/guides/keep-ai-agent-signed-in - Give an AI agent its own inbox for codes and sign-in links: https://runnerid.torchrunner.ai/guides/ai-agent-inbox-verification-codes - Human approval before AI agent actions: https://runnerid.torchrunner.ai/guides/human-approval-ai-agent-actions - Stop pasting passwords into AI agent prompts: https://runnerid.torchrunner.ai/guides/stop-pasting-passwords-into-prompts - Add runnerID to Claude and Cursor as an MCP connector: https://runnerid.torchrunner.ai/guides/mcp-connector-claude-cursor - Owner console: https://api.runnerid.torchrunner.ai/console Product names are trademarks of their owners. runnerID and Torchrunner are not affiliated with or endorsed by Anthropic, xAI, Cursor, OpenAI, Meta, Google or Perplexity.