WebPilot.siby Clane AI

Browser for AI agents

A real browser your AI agent drives.

WebPilot.si gives every user their own persistent browser. Agents drive it over MCP, programs over REST. Logins come from a vault the agent never sees, and when a step needs a person, the agent hands it over and waits.

Running it yourself? Install guide

MCP session (abridged)
> browser_open {"url": "en.wikipedia.org/wiki/Web_browser"}
opened t1 (read)
title: Web browser - Wikipedia
- link "History" [ref=e14]
- searchbox "Search Wikipedia" [ref=e3]

> browser_login {"site": "shop.example"}
logged_in · password and code from the vault

> browser_handoff {"reason": "captcha"}
Your turn: https://api.webpilot.si/handoff/…
· waiting for the person to press Done
What an agent sees: element refs to act on, vault logins by name, and a hand-off link when it needs a person.

What you get

Everything an agent needs to use the web like a person

01A real browser that stays

Each person gets their own headed Chromium with a persistent profile. Logins, cookies and history survive between runs and restarts (tabs live while the browser runs), and are never shared with another user.

02Logins the agent never sees

Passwords, card details and authenticator keys live in an encrypted vault. The agent asks for browser_login or fill_secret by name; the values are typed into the page and never returned or logged.

03Hand-offs to a person

When a step needs a human (a CAPTCHA, a code from a phone, an approval) the agent sends a "Your turn" link: the message, the browser live, and a Done button it waits for.

04Live viewer

Watch the browser as the agent works, from any device. Links are short-lived and show one user's browser only; taking over is allowed per user and enforced by the server.

05Run reports and replay

Record a tab and get one self-contained HTML report (every step, its screenshot, network and console errors) plus JUnit XML. Replay the flow later from stored locators, without an LLM.

06Guarded writes

Tabs open read-only unless asked for act. Per-site rules make a bank read-only while a shop stays writable. Every action is in the audit log, and page text is fenced as untrusted data.

How it works

From token to finished run

  1. Get a tokenAn admin creates your user; the token is shown once. Logins go in the vault (admin console or cbu vault set).
  2. ConnectPoint your agent at /mcp, or your code at /v1 or the Python or TypeScript SDK. Your browser starts on first use.
  3. Look, act, checkSnapshot the page, act by element ref, confirm with text or a screenshot. Read tabs cannot change anything.
  4. People step in, runs leave evidenceHand-offs bring a person in for one step. Recordings give a report, JUnit XML and a replayable script.

Three ways in

MCP for agents, REST and SDKs for programs

One service behind all three: the same tabs, vault, policy and limits, whichever door you use.

MCP, for agents

Claude Code, Cursor, Codex, Claude Desktop or any MCP client gets the browser_* tools over Streamable HTTP, with your token.

Connect any client · configs

Claude Code
claude mcp add --transport http webpilot \
  https://api.webpilot.si/mcp \
  --header "Authorization: Bearer $WEBPILOT_TOKEN"

# Cursor, Codex, Claude Desktop: see /examples

REST API v1

Resources with stable ids, typed errors, idempotent retries and an OpenAPI 3.1 contract. Any language with HTTP.

Full curl walk-through

curl
TAB=$(curl -s -X POST https://api.webpilot.si/v1/tabs \
  -H "Authorization: Bearer $WEBPILOT_TOKEN" \
  -H "content-type: application/json" \
  -d '{"url": "example.com"}' | jq -r .id)

curl -s https://api.webpilot.si/v1/tabs/$TAB/text \
  -H "Authorization: Bearer $WEBPILOT_TOKEN"

Python and TypeScript SDKs

Typed clients and errors, retries with backoff and logs. pip install webpilot-si · npm install webpilot-si (Node, Deno, Bun, edge).

All SDK examples

python · typescript
from webpilot import WebPilot

# the token comes from WEBPILOT_TOKEN
with WebPilot("https://api.webpilot.si") as wp:
    tab = wp.open("en.wikipedia.org/wiki/Web_browser")
    print(tab.snapshot().title)
    print(tab.read_text()[:300])
    tab.close()

// TypeScript: the same calls, awaited
const tab = await new WebPilot({ baseUrl: "https://api.webpilot.si" }).open("example.com");
console.log((await tab.snapshot()).title);