BLOG
Best Browser Agent: How to Choose a Runtime in 2026
What makes the best browser agent runtime: CDP access, session isolation, profiles, proxies, and cost. A practical evaluation guide with code.
# Best Browser Agent: How to Choose a Runtime in 2026
The best browser agent is not a single product — it is the combination of an agent framework and a browser runtime that survives production. Most teams pick the framework first (browser-use, Stagehand, Playwright with an LLM loop) and then discover that the runtime is where tasks actually fail: sessions die mid-flow, logins reset, proxies leak, and nobody can see what the agent saw. This guide covers the criteria that separate a demo-grade browser agent from one you can run on a schedule, with concrete checks you can run against any candidate runtime, including Remote Browser.
If you want the short version: judge a runtime on four things — CDP fidelity, session lifecycle control, state persistence, and observable cost. Everything else is marketing.
What "best browser agent" actually means
A browser agent is an LLM-driven loop that observes a page, decides on an action, and executes it through a browser automation API. The loop itself is cheap to build. The hard part is the browser underneath it:
- Determinism of the connection. Can your agent reconnect to the same session after a worker restart?
- Fidelity of the control surface. Does the runtime expose the full Chrome DevTools Protocol, or a lossy wrapper?
- Isolation. Does one agent's cookies, storage, or proxy bleed into another's?
- Visibility. Can a human watch the session live and replay it after a failure?
Frameworks like browser-use and Stagehand are excellent at the reasoning layer. They are not runtimes. The runtime is the part that decides whether your agent completes 200 tasks a day or 40.
The evaluation criteria that matter
1. CDP access, not just a screenshot API
The strongest signal of runtime quality is whether you can connect over CDP with standard tooling. If a provider only offers a REST endpoint that returns screenshots and click coordinates, your agent is locked into their action vocabulary. If it exposes a CDP WebSocket endpoint, you can drive it with Playwright, Puppeteer, Selenium, or a raw CDP client — and swap frameworks later without re-platforming.
Playwright's `connectOverCDP` is the reference implementation for this pattern. It attaches to an existing Chromium instance rather than launching one, which is exactly what a hosted runtime needs to support.
2. Session lifecycle control
Ask three questions of any candidate:
- Can I create a session with a TTL and extend it? Long agent tasks (multi-step checkout, multi-page research) routinely exceed default timeouts.
- What happens on disconnect? A good runtime keeps the browser alive for a grace period so a crashed worker can reconnect.
- Can I stop a session explicitly? Orphaned sessions are the most common cause of surprise bills.
3. Persistent profiles and state
Agents that log in, fill carts, or maintain context across runs need persistent storage — cookies, localStorage, IndexedDB. A runtime that wipes state on every session forces your agent to re-authenticate on every task, which is slow and triggers bot detection. Look for named profiles you can attach to a session by ID.
4. Proxies and configurable browser settings
Residential and datacenter proxies are table stakes. What matters is whether proxy configuration is per-session, whether it is applied before the first navigation, and whether you can set browser-level options (locale, timezone, user agent, viewport) without patching the runtime. Be skeptical of vague "anti-detection" claims that are not documented — prefer runtimes that expose explicit, configurable settings you can audit.
5. Live viewer and recordings
When an agent fails at step 14 of 20, you need to see the DOM it saw, not a log line. A live viewer (a real-time stream of the session) and session recordings turn debugging from guesswork into a diff. This is the single biggest productivity difference between runtimes in practice.
6. Cost model
Per-browser-hour pricing is standard, but the details differ: whether idle time counts, whether there is a minimum billing increment, whether concurrency is capped by plan. Check /pricing for current Remote Browser rates rather than relying on any third-party comparison, including this one.
Comparison: runtime categories
| Runtime type | CDP access | State persistence | Ops burden | Best for |
|---|---|---|---|---|
| Local Playwright/Puppeteer | Full | Manual (user data dir) | High — you manage Chrome, deps, scaling | Prototyping, CI with fixed infra |
| Self-hosted Browserless/Steel | Full | Configurable | Medium — you run containers | Teams with existing k8s and a browser ops owner |
| Hosted runtime (Remote Browser, Browserbase, Hyperbrowser) | Full via CDP endpoint | Named profiles | Low | Production agents, small teams |
| Screenshot/action API only | None | Limited | Low | Simple scraping, not agentic loops |
The middle two rows are where most production teams land. Self-hosting is viable if you already run container orchestration and can absorb Chrome upgrade churn, zombie process cleanup, and proxy management. Hosted runtimes trade a per-hour fee for removing that work. Neither is universally better — the decision hinges on whether browser ops is a core competency for your team.
Wiring an agent to a hosted runtime
The implementation is short. The following TypeScript example connects Playwright to a Remote Browser session over CDP, attaches a persistent profile, and wraps the agent loop with a reconnect guard. Replace the endpoint and session creation call with your provider's API.
import { chromium, Browser, Page } from "playwright";
interface SessionInfo {
cdpUrl: string; // wss://... from your runtime's session-create call
sessionId: string;
}
async function createSession(profileId: string): Promise<SessionInfo> {
const res = await fetch("https://api.remote-browser.dev/v1/sessions", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.RB_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
profileId, // persistent cookies/localStorage
ttlSeconds: 1800, // extend if your task is longer
proxy: { country: "us" },
}),
});
if (!res.ok) throw new Error(`session create failed: ${res.status}`);
return res.json();
}
async function withBrowser<T>(
session: SessionInfo,
fn: (page: Page) => Promise<T>,
): Promise<T> {
let browser: Browser | undefined;
for (let attempt = 0; attempt < 3; attempt++) {
try {
browser = await chromium.connectOverCDP(session.cdpUrl);
const context = browser.contexts()[0] ?? (await browser.newContext());
const page = context.pages()[0] ?? (await context.newPage());
return await fn(page);
} catch (err) {
if (attempt === 2) throw err;
await new Promise((r) => setTimeout(r, 1000 * 2 ** attempt));
}
}
throw new Error("unreachable");
}
// Usage
const session = await createSession("checkout-agent");
const result = await withBrowser(session, async (page) => {
await page.goto("https://example.com/cart", { waitUntil: "domcontentloaded" });
// ... agent observe/act loop ...
return page.title();
});Two details matter here. First, connectOverCDP returns a Browser whose contexts are the ones already open in the remote session — do not call newContext() blindly or you will lose the persistent profile's state. Second, the retry loop reconnects to the *same* session URL; if your runtime rotates the endpoint on reconnect, fetch it again inside the loop.
For the full API surface, see the documentation. For a broader look at why the runtime layer exists at all, read Remote browsers for AI agents.
Where browser agents fail in production
The failure modes are consistent across frameworks:
- Session expiry mid-task. Default TTLs are often 5–15 minutes. A research agent that visits 30 pages will hit that. Set TTLs explicitly and extend on activity.
- Auth state loss. If profiles are not persistent, every run starts logged out. This is the most common cause of "the agent worked yesterday."
- Concurrency collisions. Two agents sharing a profile will corrupt each other's cookies. Use one profile per logical identity, not per agent instance.
- Silent CAPTCHA walls. The agent loops on a challenge page until timeout. A live viewer makes this obvious in seconds; without one, you find out from a failed batch.
- Unbounded cost. A stuck agent that retries for an hour burns an hour of browser time. Enforce per-task wall-clock limits in your orchestrator, not just in the runtime.
None of these are solved by a better LLM. They are solved by runtime features and orchestration discipline.
How to benchmark candidates before committing
Run the same three tasks against every candidate runtime:
- A login flow with a persistent profile. Log in once, close the session, open a new session with the same profile, and confirm you are still authenticated.
- A 20-page crawl with a 5-minute TTL. Confirm the session survives and that you can extend it.
- A forced disconnect. Kill the client mid-task, reconnect, and verify the page state is intact.
Score each on completion, time-to-first-page, and whether you needed support to debug. This is more informative than any published benchmark, because it tests your actual workload. If you want to compare against a local baseline first, Remote browser online covers the setup differences.
When a hosted runtime is the wrong choice
Be honest about the trade-off. A hosted runtime adds a network hop between your agent and the browser, which matters for latency-sensitive loops that take dozens of actions per page. It also means your page content transits a third party — check data retention terms if you handle regulated data. And if your workload is a fixed set of 50 URLs scraped hourly, a self-hosted Playwright container on your existing infra is probably cheaper and simpler.
Hosted runtimes win when: you need persistent profiles and proxies without building that infrastructure, you want a live viewer for debugging, your concurrency is bursty, or your team does not want to own Chrome upgrades.
The practical answer
The best browser agent is the one whose runtime you can debug at 2 a.m. That means CDP access so you can use standard tooling, persistent profiles so state survives, a live viewer so failures are visible, and a cost model you can predict. Framework choice matters less than most comparisons suggest — browser-use, Stagehand, and a hand-rolled Playwright loop all work well on top of a competent runtime, and all of them struggle on a bad one.
Start by testing the three scenarios above against your current setup. If session expiry or state loss is already biting you, the runtime is the bottleneck, not the model. Remote Browser exposes hosted Chromium sessions over CDP with persistent profiles, configurable browser settings, and a live viewer; current rates and limits are on /pricing, and connection details are in the documentation.