← Blog

BLOG

Agent-Browser Agent-Browser: CLI, Runtime, and Production Path

Agent-browser agent-browser explained: what the CLI does, where it breaks down, and how to run the same automation on hosted Chromium.

September 10, 20269 min readRemote Browser

# Agent-Browser Agent-Browser: CLI, Runtime, and Production Path

If you searched "agent-browser agent-browser," you probably hit two things at once: a CLI package called agent-browser and a broader category of agent-browser tooling that all claims to do the same job. They don't. The CLI is a local command surface for driving a browser from an AI agent loop. The category is a runtime question — where the browser actually lives, who keeps it alive, and what happens when your agent runs for six hours instead of six seconds. This post separates the two, shows where the CLI is genuinely useful, and explains the point at which you move the browser off your laptop and onto hosted Chromium.

What "agent-browser" actually refers to

There are three distinct things sharing the name, and conflating them causes most of the confusion:

  • The `agent-browser` CLI — a browser automation command-line tool built for AI agents. It exposes navigation, clicking, typing, and page inspection as shell commands an agent can call, typically wrapping Playwright or CDP under the hood.
  • The agent-browser pattern — any architecture where an LLM decides the next browser action, executes it, reads the result, and loops. The CLI is one implementation of this pattern; browser-use, custom Playwright scripts, and hosted runtimes are others.
  • The agent-browser runtime — the infrastructure that hosts the actual Chromium process, manages sessions, and exposes a connection endpoint. This is the layer that determines whether your agent works in production.

The first two are developer ergonomics. The third is the part that fails at scale.

Why the CLI is a good starting point

A CLI is a reasonable first interface for agent-driven browsing because it maps cleanly onto how LLMs already work. Models emit structured text; a CLI accepts structured text; the output is text the model can read back. No SDK ceremony, no object lifecycle to manage.

Typical advantages:

  • Low integration cost. An agent framework that can run shell commands can drive a browser without a browser-specific library.
  • Debuggable by hand. You can run the same command the agent ran and see what it saw.
  • Composable. Pipe output, chain commands, wrap in your own retry logic.

That's real value for prototyping. The problem is that a CLI is a *client*. It assumes a browser exists somewhere reachable, and it assumes that browser is stable for the duration of the task.

Where local agent-browser setups break

Once you move past single-page demos, the failure modes are consistent and well-documented across teams running browser agents:

Failure modeWhat happens locallyProduction impact
Session deathLaptop sleeps, process is killed, Chrome crashesAgent loses mid-task state, no resume
Auth lossCookies live in a temp profile that gets wipedAgent re-authenticates every run, or gets locked out
ConcurrencyOne Chrome per machine, RAM-boundCan't run parallel tasks without more hardware
IP reputationResidential or datacenter IP tied to your officeBlocks, CAPTCHAs, silent degradation
ObservabilityYou watch a window, or you don'tNo replay, no artifact, no post-mortem
Environment driftChrome version, fonts, locale differ per machineWorks on your machine, fails in CI

None of these are CLI bugs. They're consequences of the browser living on the same machine as the agent. The fix isn't a better CLI — it's moving the browser to a runtime designed to host it.

The runtime layer: what hosted Chromium changes

A hosted browser runtime keeps Chromium running in a managed environment and hands your agent a connection endpoint instead of a local process. Remote Browser does this by exposing CDP endpoints over WebSocket, so anything that speaks the Chrome DevTools Protocol can attach — Playwright, Puppeteer, Selenium, or a raw CDP client.

The practical differences:

  • Sessions outlive your process. The browser keeps running when your script exits, your laptop closes, or your CI job finishes.
  • Persistent profiles. Cookies, localStorage, and auth state survive across runs, so agents don't re-login every time. See the runtime documentation for how profiles are scoped.
  • Isolation. Each session gets its own browser context. One agent's cookies don't leak into another's.
  • Configurable browser settings. Locale, timezone, user agent, viewport, and proxy settings are set per session rather than inherited from whatever machine you're on.
  • Live viewer. You can watch a session in real time and inspect what the agent is doing without SSHing into anything.
  • Usage controls. Sessions are metered, so you can reason about cost per task instead of guessing at VM spend. Current rates are on the pricing page.

The trade-off is that you're now depending on a network connection to your browser. For most agent workloads that's fine — the agent is already making network calls to an LLM. For latency-sensitive micro-interactions, local still wins.

Connecting Playwright to a remote browser

The migration path from a local agent-browser CLI to a hosted runtime is usually small. If your CLI wraps Playwright, you replace the local launch with a CDP connection.

import { chromium, Browser, BrowserContext, Page } from 'playwright';

interface RemoteSession {
  cdpUrl: string;
  sessionId: string;
}

// Fetch a session from the Remote Browser API.
// Endpoint shape and auth are documented at /documentation.
async function createSession(): Promise<RemoteSession> {
  const res = await fetch('https://api.remote-browser.dev/v1/sessions', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${process.env.REMOTE_BROWSER_API_KEY}`,
    },
    body: JSON.stringify({
      // Configurable browser settings, applied per session.
      locale: 'en-US',
      timezone: 'America/New_York',
      viewport: { width: 1280, height: 800 },
      // Reuse a stored profile so auth state persists across runs.
      profileId: 'agent-checkout-profile',
    }),
  });

  if (!res.ok) {
    throw new Error(`Session create failed: ${res.status} ${await res.text()}`);
  }

  const data = await res.json();
  return { cdpUrl: data.cdpUrl, sessionId: data.id };
}

async function runTask(): Promise<void> {
  const session = await createSession();

  // connectOverCDP attaches to an existing Chromium instance.
  // It does not launch a local browser.
  const browser: Browser = await chromium.connectOverCDP(session.cdpUrl);

  // A remote session may already have a context; reuse it if present.
  const context: BrowserContext =
    browser.contexts()[0] ?? (await browser.newContext());

  const page: Page = await context.newPage();

  try {
    await page.goto('https://example.com/login', {
      waitUntil: 'domcontentloaded',
    });
    await page.fill('#email', process.env.AGENT_EMAIL!);
    await page.fill('#password', process.env.AGENT_PASSWORD!);
    await page.click('button[type="submit"]');
    await page.waitForURL('**/dashboard');

    // Hand control back to the agent loop here: extract state,
    // decide the next action, repeat.
    const title = await page.title();
    console.log(`Landed on: ${title}`);
  } finally {
    // Close the page, not the browser. The session stays alive
    // on the runtime until you explicitly terminate it.
    await page.close();
    await browser.close();
  }
}

runTask().catch((err) => {
  console.error(err);
  process.exit(1);
});

Two details matter here. First, connectOverCDP is Chromium-only — it will not attach to Firefox or WebKit. If your agent needs cross-browser coverage, you need a different connection strategy. Second, browser.close() on a CDP connection detaches your client; it does not necessarily kill the remote browser. Session lifecycle is controlled by the runtime, which is the point.

For the protocol-level details, the Chrome DevTools Protocol documentation is the authoritative reference, and Playwright's own CDP guidance covers the client-side behavior.

Agent-browser CLI vs. hosted runtime: a decision table

CriterionLocal agent-browser CLIHosted Chromium runtime
Setup timeMinutesMinutes, plus API key
Session persistenceNone by defaultPersistent profiles
Parallel tasksRAM-bound on one machineSession-scoped, metered
Auth stateTemp profile, often lostStored and reusable
DebuggingWatch the windowLive viewer + session replay
IP / networkYour machine's IPConfigurable per session
Cost modelYour hardwarePer browser-hour, see /pricing
Best forPrototypes, one-off scriptsAgents that run on a schedule

The honest read: if you're running a single agent task a few times a day on your own machine, the CLI is fine. The moment you need it to run unattended, in parallel, or with login state that survives a restart, the runtime layer stops being optional.

Production criteria before you commit

Before picking either path, check these against your actual workload:

  1. Does the task need authentication? If yes, persistent profiles are close to mandatory. Re-logging in on every run is both slow and a good way to trip account security.
  2. How long does a task run? Tasks over a few minutes will outlive flaky local processes. Hosted sessions are built for this.
  3. How many concurrent tasks? Local concurrency is bounded by RAM and CPU. Hosted concurrency is bounded by your plan — check /pricing rather than assuming.
  4. Do you need to reproduce failures? If a failed run is unrecoverable, you need session artifacts and a viewer.
  5. What's your target site's tolerance? Sites with bot defenses respond to IP reputation and browser consistency. Configurable settings help; they are not a guarantee.

If you're still deciding whether the runtime layer is worth it, the remote browser for AI agents write-up covers the architectural case in more depth, and remote browser online walks through what running Chromium without local setup actually looks like.

Migrating from CLI to runtime without a rewrite

You don't have to abandon your CLI. The cleanest migration keeps the CLI as the agent's interface and swaps the browser underneath it:

  • Point the CLI at a remote CDP endpoint instead of launching local Chrome.
  • Move credential handling into profile storage rather than environment variables passed to a local process.
  • Replace local retry-on-crash logic with session reconnection against the same session ID.
  • Add a viewer step to your debugging loop so failures are inspectable after the fact.

This keeps your agent's action vocabulary intact — the model still emits the same commands — while removing the machine-local assumptions that cause production failures. For teams that want to drive sessions interactively as well as programmatically, remote control browser covers the human-in-the-loop case.

What to do next

Start by being precise about which "agent-browser" you need. If you're prototyping, install the CLI and get a task working end to end. If you're shipping, the question is not which CLI to use but where the browser lives.

The practical sequence:

  1. Get one task working locally with the CLI or a Playwright script.
  2. Identify which of the failure modes above actually applies to you.
  3. Move the browser to a hosted session and reconnect over CDP.
  4. Add persistent profiles for anything involving login.
  5. Instrument with the live viewer before you scale concurrency.

The documentation covers session creation, profile management, and CDP connection details. Current usage rates and plan limits are on /pricing.