Puppeteer Connect Options Explained
Connect Puppeteer to an existing browser with the right WebSocket endpoint or debugging URL. Learn the current options, defaults, and common fixes.
puppeteer.connect() attaches Puppeteer to a browser that is already running and returns a Browser object. Use browserWSEndpoint when you have the browser’s DevTools WebSocket URL, or browserURL when you have its debugging HTTP address. Use launch() instead when Puppeteer should start the browser process.
This guide covers Puppeteer 25.12.0’s documented connection options. Defaults and experimental labels can change, so check the current ConnectOptions reference when upgrading.
1. Connect Puppeteer to an existing browser
Install Puppeteer in a Node.js project, then pass one supported browser address to puppeteer.connect(). This example uses a WebSocket endpoint and closes only Puppeteer’s connection when it finishes; it does not ask Puppeteer to start the browser.
import puppeteer from 'puppeteer';
const browser = await puppeteer.connect({
browserWSEndpoint: process.env.PUPPETEER_WS_ENDPOINT,
});
try {
const pages = await browser.pages();
const page = pages[0] ?? await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
console.log(await page.title());
} finally {
await browser.disconnect();
}
Set PUPPETEER_WS_ENDPOINT to the full WebSocket URL supplied by your browser or hosting provider. Treat it as a credential: anyone who can use the endpoint may control the browser.
2. Find the browser endpoint
Use browserWSEndpoint
A DevTools WebSocket endpoint commonly has this shape:
ws://HOST:PORT/devtools/browser/<id>
If you already have a Puppeteer Browser instance, browser.wsEndpoint() returns its endpoint. For an independently started Chromium browser, the DevTools version endpoint at http://HOST:PORT/json/version returns JSON with a webSocketDebuggerUrl field. Use the value as the browserWSEndpoint.
const response = await fetch('http://127.0.0.1:9222/json/version');
if (!response.ok) throw new Error(`Version endpoint returned ${response.status}`);
const { webSocketDebuggerUrl } = await response.json();
const browser = await puppeteer.connect({ browserWSEndpoint: webSocketDebuggerUrl });
Only expose the debugging port on networks you trust. A reachable DevTools endpoint grants browser control; do not publish it to the open internet without an access-controlled tunnel or provider-supported protection.
Use browserURL
Pass the browser’s debugging HTTP address when that is what your environment provides:
const browser = await puppeteer.connect({
browserURL: 'http://127.0.0.1:9222',
});
Use the exact address and port documented by the browser deployment or hosting provider. Do not assume the browser’s ordinary website URL is a debugging address. For remote connections, the service may require a tunnel, authentication, or a provider-specific setup.
3. Connect options and defaults
ConnectOptions is the shared browser configuration interface used for launch and connection. These are the options most relevant when attaching to an existing browser.
| Option | Behavior and default | When to use it |
|---|---|---|
browserWSEndpoint |
Connect using the DevTools WebSocket URL. | Use when you have the browser WebSocket endpoint. |
browserURL |
Connect through the browser’s debugging HTTP address. | Use when your environment supplies that address instead of a WebSocket URL. |
defaultViewport |
Defaults to { width: 800, height: 600 }; null prevents Puppeteer from applying that default viewport to each page. |
Set explicit dimensions for consistent page work, or use null to preserve the browser’s existing viewport behavior. |
protocolTimeout |
Defaults to 180,000 ms for an individual protocol call. | Increase it only when a particular protocol operation needs more time; a longer timeout also means a stalled operation can occupy a worker longer. |
slowMo |
Slows Puppeteer operations by the configured number of milliseconds. | Useful when observing or debugging interaction sequences. |
targetFilter |
A callback decides which browser targets Puppeteer connects to. | Use when the session has targets your automation should exclude. |
headers |
Deprecated. If both it and wsOptions.headers are supplied, wsOptions.headers takes precedence. |
In Node.js use wsOptions.headers. |
wsOptions |
WebSocket connection options; Node.js only. Keep-alive settings are ignored in browser builds. | Use for Node WebSocket settings, including connection headers. |
protocol |
CDP is the documented default for browser connections. Protocol support varies by browser and runtime. | Choose a protocol only when the target browser and Puppeteer workflow support it. |
capabilities |
Applies only with protocol: 'webDriverBiDi' and Puppeteer.connect(). |
Supply BiDi capabilities for a supported BiDi connection. |
acceptInsecureCerts |
Defaults to false; controls whether HTTPS certificate errors are ignored during navigation. |
Enable only in environments where accepting invalid certificates is intentional. |
handleDevToolsAsPage |
Defaults to false; controls whether DevTools windows are treated as Puppeteer pages. |
Enable only if automation needs to interact with DevTools windows. |
networkEnabled |
Experimental. Disabling network event monitoring can break features that depend on HTTPRequest and HTTPResponse events. |
Change only when you understand which network-dependent features your code uses. |
issuesEnabled |
Experimental setting for disabling issue-event monitoring by default. | Use only when issue events are not needed. |
allowlist |
Experimental, Chrome-only, and requires Chrome 149 or newer. Uses standard URLPattern matching. Cannot be combined with blocklist. |
Adds a request guardrail; it is not a complete network sandbox. |
blocklist |
Experimental and Chrome-only. Mutually exclusive with allowlist. |
Block matching URLs when this control fits the use case. |
channel |
Experimental; Node.js and Chrome only. Looks for an open WebSocket in the well-known user-data location for a Chrome release channel. | Use only for the documented Chrome channel workflow. |
transport |
Low-level custom ConnectionTransport option. |
Use for specialized connection implementations; it is not the usual endpoint-based connection path. |
4. Pass WebSocket headers in Node.js
For a browser service that requires headers during the WebSocket handshake, use wsOptions.headers. The old top-level headers option is deprecated.
const browser = await puppeteer.connect({
browserWSEndpoint: process.env.PUPPETEER_WS_ENDPOINT,
wsOptions: {
headers: {
Authorization: `Bearer ${process.env.BROWSER_TOKEN}`,
},
},
});
This setting is Node.js only. Do not put secrets in source control or log the full endpoint and headers. Keep-alive settings in wsOptions are ignored in browser builds because the browser WebSocket API lacks the ping-frame interface Puppeteer uses.
5. Connect or launch?
| Question | Choose connect() |
Choose launch() |
|---|---|---|
| Does the browser already exist? | Yes. Attach to that running instance. | No. Puppeteer should start the browser process. |
| What do you provide? | A WebSocket endpoint, debugging HTTP address, or specialized transport. | Launch configuration, such as launch-specific options. |
| What does the API return? | A promise resolving to a Browser. |
A promise resolving to a Browser Puppeteer launched. |
| How does this affect process ownership? | Disconnect Puppeteer with browser.disconnect(); the existing browser remains running. |
Close the browser with browser.close() when the launched process should stop. |
LaunchOptions extends the shared connection options and adds launch-specific settings. The key decision is ownership: connect when another component or service already manages the browser; launch when your application should start it.
6. cURL, Python, and Node.js screenshot examples
If your goal is a screenshot rather than browser session control, these examples show the same capture using ScreenshotNeo. See the ScreenshotNeo API documentation for the request options.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
with open("shot.webp", "wb") as f:
f.write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
Or skip the browser setup
For a screenshot, ScreenshotNeo provides a single GET request that returns an image or PDF. Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See ScreenshotNeo and the API docs. Sign up for 1,000 free screenshots a month, with no card.
7. Troubleshooting Puppeteer connections
| Symptom | Likely cause | Fix |
|---|---|---|
| Connection refused or timeout | The browser is stopped, the host or port is wrong, or the debugging address is not reachable from the Node process. | Check the browser process and provider endpoint, then verify network routing and any required tunnel. |
| Invalid WebSocket URL or handshake failure | A website URL or debugging HTTP address was passed as a WebSocket endpoint, the endpoint is stale, or handshake authentication is missing. | Use the complete webSocketDebuggerUrl with browserWSEndpoint, or use the documented HTTP debugging address as browserURL. Supply required Node headers through wsOptions.headers. |
HTTP 404 at /json/version |
The service does not expose Chrome’s debugging endpoint at that host and port, or the path is unavailable through its proxy. | Consult the browser provider’s connection instructions; do not guess a provider-specific path. |
| Connect succeeds but expected pages are absent | The browser has no page target, or targetFilter excludes it. |
Inspect browser.pages(), create a page with browser.newPage() if appropriate, and review the filter. |
| Commands time out after connection | An individual protocol call exceeded protocolTimeout, or the browser is stalled. |
Check browser health and the specific command. Raise the timeout only for operations that need it. |
| Top-level headers appear ignored | headers is deprecated or the code runs in a browser build. |
In Node.js, move handshake headers to wsOptions.headers; confirm the runtime supports that option. |
| BiDi capability setting has no effect | capabilities is only applicable with protocol: 'webDriverBiDi' and Puppeteer.connect(). |
Use the documented protocol combination and ensure the browser supports it. |
| Allowlist or blocklist configuration is rejected | The feature is experimental and Chrome-only; allowlist needs Chrome 149+, and the two controls cannot be combined. | Check browser version, select only one control, and use it as an additional guardrail rather than network isolation. |
8. Performance, reliability, and cost
- Connection latency:
connect()avoids launching a new browser process, but the time to connect depends on network distance, service load, and endpoint readiness. No fixed latency is guaranteed by the API. - Reuse deliberately: Reusing an existing browser can avoid repeated startup work. Isolate pages or browser contexts when jobs should not share state, cookies, or storage.
- Bound waiting: Set a practical
protocolTimeout, and add application-level timeouts and cleanup so a stalled browser does not hold a worker indefinitely. - Disconnect cleanly: Use
browser.disconnect()for a connected browser when the session is done. This leaves the browser process running. Handle connection loss and reconnect through the owning service’s supported lifecycle. - Protect the endpoint: A DevTools WebSocket endpoint is control access. Restrict network exposure, handle credentials as secrets, and avoid logging full authenticated URLs.
- Cost: Puppeteer itself is the automation library; browser hosting, compute, and network costs depend on where the existing browser runs. A screenshot API can replace browser infrastructure for capture-only jobs.
9. FAQ
What is Puppeteer’s default viewport?
ConnectOptions.defaultViewport defaults to 800 × 600. Set it to null to avoid applying that default to each page.
Where do I get browserWSEndpoint?
Use browser.wsEndpoint() from a Puppeteer browser, or read webSocketDebuggerUrl from the browser’s /json/version response.
Can I use connect() with Firefox?
The current reference documents CDP as the default for browser connections and WebDriver BiDi for Firefox launch. Check current browser and protocol support before selecting a Firefox connection workflow.
Is the Chrome allowlist a network sandbox?
No. The API reference describes it as an additional guardrail, not complete network isolation.


