Agent Browser Runtime act as the user · on your infra
Open source · MIT · Self-hosted v0.1.1

Your agent can finally act as the user — in their own logged-in browser, on infrastructure you control.

ABR is the missing layer between “I have Playwright” and “I run unattended, per-user, authenticated browser jobs in production.” Capture a session once, store it encrypted in your database, and let any cron, queue or serverless function drive the real web UI as that user — with verification, re-auth signalling, and rotated cookies handed back every time.

npm i @praveen-palanisamy/agent-browser-runtime   # v0.1.1

Quick tour

Captured from this very page with AutoDemo (npm run site:demos) and refreshed with each release — so the demo never drifts from the product.

Open the interactive step-by-step walkthrough →

The part of “agents that do things” nobody ships

No API, or a metered one

The portal your user needs — expenses, vendor, bank, marketplace, government — has no automation surface. The only interface is the web UI they are already signed into.

Sessions live on a laptop

Browser profiles do not travel. Cookies rotate, MFA fires, and “just run Playwright on a server” dies the first time the user closes their lid.

“Did it actually happen?”

Automation that cannot verify its own outcome retries blindly and double-acts. Failures, timeouts and successes get lumped together.

How ABR works

Three primitives — capture, post, probe — around one durable idea: the user's session is portable, encrypted by you, and refreshed on every run.

ABR request lifecycle The user signs in once inside a live view. The application stores the session encrypted. Later a job decrypts it, the runtime opens a fresh browser context, verifies authentication, performs the action via a strategy, verifies the result and returns the refreshed session. User signs inlive view · MFA · no password seen Your encrypted storestorageState · your keys Orchestratorcron · queue · serverless ABR runnerfresh context · strategy · verify Browser providerlocal · CDP · Steel · Kernel Resultok · uncertain · needsReauth · refreshedSession
The runtime is stateless between requests: sessions are never persisted by it, every job runs in a fresh browser context, and the only in-memory state is an in-flight interactive capture.

See a job run

A simulated run of the runner against an expense portal that has no API. This is the exact contract you get back from /v1/post — including what happens when the session has expired.

agent-browser-runtime post --platform expense-portal

          

What you get

Portable sessions

Playwright storageState + UA + expiry hints in one AgentSessionState. Encrypt it in your DB; ABR never stores it.

Interactive capture

Users sign in inside an embeddable, proxied live view with unguessable, expiring capture ids. MFA just works. You never see a password.

Verification contract

Strategies must verify. Results distinguish ok, uncertain, needsReauth and failureStage so you never double-act.

Rotated cookies, returned

Every job hands back refreshedSession. Long-lived sessions keep working without users re-linking.

Playwright-free client

Call the runner from Cloud Functions, Lambdas, queues or cron with a tiny typed client. No Chromium in your app.

Pluggable engines

Local Chromium, any CDP endpoint, self-hosted Steel (live view), Kernel microVMs. Swap providers; strategies stay the same.

Isolation per job

Fresh context per request, disposed afterwards. Bearer-token API. Human-pace jitter so unattended jobs do not fire at machine cadence.

Ship anywhere

npm package, multi-arch GHCR image with Chromium pinned to Playwright, and a GitHub Action. Cloud Run / ECS / compose recipes included.

Agent & LLM friendly

Stable wire protocol, typed contracts, docs/AGENTS.md and llms.txt so coding agents can integrate ABR without guessing.

Where teams use it

ABR gives you the execution primitive; you remain responsible for using it only with the user's explicit authorization and within each target site's terms of service.

Integrate in three steps

1 Describe a platform

import type { WebPostStrategy } from '@praveen-palanisamy/agent-browser-runtime';

export const expensePortal: WebPostStrategy = {
  platform: 'expense-portal',
  loginUrl: 'https://expenses.corp.example/login',
  validate: (c) => (c.text ? null : 'Description required'),
  async isAuthenticated(ctx) {
    const page = await ctx.newPage();
    await page.goto('https://expenses.corp.example/');
    return page.getByRole('button', { name: 'New claim' }).isVisible();
  },
  async post(ctx, content) {
    const page = await ctx.newPage();
    await page.goto('https://expenses.corp.example/claims/new');
    await page.getByLabel('Description').fill(content.text);
    await page.getByRole('button', { name: 'Submit claim' }).click();
    const claim = await page.getByTestId('claim-number').textContent().catch(() => null);
    return claim
      ? { ok: true, platformPostId: claim, verification: 'toast' }
      : { ok: false, uncertain: true, failureStage: 'verify' };
  },
};

2 Run the runner

# container (Chromium included)
docker run -p 8080:8080 \
  -e AGENT_RUNNER_TOKEN=$(openssl rand -base64 32) \
  -v $PWD/dist:/strategies:ro \
  ghcr.io/praveen-palanisamy/agent-browser-runtime:latest \
  serve --strategies /strategies/strategies.js

# or in-process
import { startRunner } from '@praveen-palanisamy/agent-browser-runtime/service';
startRunner({ strategies: [expensePortal] });

3 Call it from anywhere

import { AgentRunnerClient } from '@praveen-palanisamy/agent-browser-runtime/client';
const runner = new AgentRunnerClient({ baseUrl, token });

// once: user signs in inside the live view you embed
const { captureId, liveViewUrl } = await runner.captureStart({ platform: 'expense-portal' });
const done = await runner.captureFinish({ captureId });
if (done.ok) await vault.save(userId, encrypt(done.state));

// later, unattended
const res = await runner.post({
  workspaceId, accountId: userId, platform: 'expense-portal', jobId,
  session: decrypt(await vault.load(userId)),
  content: { text: 'March travel', mediaUrls: receipts },
});
if (res.refreshedSession) await vault.save(userId, encrypt(res.refreshedSession));
if (res.needsReauth) notify(userId);
if (res.uncertain) queueManualReview(jobId); // never retry blindly

Prefer CI? The GitHub Action runs probe and post jobs without deploying anything.

Why not just…

Raw PlaywrightHosted browser APIABR
Per-user authenticated sessionsDIYVendor profilesPortable, encrypted by you
Runs from serverless / queuesNo (needs Chromium)YesYes — Playwright-free client
Interactive sign-in with live viewDIYSometimesBuilt in, proxied, expiring
Verified results / no double-actDIYNoContract: ok · uncertain · needsReauth
Rotated cookies returnedDIYVendor-sideEvery job
Where data livesYoursVendorYours (Steel / Kernel / local — swappable)
LicenseApache-2.0ProprietaryMIT

FAQ

What is Agent Browser Runtime (ABR)?

An open-source (MIT), self-hostable runtime that lets AI agents and scheduled jobs act as a specific user inside that user's own authenticated browser session. It handles session capture, encrypted hand-off, isolated per-job browser contexts, verification contracts and re-authentication signalling on top of Playwright, Steel or Kernel.

How is ABR different from Playwright or Puppeteer?

Playwright drives a browser. ABR adds what production needs around it: portable per-user sessions, a stateless HTTP runner with a Playwright-free client, verified results that separate uncertain from failed, refreshed cookies returned after every job, interactive sign-in capture with a live view, and pluggable browser back-ends.

Does ABR store passwords or sessions?

No. Users sign in themselves inside a live view; ABR only exports the resulting browser storage state. The runtime never persists sessions — your application encrypts and stores them and passes them in per job. Treat them with password-equivalent sensitivity.

Which browser back-ends are supported?

Local Chromium via Playwright, any Chrome DevTools Protocol endpoint, self-hosted or cloud Steel Browser (with live view), and Kernel microVMs. Providers are swappable without changing your strategies.

How do I install it?

npm i @praveen-palanisamy/agent-browser-runtime for the library and client; docker pull ghcr.io/praveen-palanisamy/agent-browser-runtime for the runner with Chromium; or uses: praveen-palanisamy/agent-browser-runtime@v0 in GitHub Actions.

Is it allowed to automate a site this way?

That depends on the site's terms and on having the user's explicit authorization. ABR is a general execution primitive — the same one a user's own browser extension or RPA bot would use — and it exposes official-API fallbacks in its contracts so you can prefer them where they exist.

Who maintains ABR?

Praveen Palanisamy. Source, issues and releases live at github.com/praveen-palanisamy/agent-browser-runtime.

Give your agent hands.