← Blog

BLOG

AI Web Agents: The Browser Runtime They Need

AI web agents fail on flaky local Chrome. Learn how hosted Chromium, CDP, and persistent profiles make browser tools reliable in production.

9 min readRemote Browser
Ivory computer towers connected across terracotta platforms in a quiet desert landscape
The infrastructure behind your browserREMOTE BROWSER / ILLUSTRATION

AI web agents are programs that read pages, decide what to click, and complete multi-step tasks in a real browser. The model gets most of the attention, but the runtime underneath decides whether the agent finishes or stalls. A local Chrome instance on a laptop works for a demo. It breaks the moment you need concurrency, persistence, or a session that survives a deploy. This guide covers what AI web agents actually require from a browser runtime, where local setups fail, and how to wire hosted Chromium over CDP with Playwright. If you want the broader context first, see remote browsers for AI agents.

What AI web agents need from a browser

An agent loop is simple in outline: observe the page, choose an action, execute it, repeat. Each step depends on the browser being in a known state. That creates requirements that ordinary browser automation tools were not built around.

  • A real browser, not a parser. Agents need JavaScript execution, cookies, and client-side routing. Fetching HTML and parsing it misses most modern apps.
  • Stable sessions. A task may span dozens of steps over minutes. The browser must not be killed by a laptop sleep, a CI job timeout, or a container restart.
  • State that persists. Logins, cookies, and local storage often need to carry across runs. Re-authenticating on every task is slow and fragile.
  • Observability. When an agent picks the wrong button, you need to see the page it saw. Screenshots and a live view matter more than logs alone.
  • Isolation. Two agents on the same browser will corrupt each other's state. Each task needs its own session.
  • Network control. Some sites behave differently by geography or IP reputation. Proxy settings need to be configurable per session.

None of these are model problems. They are infrastructure problems, and they are where most production incidents originate.

Where local Chrome breaks down

Running Playwright or Puppeteer against a local Chrome install is the default starting point, and it is fine for development. In production, the failure modes stack up:

  1. Resource contention. Each Chromium instance consumes memory. Running ten agents on one machine means tuning limits, cleaning up zombie processes, and watching for OOM kills.
  2. Version drift. The browser binary, the driver, and the automation library must stay in sync. A silent Chrome auto-update can break a selector strategy overnight.
  3. No persistence layer. Local profiles live on disk in one place. Moving a task to another worker means losing the session.
  4. No remote visibility. Debugging means attaching to a process on a machine you may not control.
  5. Headless detection. Default headless Chrome is easy to fingerprint. Sites that gate automation will block it, and the agent loops on a challenge page.

You can solve each of these yourself — containerize Chromium, mount a volume for profiles, add a VNC sidecar, tune launch flags. That is a real engineering project, and it is not the project you set out to build.

Hosted Chromium as the runtime layer

A hosted browser runtime moves Chromium off your infrastructure. You request a session through an API, get back a CDP endpoint, and connect your existing automation code to it. Remote Browser provides this: hosted Chromium sessions with CDP access, Playwright/Puppeteer/Selenium compatibility, a live viewer, persistent profiles, configurable proxy and browser settings, and per-session isolation.

The important property is that nothing about your agent changes. If your agent already drives Playwright, it keeps driving Playwright. Only the connection target moves.

ConcernLocal ChromeHosted Chromium runtime
Session lifetimeTied to process or machineManaged independently of your worker
ConcurrencyLimited by host memoryProvisioned per session
Profile persistenceLocal disk onlyPersistent profiles across sessions
DebuggingAttach locally or via tunnelLive viewer plus CDP
Browser versionWhatever is installedControlled by the runtime
Proxy configurationLaunch flags per instanceConfigurable per session
IsolationManual, per processPer-session by default
Ops burdenYoursProvider's

This is the same trade-off as managed databases: you give up some control over the host and get back the operational surface you did not want to own.

Connecting an agent over CDP

The Chrome DevTools Protocol is the wire format between automation libraries and Chromium. Playwright's connectOverCDP and Puppeteer's connect both accept a WebSocket endpoint. A hosted runtime hands you that endpoint when a session starts.

The pattern below creates a session, connects Playwright, runs a task, and closes the session. Treat the endpoint as a secret — it grants full control of the browser.

import { chromium, Browser, Page } from "playwright";

interface SessionResponse {
  id: string;
  cdpUrl: string;
}

async function createSession(): Promise<SessionResponse> {
  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({
      // Persistent profile keeps cookies and logins across runs.
      profileId: "agent-checkout",
      // Proxy and browser settings are configurable per session.
      proxy: { country: "us" },
    }),
  });
  if (!res.ok) throw new Error(`session create failed: ${res.status}`);
  return (await res.json()) as SessionResponse;
}

async function runTask(): Promise<void> {
  const session = await createSession();
  let browser: Browser | undefined;

  try {
    browser = await chromium.connectOverCDP(session.cdpUrl);
    const context = browser.contexts()[0] ?? (await browser.newContext());
    const page: Page = await context.newPage();

    await page.goto("https://example.com/orders", { waitUntil: "domcontentloaded" });

    // Agent loop goes here: observe, decide, act.
    const rows = await page.locator("table.orders tbody tr").count();
    console.log(`orders visible: ${rows}`);

    await page.screenshot({ path: "orders.png" });
  } finally {
    // Disconnect the client; the session lifecycle is managed separately.
    await browser?.close();
  }
}

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

Two details matter here. First, browser.close() on a CDP connection disconnects your client — it does not necessarily terminate the remote browser. Check the runtime's session API for explicit termination. Second, browser.contexts()[0] reuses the existing context, which is what you want when a persistent profile is attached. Creating a new context discards that state.

For the protocol itself, the Chrome DevTools Protocol documentation is the authoritative reference for domains like Page, Network, and Runtime.

Browser tools and the agent loop

"Browser tools" usually refers to the action surface an agent is given: navigate, click, type, scroll, read text, screenshot. The quality of that surface determines how often the model succeeds. A few practical rules:

  • Prefer semantic selectors. Role and label-based locators survive layout changes better than CSS paths. Playwright's getByRole and getByLabel are built for this.
  • Return compact observations. Sending the full DOM to a model wastes tokens and adds noise. Extract interactive elements with their roles and labels.
  • Make actions idempotent where possible. Agents retry. A click that submits a form twice is a bug you will ship.
  • Bound the loop. Set a step limit and a wall-clock timeout. An agent that cannot finish should fail loudly, not run until the session expires.
  • Capture evidence. A screenshot on failure is worth more than a stack trace when the page rendered differently than expected.

The runtime supports these patterns but does not enforce them. That design work stays with you.

Production criteria for choosing a runtime

When you evaluate hosted browser options for AI web agents, compare on these axes rather than on marketing pages:

  1. CDP fidelity. Does the runtime expose a standard CDP endpoint, or a proprietary protocol? Standard CDP means your Playwright and Puppeteer code ports without changes.
  2. Session lifecycle. Can you create, inspect, and terminate sessions explicitly? Are there hooks for cleanup on failure?
  3. Profile handling. Are persistent profiles supported, and can you scope them per agent or per user?
  4. Network controls. Can you set proxies per session? Are browser settings configurable without forking the runtime?
  5. Observability. Is there a live viewer? Can you retrieve recordings or screenshots after the fact?
  6. Isolation. Is each session a separate browser, or are sessions multiplexed in ways that leak state?
  7. Usage controls. Are there limits and metering you can reason about? See /pricing for current rates and quotas rather than assuming a number.
  8. Compliance posture. If you handle user data, ask about retention, data residency, and audit options.

A runtime that scores well on CDP fidelity and session lifecycle will usually be easy to adopt. One that scores well on stealth but poorly on observability will be painful to debug.

Common failure modes and fixes

Agent gets stuck on a login wall. The profile is not persisting, or the session is not attaching to it. Verify the profile ID is passed at session creation and that you reuse the existing browser context.

Selectors break after a deploy. The site changed its markup. Move to role-based locators and add a fallback that reads visible text.

Sessions time out mid-task. The task is too long for the session limit, or the agent is looping. Add step and time budgets, and split long workflows into resumable stages.

Requests get blocked. The IP reputation or browser settings are triggering a challenge. Configure a proxy and review your launch settings. Do not assume any single setting solves detection — it is a moving target.

Costs climb unexpectedly. Agents that retry indefinitely burn session time. Meter per task, alert on outliers, and cap concurrency. Current usage terms are on /pricing.

Debugging is blind. You have logs but not the page. Turn on the live viewer during development and capture screenshots at each decision point.

When hosted Chromium is the right call

Hosted Chromium is not always the answer. If you run a handful of short scripts on a schedule, a local Playwright install on a small VM is cheaper and simpler. If you need a browser for a single interactive session, a remote browser online is enough.

Hosted runtimes earn their cost when:

  • You run many agents concurrently and do not want to manage a Chromium fleet.
  • Tasks need persistent logins and cookies across runs.
  • You need to watch or replay sessions for debugging and audit.
  • Your workers are ephemeral — serverless functions, short-lived containers — and cannot hold a browser process.
  • You want browser version and configuration managed for you.

The documentation covers session creation, profile management, and CDP connection details in depth. If you are comparing runtimes, the remote web browser overview and the remote control browser guide cover adjacent use cases.

Bottom line

AI web agents are only as reliable as the browser they run in. The model decides what to do; the runtime decides whether the page is still there when it tries. Moving Chromium to a hosted runtime with standard CDP access removes the operational failure modes — version drift, resource contention, lost sessions, blind debugging — without changing your agent code. Start by connecting one existing Playwright script to a hosted session, watch it in the live viewer, and measure where it fails. That tells you more about your runtime needs than any comparison table.