Quickstart

From key to first run in five minutes.

Authenticate, run a goal, then drop the engine into your agent over MCP, LangChain, AutoGen, or raw REST.

1 · Authenticate

Send a Bearer key on every request.

Create a per-tenant key in the dashboard. The raw value is shown once — store it as a server-side secret.

Authenticationhttp
Authorization: Bearer ab_live_…

# Keys are per-tenant and shown once. Create one in the dashboard
# after signing up, then keep it server-side.
2 · Run a goal

POST /api/v1/run with a url, prompt, and success condition.

The engine perceives the page as indexed state, plans, acts, and returns the path it took. `success` is a structured check — urlIncludes, statusText, textVisible, allOf, anyOf.

Run a goalbash
curl https://twin-browser.com/api/v1/run \
  -H "Authorization: Bearer ab_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://app.acme.com/invoices",
    "prompt": "export last month as CSV",
    "success": { "urlIncludes": "/exports" }
  }'

# → 200 { "success": true, "path": [ … ], "indexedState": { … } }
# Unauthorized host → 403. The target must be on your allowlist.
3 · MCP server

Expose the engine to Claude and other MCP clients.

A stdio MCP server wraps the REST API with four tools — run_goal, compile_skill, run_skill, and list_skills. Every target-bearing call still passes through the allowlist server-side.

MCP serverbash
# Start the REST engine, then the MCP server over stdio
npm run exec        # REST API (the MCP tools call this)
npm run exec:mcp    # MCP server (stdio)

# Or run it ad-hoc
npx twin-browser-mcp

# Tools exposed to the agent:
#   run_goal       url, prompt, success → indexed state + result
#   compile_skill  url, prompt, name?   → a reusable deterministic skill
#   run_skill      name, url            → zero-LLM replay
#   list_skills
4 · LangChain / AutoGen

Add the browser layer in one line.

`makeTwinBrowserTools()` returns framework-agnostic tool descriptors over the shared client — no heavy dependency, no replay logic reimplemented.

LangChain adapterts
import { DynamicStructuredTool } from "@langchain/core/tools";
import { makeTwinBrowserTools } from "twin-browser";

// One line — framework-agnostic descriptors over the same REST engine.
const tools = makeTwinBrowserTools({ baseUrl: process.env.TWIN_BROWSER_URL })
  .map((t) => new DynamicStructuredTool(t));

// The same descriptors' func (object arg → Promise<string>) work in AutoGen too.

Get a key and ship your first run.