Skip to content

Performance bottleneck: WebDriver BiDi is significantly slower than CDP and Classic HTTP in Chrome #3974

@baflQA

Description

@baflQA

Hey everyone,

I have been running some benchmarks comparing JS evaluation speeds across different protocols in Chrome 142, and the results for the WebDriver BiDi implementation show a significant performance difference compared to other available methods.

In my tests, the WebDriver BiDi path appears to have higher latency than both the legacy Classic HTTP path and raw CDP commands executed over the same WebSocket connection.

I am providing the full Java benchmark code below to help reproduce and investigate these observations.

The Benchmarks (Avg ms/call over 5000 iterations):

Chrome (142):

CDP (Raw WebSocket): 0.1651 ms

WebDriver BiDi: 1.4739 ms

Classic (W3C HTTP): 1.3714 ms

Firefox:

WebDriver BiDi: 0.2154 ms

Classic (W3C HTTP): 0.6153 ms

Observations:

Protocol Comparison in Chrome: There is a notable gap between CDP and WebDriver BiDi performance in Chrome. Given that both are utilizing WebSockets, I was curious about why the BiDi implementation shows roughly 9x higher latency than CDP for simple JS evaluation.

Cross-Browser Comparison: In Firefox, the WebDriver BiDi implementation is very efficient (0.21ms), performing significantly faster than its Classic HTTP counterpart and approaching the speeds seen with CDP in Chrome.

Regression vs Classic: In the Chrome environment, the WebDriver BiDi protocol is currently performing slightly slower than the legacy HTTP-based ChromeDriver calls.

Why this matters:

For use cases involving high-frequency synchronization—such as checking framework stability (Angular/React) before interactions—this latency adds up over the course of a large test suite. It would be great to understand what contributes to this overhead in Chrome and if there are ways to bring BiDi performance closer to the results seen in other implementations.

We are curious to know if this is a known behavior or if there are specific configurations or upcoming changes that might optimize these execution times. There is an open thread in the Selenium's Slack channel if You would like to share some insights/ask some additional questions:
https://seleniumhq.slack.com/archives/C0ABCS03F/p1768152955499779

Benchmark code:

import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.script.ContextTarget;
import org.openqa.selenium.bidi.script.EvaluateParameters;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

import java.util.Optional;

public class JsEvaluationBenchmark {

    private static final int ITERATIONS = 5000;

    static void main(String[] args) {
        runBenchmark(new ChromeDriver(new ChromeOptions().enableBiDi()), "Chrome");
        runBenchmark(new FirefoxDriver(new FirefoxOptions().enableBiDi()), "Firefox");
    }

    private static void runBenchmark(WebDriver driver, String browserName) {
        System.out.println("\n=== Testing Browser: " + browserName + " ===");
        try {
            driver.get("about:blank");
            JavascriptExecutor setupExec = (JavascriptExecutor) driver;

            setupExec.executeScript(
                    "document.body.innerHTML = `" +
                            "<div style='font-family:Segoe UI, sans-serif; padding:20px; background:#f4f7f6;'>" +
                            "  <h2>" + browserName + " Protocol Benchmark</h2>" +
                            "  <div style='display:flex; gap:15px;'>" +
                            "    <div id='classic-box' style='flex:1; padding:15px; background:white; border-left:5px solid #e74c3c;'>Classic HTTP<div id='classic-counter' style='font-size:24px;'>0</div><div id='classic-res'>-</div></div>" +
                            "    <div id='bidi-box' style='flex:1; padding:15px; background:white; border-left:5px solid #2ecc71;'>WebDriver BiDi<div id='bidi-counter' style='font-size:24px;'>0</div><div id='bidi-res'>-</div></div>" +
                            "    <div id='cdp-box' style='flex:1; padding:15px; background:white; border-left:5px solid #3498db;'>CDP (Legacy WS)<div id='cdp-counter' style='font-size:24px;'>0</div><div id='cdp-res'>-</div></div>" +
                            "  </div>" +
                            "</div>`;"
            );

            String handle = driver.getWindowHandle();

            // 1. Classic Benchmark
            long startClassic = System.nanoTime();
            for (int i = 0; i < ITERATIONS; i++) {
                setupExec.executeScript("document.getElementById('classic-counter').innerText = 'Iter: " + (i + 1) + "';");
            }
            long endClassic = System.nanoTime();
            double classicAvg = printOnPage(setupExec, "classic", endClassic - startClassic);

            // 2. BiDi Benchmark
            long startBidi;
            try (Script bidiModule = new Script(driver)) {
                ContextTarget target = new ContextTarget(handle);
                startBidi = System.nanoTime();
                for (int i = 0; i < ITERATIONS; i++) {
                    bidiModule.evaluateFunction(new EvaluateParameters(target, "document.getElementById('bidi-counter').innerText = 'Iter: " + (i + 1) + "';", false));
                }
            }
            long endBidi = System.nanoTime();
            double bidiAvg = printOnPage(setupExec, "bidi", endBidi - startBidi);

            // 3. CDP Benchmark
            double cdpAvg = 0;
            if (driver instanceof HasDevTools hasDevTools) {
                DevTools devTools = hasDevTools.getDevTools();
                devTools.createSession();
                long startCdp = System.nanoTime();
                for (int i = 0; i < ITERATIONS; i++) {
                    devTools.send(org.openqa.selenium.devtools.v143.runtime.Runtime.evaluate("document.getElementById('cdp-counter').innerText = 'Iter: " + (i + 1) + "';",
                            Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(),
                            Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(),
                            Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(),
                            Optional.empty(), Optional.empty(), Optional.empty()));
                }
                long endCdp = System.nanoTime();
                cdpAvg = printOnPage(setupExec, "cdp", endCdp - startCdp);
            } else {
                setupExec.executeScript("document.getElementById('cdp-counter').innerText = 'Unsupported';");
            }

            System.out.printf("[%s] Classic: %.4f | BiDi: %.4f | CDP: %.4f ms/call%n",
                    browserName, classicAvg, bidiAvg, cdpAvg);
        } finally {
            try {
                Thread.sleep(3000);
            } catch (Exception ignored) {
            }
            driver.quit();
        }
    }

    private static double printOnPage(JavascriptExecutor executor, String prefix, long nanoTime) {
        double avg = (nanoTime / 1_000_000.0) / ITERATIONS;
        executor.executeScript("document.getElementById('" + prefix + "-res').innerText = 'Avg: " + String.format("%.4f", avg) + " ms/call';");
        return avg;
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions