Puppeteer WebDriver BiDi WebSocket Endpoint Regex Explained
Learn what Puppeteer’s WebDriver BiDi endpoint regex matches, why the launcher appends `/session`, and how to troubleshoot endpoint discovery.
WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEX matches a Puppeteer browser-process output line that begins with the exact text WebDriver BiDi listening on , then captures the remainder of the line if it starts with ws://. Puppeteer’s launcher takes capture group 1 and appends /session before opening its BiDi WebSocket connection. The regex extracts a base endpoint; it does not parse a URL or add the session path. The current source on Puppeteer’s main branch defines it as:
export const WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEX =
/^WebDriver BiDi listening on (ws:\/\/.*)$/;
This is an internal launch detail. If a release behaves differently, check the source for the installed Puppeteer and browser versions rather than assuming the current main implementation applies. Current @puppeteer/browsers launch source
1. What does WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEX match?
The expression is anchored at both ends. It expects one complete output line in this form:
WebDriver BiDi listening on ws://127.0.0.1:9222
It captures ws://127.0.0.1:9222 as group 1. The launcher later uses that value as the basis for the BiDi connection URL.
| Part | Meaning |
|---|---|
^ |
Start of the string or line being tested. |
WebDriver BiDi listening on |
Exact, case-sensitive literal prefix, including its trailing space. |
(...) |
Capture group 1, whose value the line-waiting helper returns. |
ws:\/\/ |
The regex-literal spelling for the required ws:// prefix. The backslashes escape slash delimiters. |
.* |
Zero or more remaining characters, greedily captured through the end. |
$ |
End of the string or line being tested. |
There are no flags. This pattern checks a specific log format and a prefix; it is not a general WebSocket URL validator. Because .* can match an empty string, the expression’s own constraint after the prefix is only ws://. It also accepts trailing characters as part of the capture. A wss:// endpoint does not match this expression because the required scheme is ws://. These are properties of this pattern, not a claim that every browser emits the same endpoint format.
2. Why is Puppeteer waiting for WebDriver BiDi listening on?
The browser launcher starts a process and needs to discover the WebSocket address that process announces. The @puppeteer/browsers process helper checks output lines against the supplied regex and resolves with match[1] when one matches. That makes the exact prefix and the first capture group part of the handoff between browser output and Puppeteer’s launcher. Process launch helper source
If the expected line never appears, the helper cannot obtain the endpoint through this path. That can happen when the browser exits early, the selected browser build does not emit the expected line, or the output format differs from the version Puppeteer expects. Inspect the actual process output and the matching source for the installed versions.
3. Why does Puppeteer append /session?
The regex captures the listener’s base WebSocket address from the process output. In Puppeteer’s BiDi launch flow, createBiDiBrowser appends /session to that captured address, then uses the resulting URL for the WebSocket transport and BiDi connection. The regex itself neither knows about nor appends this path. BrowserLauncher source
This matches the WebDriver BiDi connection flow described in the W3C specification: the WebSocket URI is constructed from listener details and a resource name; for a null session, that resource name is /session. W3C WebDriver BiDi specification
When debugging, distinguish the two values: the captured base endpoint and the final connection endpoint after the launcher adds the path. Do not append /session to a value before passing it into a code path that expects the base endpoint unless that API specifically documents a complete session URL.
4. Puppeteer BiDi versus CDP: browser defaults and API limits
Puppeteer documents WebDriver BiDi automation support for Chrome and Firefox. Firefox uses BiDi by default when launched. Chrome continues to use CDP by default because not all CDP features are supported over BiDi; Chrome can select BiDi explicitly with protocol: 'webDriverBiDi'. Some operations can raise UnsupportedOperation under BiDi. Puppeteer WebDriver BiDi support and support table
Examples of documented unsupported areas include CDP-specific APIs such as Page.createCDPSession(), along with selected emulation, coverage, tracing, accessibility, page, and network methods. Consult the support table for the Puppeteer version in use before changing protocols; support can evolve.
The public ConnectOptions reference documents browserWSEndpoint. It also describes BiDi capabilities being passed to session.new for protocol="webDriverBiDi" and Puppeteer.connect(). That connection option is distinct from the launcher’s process-output regex: do not assume every connect() call uses this expression.
5. Reproduce the regex behavior in JavaScript
This runnable Node.js example demonstrates the pattern and the captured base endpoint. It does not start a browser or perform a BiDi connection; it isolates the parsing behavior Puppeteer relies on.
const WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEX =
/^WebDriver BiDi listening on (ws:\/\/.*)$/;
const line = 'WebDriver BiDi listening on ws://127.0.0.1:9222';
const match = line.match(WEBDRIVER_BIDI_WEBSOCKET_ENDPOINT_REGEX);
if (!match) {
throw new Error('No WebDriver BiDi endpoint found in the process output line');
}
const baseEndpoint = match[1];
const connectionEndpoint = `${baseEndpoint}/session`;
console.log({ baseEndpoint, connectionEndpoint });
Expected output:
{
baseEndpoint: 'ws://127.0.0.1:9222',
connectionEndpoint: 'ws://127.0.0.1:9222/session'
}
The example follows the current source’s simple concatenation. It is not a recommended generic URL-joining function: if input already contains a path or trailing slash, concatenating a path can produce a different result. The expected log format and launcher flow determine the intended base value.
6. Troubleshoot endpoint discovery
| Symptom | Likely cause | What to check or change |
|---|---|---|
| The launcher waits and never connects. | No output line matches the expected prefix and ws:// scheme. |
Capture the browser process output. Check spelling, capitalization, spacing, scheme, and whether the process exited before announcing an endpoint. |
| A line looks right but does not match. | The prefix differs, there is leading text, or the actual string includes characters outside the line tested. | Test the exact line passed to the helper. The expression is anchored with ^, uses an exact literal prefix, and has no flags. |
| The capture contains unexpected trailing text. | .* greedily captures all remaining characters. |
Inspect the raw output line and the caller’s line-splitting behavior. Do not treat the capture as a validated URL. |
| The connection URL has a duplicated or malformed path. | /session may have been included before Puppeteer appended it, or a base endpoint may contain a trailing slash/path. |
Log the captured base endpoint separately from the final connection URL. Compare with the installed launcher source and expected browser output. |
| Chrome works with CDP but fails after selecting BiDi. | A needed Puppeteer operation may not be supported over BiDi. | Check the versioned support table for that operation, handle UnsupportedOperation, or use the protocol that supports the required API. |
| The source regex does not match the installed package’s behavior. | The reference source is current main, while the installed release may differ. |
Inspect the exact package version and corresponding source or release tag, plus the browser build’s output format. |
For a release-specific diagnosis, record the Puppeteer version, browser name and version, launch protocol, the relevant unmodified output line, and whether the failure occurs during launch or when connecting to an explicitly supplied endpoint. Avoid publishing local endpoint details if they reveal sensitive environment information.
7. Performance, reliability, and cost considerations
This regex is a small string match; in this flow, the practical reliability question is whether the process emits the expected line and whether Puppeteer and the browser agree on the output format and protocol. The source and dossier do not provide a benchmark for the regex or a cost figure for running BiDi, so there is no supported numerical comparison to make. Browser startup, page loading, and automation work are separate from this endpoint extraction step.
For stable automation, pin compatible Puppeteer and browser versions, select the protocol intentionally, and check the documented feature support for that version. If a failure appears after an upgrade, compare the installed source and emitted log line before changing the regex or constructing a different endpoint.
8. Screenshot a page without managing browser launch
If the goal is to capture a website rather than debug Puppeteer’s BiDi transport, ScreenshotNeo is an alternative to try first: it provides a screenshot API and MCP server, so a website capture does not require you to manage this browser launch flow. See ScreenshotNeo and its API documentation.
Or skip the browser setup
Make one GET request for a screenshot. Replace the example target with the page you need and use an API key from your account.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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 take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. See the API docs and sign up for 1,000 free screenshots a month, no card required.
9. FAQ
Does the regex accept wss://?
No. Its captured group must begin with the literal ws://.
Does this expression validate that the endpoint is reachable?
No. It only matches text in a process-output line. A match does not establish that a WebSocket server is accepting connections.
Is this regex used whenever Puppeteer connects to a browser?
Do not assume so. The cited expression is used in the launcher’s process-output discovery path; explicit connection options are documented separately.
Where should I verify behavior for my Puppeteer version?
Inspect that installed version’s launcher and browser helper source, then compare it with the output from the browser build you launch. The source links in this article point to mutable main.


