What Is WebDriver BiDi? How It Works with Puppeteer
WebDriver BiDi adds WebSocket-based, two-way communication to browser automation. Learn how Puppeteer uses it with Firefox and Chrome, where it differs from CDP, and how to check API support.
WebDriver BiDi is a browser automation protocol that lets an automation client send commands to a browser and receive browser events over a WebSocket connection. Puppeteer uses BiDi by default with Firefox. With Chrome, Puppeteer uses the Chrome DevTools Protocol (CDP) by default; choose BiDi explicitly when you want to use that protocol. Many common Puppeteer tasks work over BiDi, but its API coverage is not identical to CDP.
This guide explains the protocol, shows how to launch Firefox and Chrome with Puppeteer, and gives you a practical checklist for deciding whether BiDi fits an existing automation workflow. The protocol and library support evolve, so verify the compatibility guide for the Puppeteer version and browser you deploy.
1. What WebDriver BiDi is
Classic WebDriver follows a command-and-response pattern: the client sends a command and waits for its result. WebDriver BiDi extends browser automation with bidirectional communication over WebSockets. The client can issue protocol commands, while the browser can independently send events as activity occurs.
That event stream is useful for observing activity such as network requests, console output, and JavaScript errors without repeatedly polling the browser for changes. The W3C specification organizes capabilities into modules for areas such as sessions and browsing contexts, scripts, network activity, DOM interaction, and emulation. See the [W3C WebDriver BiDi specification](https://www.w3.org/TR/webdriver-bidi/) and [MDN’s WebDriver BiDi reference](https://developer.mozilla.org/en-US/docs/Web/WebDriver/Reference/BiDi).
BiDi and CDP at a glance
| Question | WebDriver BiDi | CDP |
|---|---|---|
| How does communication work? | Bidirectional WebSocket connection; browser events can arrive independently of client commands. | Chrome DevTools Protocol, used by Puppeteer’s default Chrome path. |
| What is Puppeteer’s default? | Firefox uses BiDi by default. Chrome can use BiDi when selected explicitly. | Chrome uses CDP by default. |
| What should I check before switching? | Whether the specific Puppeteer methods and options in your workflow are supported on its BiDi path. | Whether your workflow depends on CDP-specific capabilities or extensions. |
| Is support identical? | No. BiDi API coverage and the available options can differ. | No direct one-to-one equivalence is implied between protocol APIs. |
BiDi is a cross-browser standardization effort, while CDP provides Chrome-specific functionality. That distinction does not guarantee that every browser implements every BiDi feature or that every Puppeteer method accepts the same options across protocols. The cited [W3C document](https://www.w3.org/TR/webdriver-bidi/) is a Working Draft dated September 16, 2026; the [W3C repository](https://github.com/w3c/webdriver-bidi) describes the work as a living standard.
2. Does Puppeteer support WebDriver BiDi?
Yes. Puppeteer supports BiDi with Firefox and Chrome. Firefox automation uses BiDi by default. Chrome automation uses CDP by default, and you can request BiDi using protocol: 'webDriverBiDi'. Puppeteer’s FAQ says support for Chrome and Firefox has been available since Puppeteer v23.0.0 and describes BiDi support as production-ready; this does not mean every API is supported over BiDi. Read the [Puppeteer BiDi guide](https://github.com/puppeteer/puppeteer/blob/main/docs/webdriver-bidi.md) and [FAQ](https://pptr.dev/faq) for current details.
3. Enable BiDi in Puppeteer
Use a Puppeteer version that supports BiDi, then choose the browser and protocol deliberately. The following examples use JavaScript with ES modules.
Install Puppeteer
npm install puppeteer
This installs Puppeteer and its managed browser setup. If your environment supplies browsers separately, follow the Puppeteer installation documentation for that setup and verify the browser version and launch requirements.
Run the same basic page capture in Firefox and Chrome
import puppeteer from 'puppeteer';
async function capture(browserOptions, filename) {
const browser = await puppeteer.launch(browserOptions);
try {
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.screenshot({ path: filename, fullPage: true });
} finally {
await browser.close();
}
}
// Firefox uses WebDriver BiDi by default in Puppeteer.
await capture({ browser: 'firefox' }, 'firefox.png');
// Chrome uses CDP by default. Select BiDi explicitly.
await capture(
{ browser: 'chrome', protocol: 'webDriverBiDi' },
'chrome-bidi.png'
);
Save this as capture.mjs and run node capture.mjs. The finally block closes the browser even if navigation or capture fails. For a quick compatibility check, run one representative task from your actual test suite under each intended browser and protocol.
Choose the protocol explicitly in reusable code
If a script can run in multiple browsers, make the choice visible in configuration rather than relying on defaults that readers may not know:
import puppeteer from 'puppeteer';
const browserName = process.env.BROWSER ?? 'firefox';
const useBidi = process.env.PROTOCOL === 'bidi';
const options = { browser: browserName };
if (browserName === 'chrome' && useBidi) {
options.protocol = 'webDriverBiDi';
}
const browser = await puppeteer.launch(options);
try {
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
console.log(await page.title());
} finally {
await browser.close();
}
For Firefox, Puppeteer’s documented default is BiDi. For Chrome, omit protocol to retain CDP, or set it to 'webDriverBiDi' to select BiDi. Avoid setting the Chrome protocol based on an assumption that it is already BiDi.
4. What works over Puppeteer BiDi—and what to verify
Puppeteer’s BiDi path supports many ordinary automation tasks, including navigation, selectors and locators, script evaluation, common input, dialogs, screenshots, PDF generation, permissions, and request interception. However, some methods support fewer options over BiDi than over CDP, and some APIs are unavailable.
The Puppeteer BiDi guide lists unsupported areas including several emulation APIs, CDP-specific sessions and extensions, accessibility, coverage, tracing, some response-reading methods, some drag-and-drop methods, network-condition emulation, and screencasting. Treat that list as version-sensitive and consult the live [compatibility guide](https://github.com/puppeteer/puppeteer/blob/main/docs/webdriver-bidi.md) before adopting BiDi or upgrading Puppeteer.
Migration checklist
- Record the exact Puppeteer version, browser, and protocol used in your current runs.
- List every Puppeteer method and important option your workflow calls, including helpers used by test frameworks.
- Compare those calls with the current BiDi supported and unsupported lists.
- Run representative flows in the target browser using BiDi, checking navigation, screenshots, request handling, and cleanup.
- Keep a CDP path where the workflow depends on CDP-only APIs or options that BiDi does not provide.
- Recheck compatibility when changing Puppeteer versions or browser versions.
5. When to use BiDi or CDP
Choose based on required browser coverage and the APIs your project needs, rather than protocol labels alone.
- Consider BiDi when its standards-based, bidirectional event model fits your workflow and the required browser and Puppeteer APIs are supported.
- Keep CDP when your Chrome automation relies on CDP-specific sessions, extensions, or capabilities absent from Puppeteer’s BiDi path.
- For Firefox in Puppeteer, account for BiDi being the default and validate the methods and options your tests use.
- For Chrome in Puppeteer, decide explicitly whether to retain the default CDP protocol or request BiDi.
BiDi’s event stream is a useful fit for observing browser activity as it happens. It is not, by itself, a reason to migrate a workflow whose required functionality is only available through another path. Browser implementation and library support can vary, so check the current documentation for your exact combination.
6. Events, reliability, and performance considerations
BiDi lets a client subscribe to browser events instead of repeatedly polling for changing state. This can make event-driven automation code a better match for network, console, or JavaScript-error monitoring. It does not guarantee that a particular test will run faster: overall performance depends on the browser, page, workload, and automation code.
- Prefer event-driven observation when the protocol and Puppeteer API expose the event you need; avoid redundant polling when an event can provide the signal.
- Set explicit navigation and operation timeouts in your application where supported, and handle timeouts as expected failures rather than assuming the page is ready.
- Close pages and browsers reliably with
try/finallyso failed assertions or navigation do not leave browser processes behind. - Keep browser and Puppeteer versions controlled in CI, and record them when investigating a protocol-specific failure.
- Test the failure path for disconnects, failed navigation, and unsupported methods; a successful launch alone does not establish that a full workflow is compatible.
The research sources do not provide a benchmark comparing BiDi and CDP latency, resource use, or cost. Do not assume one protocol is faster or cheaper for your workload without measuring it in your own environment.
7. Troubleshooting Puppeteer BiDi
| Symptom | Likely cause | What to do |
|---|---|---|
| Chrome launches, but the script is still using CDP. | CDP is Puppeteer’s Chrome default. | Set protocol: 'webDriverBiDi' in the Chrome launch options. |
| A method or option throws, is missing, or behaves differently after switching protocols. | The method, option, or behavior may not be supported on Puppeteer’s BiDi path. | Check the current BiDi guide’s supported and unsupported lists. Retain CDP for a workflow that needs an unavailable CDP capability. |
| Firefox launch fails in a new environment. | The required browser may not be installed or available to the environment. | Follow Puppeteer’s current installation instructions for managed or separately installed browsers; confirm the selected browser is available to the process. |
| Navigation times out or the page appears incomplete. | The selected readiness condition may not match the page, or the page may be slow or unable to load. | Choose a navigation wait condition appropriate to the task, set a suitable timeout, and inspect the page and browser errors. Do not treat a timeout as proof that BiDi itself is at fault. |
| An event handler appears to miss activity. | The event may not be enabled, exposed by the API path, or observed at the right point in the flow. | Check the protocol and Puppeteer documentation for the event and subscription behavior, then register observation before triggering the activity. |
| CI works on one machine but not another. | Browser, Puppeteer, operating system, or launch environment may differ. | Pin and log relevant versions, compare launch configuration, and reproduce with the same browser and protocol in both environments. |
| Browser processes remain after failures. | Cleanup did not run after an exception. | Place browser closure in a finally block and ensure the code awaits it. |
8. Capture a screenshot without managing Puppeteer
If your task is simply to get a rendered page image rather than run browser automation, [ScreenshotNeo](https://screenshotneo.com) offers a website screenshot API and MCP server. Its API returns a PNG, JPEG, WebP, or PDF from a GET request; see the [API documentation](https://screenshotneo.com/docs/) for the available parameters.
Or skip the browser setup
This one-call example saves a screenshot of the target page. Replace the URL and use your API key:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
ScreenshotNeo accepts cookie and consent banners like a visitor and removes 60+ known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and whether the request was billed. Its MCP server gives AI agents tools for screenshots, page information, and PDF capture. The free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 screenshots.
Create a free account and get 1,000 screenshots a month with no card.
9. Cost and operational notes
WebDriver BiDi is a protocol choice; the dossier does not establish a protocol-specific Puppeteer price. For self-managed Puppeteer automation, account for the browser environment and the engineering work of installing, running, and maintaining it. Measure runtime and resource use for your actual workload rather than inferring them from the protocol.
For a screenshot API option, ScreenshotNeo’s listed plans are Free: 1,000 shots per month with no card; Starter: $5 for 3,000; Growth: $15 for 15,000; Pro: $39 for 60,000; Scale: $99 for 250,000; and Business: $249 for 1,000,000. Yearly billing gives two months free, and every feature is available on every plan. These are product plan details, not a benchmark against running Puppeteer.
10. Frequently asked questions
Is WebDriver BiDi the same as WebDriver?
BiDi extends the WebDriver automation model with bidirectional WebSocket communication and browser-originated events. It is a protocol development described by the W3C specification.
Does Puppeteer use BiDi for every browser?
No. Puppeteer uses BiDi by default for Firefox. Chrome defaults to CDP, and you must select BiDi explicitly if that is the Chrome protocol you want.
Can I switch an existing Puppeteer project to BiDi by changing one launch option?
The launch option selects the protocol for Chrome, but compatibility depends on every API and option your workflow uses. Check the current Puppeteer guide and exercise representative flows before switching.
Does BiDi guarantee cross-browser-identical behavior?
No. A shared protocol does not ensure identical browser implementation or identical Puppeteer API coverage. Validate the target browser and library versions.
Where should I check for changes?
Use the [Puppeteer BiDi guide](https://github.com/puppeteer/puppeteer/blob/main/docs/webdriver-bidi.md), [Puppeteer FAQ](https://pptr.dev/faq), and [W3C WebDriver BiDi specification](https://www.w3.org/TR/webdriver-bidi/). The specification and implementation support evolve.


