← Blog

BLOG

Browse Tools for AI Agents: A Production Runtime Guide

Browse tools for AI agents need a real browser runtime. Learn how hosted Chromium, CDP, and persistent profiles fit into production web automation.

10 min readRemote Browser
An ivory retro computer overlooking a terracotta landscape beneath a sage green sky
A real browser for your next workflowREMOTE BROWSER / ILLUSTRATION

"Browse tools" is a loose phrase. It can mean a browser extension, a scraping library, a CLI, or a full remote runtime. For teams building an AI agent for a website, the choice matters more than the label suggests. The browse tools you pick determine whether your agent can hold a session, survive a login, and be debugged when it fails at 2 a.m.

This guide separates the categories, explains where each one breaks down in production, and shows how to wire a hosted Chromium runtime into a Playwright or CDP workflow. If you already know you need a remote browser, the remote browser for AI agents post covers the runtime layer in more depth.

What "browse tools" actually covers

The term spans at least four distinct things, and conflating them is the most common source of bad architecture decisions.

  • Browser automation libraries. Playwright, Puppeteer, and Selenium drive a browser from code. They are the control layer, not the browser itself.
  • Agent frameworks. browser-use, Stagehand, and similar projects wrap a library with an LLM loop that decides what to click next.
  • CLI and MCP wrappers. Tools like agent-browser expose browser actions as commands or tool calls so an agent can invoke them without writing Playwright.
  • Browser runtimes. The actual Chromium process, its network, its profile, and its lifecycle. This is where most production failures live.

Most "browse tools" content focuses on the first three. The fourth is the one that decides whether your automation holds up under load, across logins, and behind anti-bot defenses.

Where local browse tools stop working

Running Playwright against a local Chrome install is fine for development. It becomes a liability when you move to production for a few predictable reasons.

Session state is fragile. A local browser profile lives on one machine. If your worker restarts, the cookies, localStorage, and logged-in state are gone unless you built persistence yourself. Agents that need to stay signed in to a dashboard or SaaS tool break on every deploy.

Concurrency is bounded by the host. Each Chromium instance consumes a significant amount of RAM. Running twenty in parallel on one box is possible; running two hundred is not. You end up building a scheduler, a queue, and a cleanup process before you have shipped a single task.

Debugging is blind. When an agent fails, you get a stack trace and maybe a screenshot. You cannot watch the session live, rewind it, or inspect the DOM at the moment of failure without adding instrumentation.

Network identity is shared. Every session from one host shares an IP. Sites that rate-limit or fingerprint will treat your agent's traffic as one client, which is rarely what you want when running many independent tasks.

Environment drift. Chrome updates, OS patches, and font differences change rendering. A selector that worked in CI fails on a different host because the page laid out differently.

Hosted runtimes address these by moving the browser off your infrastructure. The trade-off is a network hop and a dependency on a provider, which is why the criteria below matter.

The production criteria that separate browse tools

Before comparing options, define what "production" means for your workload. These are the dimensions that actually cause incidents.

CriterionWhy it mattersWhat to check
Session isolationOne agent's cookies must not leak into another'sSeparate browser contexts or processes per session
Persistent profilesAgents need to stay logged in across runsProfile save/restore tied to a stable identifier
CDP accessYou need Playwright, Puppeteer, or raw CDPWebSocket endpoint exposed per session
Live viewerHumans must watch and interveneReal-time session view, not just recordings
Proxy and network controlsIP identity affects success rateConfigurable proxy settings per session
Lifecycle controlsSessions must start and stop cleanlyExplicit create/stop API, idle timeouts
Usage meteringCost must be predictablePer-session or per-hour accounting, visible in a dashboard
DebuggabilityFailures must be reproducibleLogs, recordings, and DOM snapshots

A tool that scores well on the first three but fails on the last three is a demo, not a runtime. The documentation covers how Remote Browser exposes each of these.

Comparing browse tool categories

Here is how the main categories stack up for an AI agent that needs to complete real tasks on a website.

CategoryBest forWeakness in productionTypical fix
Local Playwright/PuppeteerDevelopment, CI testsNo persistence, bounded concurrencyMove to hosted runtime
Scraping libraries (requests, cheerio)Static pages, APIsNo JS execution, no login flowsUse a real browser for dynamic sites
Agent frameworks (browser-use, Stagehand)Task planning and controlStill need a browser underneathPoint them at a remote CDP endpoint
CLI/MCP wrappersQuick agent integrationThin abstraction over the runtimePair with a managed browser
Hosted browser runtimeScale, persistence, debuggingNetwork hop, provider dependencyChoose on isolation and CDP fidelity

The pattern is consistent: frameworks and CLIs are control layers, and they all need a runtime. The question is whether you build that runtime or rent it.

Wiring a hosted runtime into your browse tools

The integration path is the same whether you use Playwright directly, Puppeteer, or an agent framework that speaks CDP. You request a session, get a WebSocket endpoint, and connect.

import { chromium } from "playwright";

// Request a session from the runtime API.
// Replace with your actual endpoint and auth header.
async function createSession(): Promise<{ cdpUrl: string; sessionId: string }> {
  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({
      // Reuse a profile so logins persist across runs.
      profileId: "agent-checkout-flow",
      // Configurable browser settings; see docs for supported options.
      settings: { locale: "en-US", timezone: "America/New_York" },
    }),
  });
  if (!res.ok) throw new Error(`session create failed: ${res.status}`);
  const data = await res.json();
  return { cdpUrl: data.cdpUrl, sessionId: data.id };
}

async function runTask() {
  const { cdpUrl, sessionId } = await createSession();
  const browser = await chromium.connectOverCDP(cdpUrl);

  try {
    const context = browser.contexts()[0] ?? (await browser.newContext());
    const page = await context.newPage();
    await page.goto("https://example.com/dashboard", { waitUntil: "domcontentloaded" });

    // Your agent logic here: locate elements, fill forms, extract data.
    const title = await page.title();
    console.log("page title:", title);
  } finally {
    // Always close the connection; stop the session via the API.
    await browser.close();
    await fetch(`https://api.remote-browser.dev/v1/sessions/${sessionId}`, {
      method: "DELETE",
      headers: { Authorization: `Bearer ${process.env.REMOTE_BROWSER_API_KEY}` },
    });
  }
}

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

Two details matter here. First, connectOverCDP attaches to an existing browser rather than launching one, which is how you drive a remote session. The Playwright CDP documentation covers the connection semantics and the Chromium-only constraint. Second, the profileId is what makes persistence work: the runtime loads the saved profile before the session starts, so cookies and storage are already present when your agent's first goto runs.

For raw CDP without Playwright, the Chrome DevTools Protocol defines the domains you will use: Page, Runtime, Network, and Target. Most agent frameworks use a subset of these under the hood.

Persistent profiles and the profile list

A profile is the unit of identity in a hosted runtime. It holds cookies, localStorage, IndexedDB, and cached credentials. The runtime keeps a profile list you can reference by ID when creating sessions.

This matters for three workflows:

  • Long-lived logins. An agent that checks a SaaS dashboard daily should reuse one profile so it does not re-authenticate every run.
  • Per-customer isolation. If you run agents on behalf of many users, each user gets a profile. Sessions never share state.
  • Reproducible debugging. When a task fails, you can replay it against the same profile to see whether the issue was state or logic.

The trade-off is that profiles are stateful and therefore need lifecycle management. You will want to rotate credentials, expire stale profiles, and audit which sessions touched which profile. A runtime that treats profiles as first-class objects makes this tractable; one that treats them as an afterthought does not.

Live viewer and debugging

The single biggest gap between local and hosted browse tools is observability. With a local browser, you can watch the window. With a remote session, you need a viewer.

A useful live viewer shows the current page, lets you take control, and pairs with a session log. When an agent gets stuck on a modal or a CAPTCHA, a human can step in, complete the step, and hand control back. This is not a nice-to-have; it is the difference between an agent that fails silently and one that can be recovered.

Pair the viewer with recordings. A recording of a failed session, replayed alongside the agent's action log, tells you exactly which selector missed and why. The remote control browser post covers the intervention workflow in detail.

Cost and usage controls

Hosted runtimes meter by session time, usually in browser-hours. The exact rate depends on the provider and the plan, so check /pricing for current numbers rather than relying on a blog post.

What matters architecturally is that you can see and bound usage:

  • Idle timeouts. Sessions that sit open without activity should stop automatically.
  • Per-task budgets. If a task is expected to take two minutes, a session that runs for twenty is a bug, not a cost problem.
  • Concurrency limits. Know your plan's ceiling before you scale a queue.
  • Attribution. Tag sessions by task or customer so you can see where time goes.

Teams that skip this step discover their cost problem only after a runaway loop has been running for a week.

When to use a hosted runtime vs. local

A simple decision rule:

  • Local is fine for development, one-off scripts, and CI tests where you control the environment and do not need persistence.
  • Hosted is necessary when you need concurrency beyond one machine, persistent logins, live debugging, or network isolation per session.
  • Hybrid works well: develop locally against the same Playwright code, then point connectOverCDP at a hosted endpoint in staging and production.

The remote web browser post walks through the hybrid setup if you want to keep local iteration fast while running production remotely.

Common mistakes with browse tools

A few patterns show up repeatedly in teams moving from prototype to production.

Treating the agent framework as the runtime. browser-use and Stagehand are excellent control layers, but they still need a browser. If you run them against a local Chrome on a single VM, you inherit every limitation above.

Ignoring profile hygiene. Reusing one profile across all tasks is convenient until one task's cookies corrupt another's session. Scope profiles to the smallest unit of identity that makes sense.

Skipping the viewer. Teams that never watch their sessions in production are surprised by how often agents get stuck on cookie banners, interstitials, and layout shifts. A viewer turns a mystery into a five-minute fix.

Hardcoding selectors without fallbacks. Pages change. An agent that relies on a single CSS selector will break. Prefer role-based locators, text matching, and explicit waits over fixed sleeps.

Not metering. Without usage visibility, you cannot tell whether a task is slow because of the site, the network, or your own retry logic.

Getting started

The practical path is short. Pick a runtime that exposes CDP, create a session, connect with Playwright, and run one real task end to end. Then add a profile, watch the session in the viewer, and measure how long it takes.

If you want to see the runtime in action before writing code, the remote browser online guide covers the browser-only path. When you are ready to integrate, the documentation has the session API, profile management, and connection examples for Playwright, Puppeteer, and raw CDP.

Browse tools are only as good as the browser underneath them. Choose the runtime on isolation, persistence, CDP fidelity, and debuggability, and the rest of your stack, from agent framework to CLI, will have a stable foundation to build on.