Playwright Remote: Run Browser Automation in the Cloud
Running Playwright against a remote browser is the difference between a script that works on your laptop and an automation pipeline that survives production. When you connect Playwright to a hosted Chromium instance over the Chrome DevTools Protocol (CDP), you get persistent sessions, clean IP reputation, and the ability to scale across workers without managing browser infrastructure yourself.
This guide covers what Playwright remote execution actually means, how to connect to a hosted browser over CDP, and the production criteria that matter when you move from local scripts to cloud-hosted sessions.
Why "Playwright Remote" Is More Than a Hostname Change
Playwright's connect_over_cdp() method lets you attach to an already-running browser. Locally, that's useful for debugging. In production, it's the foundation for a different architecture: the browser lives in the cloud, your code connects to it, and the session persists independently of your worker process.
This matters for three reasons:
- Session persistence — A browser that survives worker restarts keeps cookies, localStorage, and login states intact.
- IP consistency — The browser's egress IP stays stable, which matters for sites that flag automation traffic.
- Resource isolation — Your Playwright script runs in a lightweight worker while the heavy browser process runs elsewhere.
The common alternative — launching a browser inside your worker — couples browser lifecycle to code lifecycle. If your worker dies, the browser dies. If you need to retry a task, you start from zero.
How to Connect Playwright to a Remote Browser
Remote Browser exposes hosted Chromium sessions via CDP. Your Playwright script connects using connect_over_cdp(). Here's a minimal TypeScript example:
import { chromium } from 'playwright';
async function main() {
// Connect to a hosted Chromium session via CDP
const browser = await chromium.connectOverCDP(
'wss://remote-browser.dev/cdp/your-session-id'
);
// The default context is the browser's persistent context
const context = browser.contexts()[0];
const page = await context.newPage();
await page.goto('https://example.com');
console.log(await page.title());
// The browser stays alive after your script exits
await browser.close();
}
main().catch(console.error);
The key detail: browser.close() disconnects your client but doesn't terminate the hosted browser. That's the semantic shift from local Playwright. You're a client, not the owner.
CDP vs. Playwright's WebSocket Protocol
Playwright has two remote connection modes:
| Mode | Method | Use Case |
|---|---|---|
| CDP | connectOverCDP() |
Attach to existing Chrome/Chromium, persistent sessions, cross-language control |
| Playwright Protocol | connect() |
Connect to a Playwright server, full control over browser lifecycle |
For AI agents and long-running automation, CDP is usually the right choice. It lets you attach to a browser that someone else manages, and it's the standard protocol for browser tooling. Playwright's own documentation covers CDP connection details if you need the full API reference.
Production Criteria for Playwright Remote Setups
Not all remote browser services are equal. When evaluating a Playwright remote setup, check these criteria:
1. Session Lifecycle Control
Your browser session should outlive any single script execution. Look for:
- Sessions that persist until explicitly terminated
- Ability to reconnect after network drops
- Snapshot or restore capabilities for long-running tasks
2. Live Debugging and Visibility
When a Playwright script fails in production, you need to see what happened. A live viewer or session replay is not a luxury — it's how you debug flaky selectors and unexpected popups.
3. Proxy and IP Management
Sites increasingly block datacenter IPs. A remote browser service should let you configure proxy settings per session, so you can route traffic through residential or clean IPs when needed.
4. Profile Persistence
Cookies, localStorage, and browser profiles should survive across connections. This is what makes "login once, use many times" workflows possible.
5. Compatibility Layer
Your existing Playwright code should work without rewrites. If you need to switch from launch() to connectOverCDP(), that's fine. If you need to rewrite your entire automation logic, that's a red flag.
Playwright Remote vs. Local Browser Management
Here's a practical comparison:
| Aspect | Local Playwright | Playwright Remote (Hosted Chromium) |
|---|---|---|
| Setup time | Minutes | Minutes (API key + session ID) |
| Session persistence | Tied to process | Independent of process |
| Scaling | Manual, per-machine | Add workers, reuse sessions |
| IP reputation | Your IP, your problem | Configurable egress IPs |
| Resource usage | Browser + script compete | Browser isolated in cloud |
| Debugging | Local DevTools | Live viewer, session logs |
| Cost | Hardware + maintenance | Metered browser hours |
The trade-off is straightforward: local Playwright is fine for development and small test suites. Once you need reliability, persistence, or scale, remote execution wins.
Keeping Browser Sessions Alive Across Cloud Workers
A common pattern: you have multiple cloud workers (Lambda, Cloudflare Workers, Fly Machines) that need to share browser state. With Playwright remote, each worker connects to the same hosted browser session.
// worker-a.ts — logs in and stores state
import { chromium } from 'playwright';
const browser = await chromium.connectOverCDP(process.env.CDP_URL!);
const context = browser.contexts()[0];
const page = await context.newPage();
await page.goto('https://app.example.com/login');
await page.fill('#email', process.env.EMAIL!);
await page.fill('#password', process.env.PASSWORD!);
await page.click('button[type="submit"]');
await page.waitForURL('https://app.example.com/dashboard');
// Session state is now persisted in the hosted browser
await browser.close();
// worker-b.ts — reuses the session
import { chromium } from 'playwright';
const browser = await chromium.connectOverCDP(process.env.CDP_URL!);
const context = browser.contexts()[0];
const page = await context.newPage();
// Already authenticated
await page.goto('https://app.example.com/dashboard');
const data = await page.locator('.data-table').innerText();
console.log(data);
await browser.close();
This pattern eliminates re-login overhead and keeps state consistent across your fleet.
Playwright Remote for AI Agents
AI agents that browse the web have different requirements than test suites. They need:
- Long-lived sessions — Agents can run for hours, not minutes
- Human-like behavior — Configurable browser settings to avoid detection
- Observability — See what the agent is doing in real time
- Isolation — Separate sessions for separate tasks or users
Remote Browser's hosted Chromium is built for this. The remote browser for AI agents post covers the runtime layer in more detail, but the core idea is: your agent code connects to a browser that's already running, does its work, and disconnects — without killing the session.
The "Agent Browser" Confusion
You might see "agent browser" in your task manager or in product names. That's usually a browser process spawned by an automation tool. The term is overloaded — it can mean:
- A browser controlled by an AI agent
- A browser that runs agent tasks (like Remote Browser)
- A browser process in Chrome's task manager (often just a renderer process)
For production AI workloads, what matters is whether the browser runtime supports the patterns above: persistence, CDP access, and live debugging.
Selenium and Puppeteer: The Same Remote Pattern
Playwright isn't the only automation library that benefits from remote browsers. Selenium's WebDriver protocol and Puppeteer's CDP support both work with hosted Chromium. The pattern is identical:
- Start (or connect to) a hosted browser session
- Get the connection endpoint (WebSocket URL for CDP, or a remote WebDriver URL)
- Point your automation library at that endpoint
- Run your script, disconnect, keep the browser alive
If you're standardizing on Playwright but have legacy Selenium tests, a remote browser service that supports both protocols lets you migrate incrementally.
Common Pitfalls with Playwright Remote
Pitfall 1: Assuming browser.close() Terminates the Session
In local Playwright, browser.close() kills the browser. With connectOverCDP(), it disconnects your client. The hosted browser keeps running. This is usually what you want, but it means you need explicit session termination for cleanup.
Pitfall 2: Ignoring Context Isolation
A hosted browser may have multiple contexts. Make sure you're operating in the right one. browser.contexts()[0] is the default, but if you create new contexts, track them explicitly.
Pitfall 3: Not Handling Reconnects
Network connections drop. Your Playwright client should handle disconnected events and reconnect to the same session. The browser state persists; your client connection doesn't have to.
Pitfall 4: Forgetting About Browser Version
Hosted browsers are managed by the service provider. If your Playwright version expects a specific Chromium version, check compatibility. Most services run recent stable Chromium, but pinning your Playwright version to match is safer.
When Not to Use Playwright Remote
Remote execution isn't always the answer. Consider local Playwright if:
- You're running a small test suite with no persistence needs
- You need to test browser extensions that require local installation
- You have strict data residency requirements that prevent cloud browser usage
- Your automation is short-lived and stateless
The decision hinges on whether you need persistence, scale, or IP management. If none of those apply, local is simpler.
Getting Started with Remote Browser
Remote Browser provides hosted Chromium sessions with CDP access, Playwright compatibility, and the production features discussed above. The documentation covers API details, and the pricing page has current rates for browser hours.
For a deeper dive into specific use cases:
- Remote browser online — running Chromium without local setup
- Remote web browser — the practical runtime for browser automation
- Remote control browser — when code and agents need to drive the web
The Bottom Line on Playwright Remote
Playwright remote execution via CDP is the production pattern for browser automation that needs to survive beyond a single script run. It decouples browser lifecycle from code lifecycle, enables session persistence across workers, and gives you the observability you need to debug real-world automation.
The shift from chromium.launch() to chromium.connectOverCDP() is small in code but significant in architecture. You stop managing browsers and start using them as a service. For AI agents, multi-worker pipelines, and anything that needs consistent browser state, that's the right trade.
Start with a hosted Chromium session, connect your existing Playwright code, and see how much of your infrastructure overhead disappears.
Top comments (0)