OpenWPM 2026 report

A report on the OpenWPM releases that went out in early 2026, and what is planned after them.

The state of OpenWPM

OpenWPM had been dormant since the v0.31.0 release in January 2025. That release tracked Firefox 134. By early 2026, Firefox had shipped a new major version roughly every four weeks, and OpenWPM was more than a dozen releases behind.

The main cost of that is practical. The gap does not close on its own, Firefox's internals keep shifting underneath it, and the longer the lag runs the more expensive catching up becomes. There is a representativeness cost too: a year-old browser is further from what people actually run. But it is a smaller cost than it might sound, since an OpenWPM crawl is already distinguishable from ordinary browsing in other ways. Keeping current is mostly about keeping the tool maintainable at all.

Getting unstuck

OpenWPM is a side project. It gets worked on in the evenings, after a day job, and for most of 2025 I simply did not have the energy left to move it forward, so it sat.

What broke the stall in February 2026 was a change in how I work on it, not a change in how much time I have. That shift deserves its own post, so I have written it up separately. For this report, the relevant part is just the result: I could start clearing the backlog again.

What shipped

The work since February splits into two parts: catching up, and clearing backlog.

Catching up

Three releases went out: v0.32.0 (Firefox 148), v0.33.0 (Firefox 149) and v0.34.0 (Firefox 150), closing the gap to current Firefox. Sustaining that pace meant fixing the maintenance process itself:

  • Dependency updates that pick the right versions. OpenWPM has an update script that repins its conda environment and refreshes its npm packages. Conda's own solver already produces a latest-compatible set, so that side is straightforward. npm is the hard part. Getting the latest mutually compatible set of dev dependencies there is awkward because of peer dependencies, and a plain npm update does not get there. The script now handles this, and it keeps the pre-commit linter versions in sync with the conda environment, so the formatter that runs in CI is the same one that runs locally.
  • Test distribution by runtime. CI used to split the test suite unevenly: one runner would finish in 15 minutes while another took 40. Switching to pytest-split, which balances the split using recorded test durations, evened that out and shortened the critical path.

Catching up also meant two changes to what the collected data means, which anyone running a pipeline on top of OpenWPM should know about. A cookie with no explicit SameSite attribute is now recorded as unspecified rather than no_restriction. The old value conflated "the site said nothing" with "the site opted out of the restriction." And a 404 response is no longer reported as a cache hit. Neither is a large change, but both alter what the recorded data means without changing how it looks, so they are stated here rather than left to a changelog.

Clearing backlog

Most of the substantive work landed in DNS instrumentation. It is the part of the WebExtension I understand best, so it is where I was most confident making changes. Three things changed:

  • We capture every hop of a redirect chain. DNS instrumentation moved from the onCompleted event to onHeadersReceived, which fires for every response in a redirect chain, so we now record each hop, not just the final destination.
  • We capture failed lookups. Using onErrorOccurred, a DNS resolution that fails is now recorded rather than silently dropped.
  • A nonexistent domain no longer aborts a crawl. A domain that simply does not exist (NXDOMAIN) is a normal fact of the web, not a crawler malfunction, so it no longer counts toward the consecutive-failure limit that ends a crawl. It still triggers a browser restart, which is appropriately cautious for a measurement tool, while DNS timeouts and SERVFAILs still count, since those can signal a real network problem.

All three had been waiting as open issues or draft PRs, the oldest a draft PR for the redirect-chain change that had been open since January 2023. What changed was not the ideas. It was finally having the bandwidth to demand tests, work through the design iterations, and keep chipping away.

What's next

Now that cutting an OpenWPM release no longer means a weekend of manual work, I expect to keep it in rough lockstep with Firefox: a new OpenWPM version shortly after each Firefox release.

The issue backlog is still long, but I think OpenWPM can be evolved confidently as long as three things hold: a clear vision for where it is going, guardrails enforced statically rather than by discipline, and enough tests that a regression is loud. An idealized OpenWPM would have:

  • Fewer timeouts. Where the browser can send an explicit signal, we should wait for that signal instead of guessing with a timeout.
  • Stronger static analysis across the whole codebase, so more classes of mistake fail at lint time instead of halfway through a crawl. TypeScript 6's stricter inference already flags around two hundred latent type issues in the extension; TypeScript is pinned to 5.x until those are worked through. That is the kind of problem stronger analysis is meant to surface.
  • Its broken features restored. The one I miss most is the CallstackInstrument, which used DevTools internals to attribute a network request to the JavaScript that triggered it. It broke when we could not keep up with churn in Firefox's internals, exactly the kind of capability worth rebuilding now that keeping up is realistic again.

Five years ago I wrote about OpenWPM's future and worried it would rot into another unmaintained project. For a while, that looked like where it was headed. It is not anymore.