deniz.in

Markets

Weather

Loading weather

· via dev.to (home feed)

Chrome's ModHeader breakage leaves Selenium header tests on CDP and MV3 extensions

ModHeader's store removal, Chrome's Manifest V2 shutdown and the --load-extension change broke a popular Selenium pattern; CDP calls, Playwright options and MV3 extensions now cover the gap.

Chrome's ModHeader breakage leaves Selenium header tests on CDP and MV3 extensions

What broke

A long-standing approach to setting HTTP headers in browser tests — loading the ModHeader extension via Selenium — stopped working this year, and according to a write-up on dev.to the failure comes from three separate changes landing together, not one.

ModHeader was pulled from the browser stores in July, closing the normal installation path. The copy bundled in the chrome-modheader package on npm, and its modheader_selenium counterparts for Python and Java, is version 4.3.2, a Manifest V2 build; Chrome has turned off MV2 extensions, so it never activates, and the package has not been updated. On top of that, Chrome 137 and newer ignore the --load-extension flag in the regular browser, which is the mechanism ChromeDriver uses to install anything passed through addExtensions. Chrome for Testing and plain Chromium still accept the flag.

A silent failure in CI

The dev.to post estimates the npm package still receives around 150,000 downloads a month, mostly from CI. Those pipelines are installing an extension that does nothing, so tests that depend on it send no headers at all. The failure mode is quiet rather than a hard error, which is part of why the breakage has spread so widely before being noticed.

Setting request headers without an extension

For the most common need — attaching the same request headers everywhere, such as routing tests to a staging environment or authenticating a test user — the post argues no extension is required.

Playwright has this built in: a browser context can be created with an extraHTTPHeaders option. Selenium 4 driving Chrome can use the DevTools protocol instead, enabling the Network domain and calling Network.setExtraHTTPHeaders to reach the same result.

Both approaches add headers to every request from that context or tab. The post also lists their limits: they cannot alter response headers, cannot stop the browser from sending a header, and cannot restrict headers to particular URLs. Playwright's request interception can handle per-URL cases, at the cost of managing each request inside the test itself.

Where an extension still earns its place

Response-header work such as CORS or CSP, stripping headers like Referer or Cookie, and rules scoped to a single API host still need an extension — or a proxy such as mitmproxy. A proxy brings certificate management, which cloud grids frequently do not permit.

Here the author discloses a direct interest: they maintain Headerwise, an open source, MIT-licensed MV3 header extension with a dedicated automation build. It ships with a fixed extension ID and is configured by opening a URL that encodes the desired headers, then waiting for a readiness signal. Because regular Chrome rejects --load-extension, Selenium users must run Chrome for Testing, which Selenium Manager downloads when a browser version is requested; grids expose that build under separate names, with BrowserStack calling it chromefortesting.

The automation build also responds to ModHeader's own webdriver.modheader.com add, clear and load URLs — the author says the browser redirects those addresses to the extension locally, so nothing actually reaches modheader.com — and sets the page title to Done, matching ModHeader's old behaviour. Migrating an existing ModHeader suite can therefore be as small as swapping which extension file the test loads.

Why it matters

Header injection underpins many test suites that log in as synthetic users or point traffic at internal environments, and the download figures suggest a substantial amount of latent breakage is still running in CI. The episode is also a reminder that Chrome's platform cleanup — first the Manifest V2 sunset, then the --load-extension restriction — keeps quietly removing techniques automation teams relied on. The durable lesson from the post is to prefer first-class APIs such as Playwright's context options or Selenium's CDP bridge where they suffice, and to treat extension side-loading as a fallback rather than the default. One caveat for readers: the specific extension recommended in the post is the author's own project, so that recommendation warrants independent evaluation before adoption.

  • #selenium
  • #chrome
  • #browser-automation
  • #testing
  • #playwright