BLOG
Puppeteer Connect to Existing Browser: CDP Guide for Production
Learn how to use Puppeteer connect to existing browser workflows via CDP, and when hosted Chromium makes sense for AI agents.
# Puppeteer Connect to Existing Browser: A Practical CDP Guide
If you're trying to figure out how to make Puppeteer connect to existing browser instances rather than launching a fresh Chromium process, you're not alone. This is one of the most common questions in browser automation, and it's especially relevant for AI agents that need to attach to a session that's already running.
The short answer is puppeteer.connect(), which uses the Chrome DevTools Protocol (CDP) to attach to a browser that's already listening on a debugging port. But the longer answer involves understanding when this pattern makes sense, what its limitations are, and how it scales beyond a single local machine.
This guide covers the mechanics of connecting Puppeteer to an existing browser, the trade-offs of local vs. hosted approaches, and what to consider when you're building production-grade automation or AI agent workflows.
Why Connect to an Existing Browser?
There are several legitimate reasons to attach Puppeteer to a running browser instead of launching a new one:
- Persistent sessions: You want to keep cookies, localStorage, and login state alive across script runs.
- Debugging: You started a browser manually with
--remote-debugging-port=9222and want to inspect or drive it. - Resource efficiency: You're running multiple scripts against the same browser process rather than spawning dozens of Chromium instances.
- AI agent workflows: An agent needs to observe and act on a browser session that was initiated by another tool or process.
The core mechanism is CDP. When Chromium starts with --remote-debugging-port=9222, it exposes a WebSocket endpoint. Puppeteer can connect to that endpoint and control the browser as if it had launched it itself.
The Mechanics: Puppeteer connect() and CDP
Here's the canonical pattern for connecting Puppeteer to an existing browser:
import puppeteer from 'puppeteer';
import type { Browser } from 'puppeteer';
async function connectToExistingBrowser(): Promise<Browser> {
// Assumes Chrome/Chromium is already running with:
// chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-profile
const browser = await puppeteer.connect({
browserURL: 'http://localhost:9222',
defaultViewport: null, // Preserve the existing viewport
});
const pages = await browser.pages();
console.log(`Connected to browser with ${pages.length} open pages`);
// Use the existing page or create a new one
const page = pages[0] ?? (await browser.newPage());
await page.goto('https://example.com');
// Don't call browser.close() — you're connected to a shared browser
// await browser.disconnect();
return browser;
}
connectToExistingBrowser().catch(console.error);Key points to note:
- `browserURL` vs. `browserWSEndpoint`: You can connect using either the HTTP endpoint (
http://localhost:9222) or the WebSocket endpoint directly. ThebrowserURLapproach is simpler because Puppeteer fetches the WebSocket URL for you.
- Don't call `browser.close()`: When you connect to an existing browser, calling
browser.close()will terminate the browser process. Instead, usebrowser.disconnect()to detach while leaving the browser running.
- `defaultViewport: null`: By default, Puppeteer sets a 800x600 viewport on pages it creates. When connecting to an existing browser, you often want to preserve the actual viewport, so pass
null.
- Multiple connections: CDP allows multiple clients to connect to the same browser. This is useful for observability — you can have one client driving the browser and another monitoring network traffic.
When Local CDP Connection Falls Short
The pattern above works well on a single machine. But it breaks down in several scenarios:
1. Distributed Systems
If your automation runs on one server but the browser is on another, you need to expose the debugging port over the network. This is a security risk — anyone who can reach that port can control the browser. You'd need to wrap it in a secure tunnel or VPN, which adds complexity.
2. Scaling
Managing a pool of long-running browser processes on a single machine is resource-intensive. Each Chromium instance can consume 500MB–1GB of RAM. When you need dozens of concurrent sessions for AI agents or test suites, local management becomes a bottleneck.
3. Reliability
Local browser processes crash. They get killed by OOM (out-of-memory) handlers. The machine reboots. When your AI agent depends on a browser session that's been running for hours, a crash means starting over.
4. Observability
When a browser runs locally, you can only see it if you have access to that machine. For debugging AI agent behavior, you often need to watch the browser live, replay sessions, or inspect network requests after the fact. This is hard to do with a local process.
The Hosted Alternative: Remote Browser
This is where hosted browser runtimes like Remote Browser come in. Instead of connecting Puppeteer to a local Chrome instance, you connect to a Chromium session running in the cloud.
The connection mechanism is the same — CDP over WebSocket — but the browser itself is managed for you. This shifts the operational burden:
| Concern | Local Chrome + CDP | Hosted Chromium (Remote Browser) |
|---|---|---|
| Setup | Install Chrome, launch with flags, manage ports | API key + connect call |
| Scaling | Manual process management, RAM limits | On-demand sessions, no local resource ceiling |
| Persistence | Tied to local process lifecycle | Persistent profiles survive session restarts |
| Observability | Limited to local DevTools | Live viewer, session recording, network logs |
| Network isolation | Depends on your machine's IP | Configurable proxy and browser settings |
| Failure recovery | Manual restart, state loss | Session state preserved, reconnection supported |
| Security | Open debugging port is risky | Authenticated API access |
The trade-off is that you're sending your browser traffic through a third-party service. For many teams, this is acceptable because the alternative — managing a browser farm — is more expensive and error-prone.
Puppeteer vs. Playwright for CDP Connections
While this guide focuses on Puppeteer, it's worth noting that Playwright has a similar capability. Playwright's chromium.connectOverCDP() method does essentially the same thing.
The choice between them often comes down to your existing stack:
- Puppeteer: Lighter weight, closer to raw CDP, good for Chrome-only workflows.
- Playwright: Multi-browser support (Chromium, Firefox, WebKit), better test runner integration, auto-waiting features.
For AI agents, the more important consideration is whether the library supports attaching to a remote browser over CDP. Both do. The question is what happens after you attach — can you maintain state, handle disconnects, and scale?
Production Criteria for Browser Connection
If you're building automation that needs to connect to an existing browser — whether local or hosted — here's what matters in production:
1. Connection Resilience
Network connections drop. The browser might restart. Your code should handle TargetClosedError and similar exceptions gracefully. Implement reconnection logic with exponential backoff.
2. Session State
For AI agents, losing session state (cookies, localStorage, etc.) often means the agent has to re-authenticate or restart its task. A hosted browser with persistent profiles can maintain state across connections, which is critical for long-running workflows.
3. Concurrency Isolation
If you're running multiple agents, each needs its own browser session. Sharing a browser between agents can lead to state leakage and unpredictable behavior. Look for a runtime that provides session isolation by default.
4. Live Debugging
When an agent gets stuck, you need to see what it's looking at. A live viewer that shows the browser screen in real time is invaluable for debugging. This is something hosted runtimes provide out of the box.
5. IP and Proxy Configuration
Some sites block traffic from data center IPs. If your automation targets such sites, you need the ability to configure proxies or use residential IPs. This is easier to manage in a hosted environment than on a local machine.
Code Example: Connecting to a Remote Browser Session
Here's how you'd connect Puppeteer to a hosted Chromium session using Remote Browser:
import puppeteer from 'puppeteer';
import { RemoteBrowserClient } from '@remote-browser/sdk'; // Hypothetical SDK
async function connectToRemoteBrowser() {
// Create a new browser session or retrieve an existing one
const client = new RemoteBrowserClient({
apiKey: process.env.REMOTE_BROWSER_API_KEY,
});
// This returns a WebSocket endpoint for a hosted Chromium session
const session = await client.createSession({
profileId: 'my-persistent-profile', // Optional: use a persistent profile
proxy: { country: 'US' }, // Optional: route through a proxy
});
// Connect Puppeteer to the remote browser using the WebSocket endpoint
const browser = await puppeteer.connect({
browserWSEndpoint: session.wsEndpoint,
defaultViewport: null,
});
const page = await browser.newPage();
await page.goto('https://example.com');
// Do your automation work here...
// Disconnect but keep the session alive for later reconnection
await browser.disconnect();
// Or terminate the session when done
// await session.terminate();
}
connectToRemoteBrowser().catch(console.error);The key difference from the local example is that the WebSocket endpoint points to a cloud-hosted Chromium instance rather than localhost. Everything else — page navigation, element interaction, network interception — works the same way.
When to Use Each Approach
There's no one-size-fits-all answer. Here's a practical decision framework:
Use local Chrome + CDP when:
- You're developing and debugging locally.
- You need offline capability.
- You have strict data residency requirements that prevent cloud browser usage.
- Your automation is short-lived and doesn't need persistence.
Use a hosted browser runtime when:
- You're running AI agents that need to operate 24/7.
- You need persistent profiles across sessions.
- You want live debugging and session recording.
- You need to scale beyond a single machine.
- Your automation targets sites that require specific IP configurations.
For more on the hosted approach, see our guide on remote browsers for AI agents and the remote browser online overview.
Security Considerations
Connecting to an existing browser over CDP has security implications:
- Never expose the debugging port publicly. Anyone with access to the port can control the browser, read cookies, and exfiltrate data.
- Use authentication for remote connections. If you must connect over the network, wrap the CDP endpoint in a service that requires authentication.
- Isolate sessions. Don't share a browser between untrusted code paths. A compromised script running in one page can potentially access other pages in the same browser.
- Be careful with `browser.close()`. As mentioned earlier, this kills the browser. In a shared environment, this could disrupt other users of that browser.
Conclusion
Connecting Puppeteer to an existing browser via CDP is a powerful pattern for persistent sessions, debugging, and resource efficiency. The mechanics are straightforward — puppeteer.connect() with a WebSocket endpoint — but the operational considerations are where things get complex.
For local development, connecting to a manually launched Chrome instance is perfectly fine. For production workloads, especially AI agents that need to run reliably over long periods, a hosted browser runtime addresses the scaling, persistence, and observability challenges that local setups struggle with.
The right choice depends on your specific requirements: how long your sessions need to live, how many concurrent sessions you need, and what level of operational overhead you're willing to accept.
If you're evaluating hosted options, check our pricing page for current details, or read about remote web browser patterns and remote control browser workflows to see what fits your use case.
For the underlying protocol, the Chrome DevTools Protocol documentation is the authoritative reference for what's possible over CDP connections.