A developer discovered that attaching a Chrome DevTools debugger through Playwright or Puppeteer throttles fetch-based uploads by more than 20 times, turning everyday performance benchmarks into misleading data.

The puzzle that sparked the investigation

Coffer, a browser-based file store that encrypts data before sending it to the server, routinely pushes gigabit-class uploads over a local network. When the team measured upload speeds, they saw a gap: downloads saturated the link, but uploads crawled at roughly one-eighth of the available bandwidth. The discrepancy prompted three rounds of code changes that failed to move the needle, until a fourth “fix” appeared to deliver a massive jump—only to vanish when the debugger was removed.

What the team tried first

The engineers chased the usual suspects:

  • Chunk size – Doubling the block from 16 MiB to 32 MiB left the throughput unchanged.
  • Pipelining – Overlapping encryption of the next block with the current upload yielded a modest 13 % gain, indistinguishable from measurement noise.
  • Concurrency – Running several uploads in parallel capped at the same total speed, suggesting a global ceiling.

None of these variations explained the 8× slowdown.

A surprising head-to-head comparison

To isolate the problem, the team swapped the client implementation. Using .NET HttpClient they recorded 700 Mbps on the same network; the same request issued from Chromium’s fetch() API stalled at 140 Mbps. The stark contrast pointed to the browser’s network stack as the culprit—until the next experiment proved otherwise.

The debugger’s hidden cost

Playwright and Puppeteer drive Chrome via the Chrome DevTools Protocol (CDP). That protocol attaches a debugger to the browser process, exposing network events, DOM snapshots, and console logs. The team ran a focused test: a fetch() call sending a Uint8Array payload, once with the CDP debugger attached and once without.

  • Debugger attached: 113 Mbps

The presence of the debugger reduced upload speed by more than 20 ×. A manual test in a regular Edge window—no debugger attached—reached 600 + Mbps, confirming that the browser itself can handle the traffic when unencumbered.

A modest, real improvement

While the debugger accounted for the bulk of the slowdown, the team still uncovered a genuine optimization: switching the request body from a Uint8Array to a Blob lifted Chromium’s speed by roughly 30 %. It’s a useful tweak, but nowhere near the “miracle” boost originally hoped for.

Why this matters to engineers

  • Instruments can lie. Performance tools that automate browsers are themselves part of the measurement chain.
  • Benchmarks that look impossible deserve a sanity check. If numbers diverge wildly from network capacity, the measurement environment should be the first suspect.
  • A null result is valuable. Confirming that a change does nothing prevents wasted effort chasing phantom bugs.
  • Manual controls are cheap insurance. Running the same operation in a plain browser window can reveal hidden instrumentation overhead.

Counter-point: when debuggers are indispensable

Debuggers provide visibility into page behavior, error traces, and network timelines that are otherwise inaccessible. For regression testing, security audits, or complex UI interactions, attaching a CDP debugger is often non-negotiable. The key is to separate functional testing from raw performance measurement, and to disable the debugger when the latter is the goal.

Takeaway: The tools that make automated testing possible can also become the biggest source of performance distortion. Before blaming the browser, the network, or the code, verify that no debugger is silently throttling the data stream.