How to Get the URL of a Puppeteer Connection
Get a Puppeteer browser’s WebSocket endpoint with browser.wsEndpoint(), then use it to reconnect. Includes the external Chrome and pipe transport cases.
Call browser.wsEndpoint() on a Puppeteer Browser instance to get its WebSocket endpoint. Save the returned string and pass it as browserWSEndpoint to puppeteer.connect() when you want to attach to the same running browser later. The endpoint is a browser automation connection address, not a normal page URL.
Get the endpoint from a browser Puppeteer launched
Browser.wsEndpoint() returns a string in this documented form: ws://HOST:PORT/devtools/browser/<id>. The host, port, and identifier depend on the running browser.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const browserWSEndpoint = browser.wsEndpoint();
console.log(browserWSEndpoint);
// Keep the browser process running while disconnected.
await browser.disconnect();
// Attach to that same browser later, while it is still running.
const browser2 = await puppeteer.connect({ browserWSEndpoint });
console.log(await browser2.version());
// Close the browser process when you are done with it.
await browser2.close();
This save, disconnect, and reconnect pattern is documented by Puppeteer. disconnect() detaches Puppeteer while leaving the browser running; close() closes the browser.
Reconnect without disconnecting first
You can also keep the original Puppeteer connection open and use its endpoint to create another connection, where your setup permits multiple clients:
const browser = await puppeteer.launch();
const endpoint = browser.wsEndpoint();
const attachedBrowser = await puppeteer.connect({
browserWSEndpoint: endpoint,
});
console.log(await attachedBrowser.pages());
await attachedBrowser.disconnect();
await browser.close();
Use browser.disconnect() on the attached connection if you only want to detach it. Close the browser through the connection that owns its lifecycle when finished.
Connect to a browser started outside Puppeteer
If Chrome was started independently with remote debugging enabled, request its version endpoint and read the webSocketDebuggerUrl field. For example, if the debugging host and port are reachable at localhost:9222:
const response = await fetch('http://localhost:9222/json/version');
if (!response.ok) {
throw new Error(`Version endpoint returned ${response.status}`);
}
const info = await response.json();
if (!info.webSocketDebuggerUrl) {
throw new Error('Response did not contain webSocketDebuggerUrl');
}
const browser = await puppeteer.connect({
browserWSEndpoint: info.webSocketDebuggerUrl,
});
console.log(await browser.pages());
await browser.disconnect();
The host and port must be reachable from the process running Puppeteer. A browser’s startup output may also show its debugging endpoint. The value returned by /json/version is passed to puppeteer.connect() in the same way as the value from browser.wsEndpoint().
cURL, Python, and Node.js endpoint discovery
When the externally managed browser exposes Chrome’s debugging HTTP endpoint, you can inspect its version response from the command line or Python. These examples retrieve the endpoint; use Puppeteer’s Node.js API to connect to it.
cURL
curl --fail --silent --show-error http://localhost:9222/json/version
Find webSocketDebuggerUrl in the returned JSON.
Python
import json
from urllib.request import urlopen
with urlopen('http://localhost:9222/json/version', timeout=10) as response:
info = json.load(response)
endpoint = info.get('webSocketDebuggerUrl')
if not endpoint:
raise RuntimeError('Response did not contain webSocketDebuggerUrl')
print(endpoint)
Node.js
const response = await fetch('http://localhost:9222/json/version');
if (!response.ok) {
throw new Error(`Version endpoint returned ${response.status}`);
}
const { webSocketDebuggerUrl } = await response.json();
if (!webSocketDebuggerUrl) {
throw new Error('Response did not contain webSocketDebuggerUrl');
}
console.log(webSocketDebuggerUrl);
Choose the right endpoint source
| Browser setup | How to get the endpoint | How to attach |
|---|---|---|
| Started with Puppeteer | browser.wsEndpoint() |
puppeteer.connect({ browserWSEndpoint }) |
| Started independently with Chrome remote debugging | Read webSocketDebuggerUrl from /json/version, or use endpoint shown at startup |
puppeteer.connect({ browserWSEndpoint }) |
| Started with pipe transport | No WebSocket URL is provided by the pipe connection | Continue using the pipe-connected Puppeteer instance |
Important details and edge cases
- It is a browser endpoint, not a page address. A page address usually begins with
http://orhttps://and identifies content to visit. The browser endpoint uses WebSocket, typicallyws://, and attaches automation to the browser. - The endpoint belongs to a running browser instance. Save it only for reconnecting while that browser remains available. After the browser exits, its old endpoint will not attach to a new process.
- Not every launch has a WebSocket endpoint. Puppeteer supports Chrome pipe transport with
pipe: true. A pipe is not a WebSocket URL, sobrowser.wsEndpoint()is not a substitute for a pipe connection. - Use the browser-level method for the browser URL. Puppeteer also documents
Connection.url(), but the browser-level endpoint and documented format are given byBrowser.wsEndpoint(). - Keep endpoint handling scoped to your environment. The endpoint lets a client attach to browser automation. Avoid treating it as a public page URL or publishing it unnecessarily.
Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
browserWSEndpoint is empty or not what you expected |
You are not reading it from the active browser instance, or the browser was launched with pipe transport. | Call wsEndpoint() on the Browser returned by launch(). Check whether launch options set pipe: true. |
Connection refused or request to /json/version fails |
The browser is not listening on that host and port, or the address is unreachable from the client. | Confirm the browser is running with remote debugging enabled and use its reachable host and debugging port. |
puppeteer.connect() cannot connect |
The endpoint may be stale, malformed, or unreachable from the connecting process. | Fetch a fresh endpoint from the running browser, preserve the full webSocketDebuggerUrl, and check network reachability. |
/json/version response has no webSocketDebuggerUrl |
The response is not the expected browser version endpoint, or the service returned a different response. | Check the URL, status code, and response body; query the browser’s debugging host and port. |
| The browser disappears after disconnecting | The code closed it, or its owning process exited. | Use disconnect() to detach while leaving it running. Use close() only when you intend to close it. |
Performance, reliability, and cost
Retrieving the endpoint with wsEndpoint() is a local browser API call. For an externally managed browser, /json/version adds an HTTP request before the WebSocket connection. Reuse the endpoint while the same browser process remains alive rather than repeatedly rediscovering it. For reliable reconnects, handle browser restarts by obtaining a fresh endpoint; the endpoint identifies the running browser instance, not a durable service location.
Puppeteer itself does not set a per-endpoint price in these API references. Your runtime and browser hosting determine the cost of keeping a browser process alive. This method is for browser automation and does not itself produce a screenshot image.
Or skip the browser setup
If your goal is simply a website screenshot, ScreenshotNeo returns an image or PDF from one API request, without launching or reconnecting a browser yourself. Its API accepts screenshot options such as full-page capture, selectors, device presets, custom CSS, and wait conditions; see the API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Cookie and consent banners, newsletter popups, and chat widgets are removed before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and the response headers identify the page verdict and billing status. An MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000 screenshots.
Sign up for 1,000 free screenshots a month, with no card.
FAQ
What is the exact Puppeteer method?
Use browser.wsEndpoint() on the browser instance.
Can I use the endpoint to open a website?
No. It attaches Puppeteer to the browser; navigate to a website through a page after connecting.
Can I get a WebSocket URL when using pipe: true?
The cited Puppeteer launch options describe pipe as a separate transport. They do not provide a WebSocket URL equivalent for that pipe connection.


