DeclarativeNetRequest and webRequest in Firefox

This article explains how Mozilla Firefox uniquely supports both the declarativeNetRequest (DNR) API and the dynamic webRequest blocking API within its Manifest V3 (MV3) implementation. It covers why Firefox maintains both APIs, how the browser's network pipeline processes them simultaneously, how conflicts between competing rules are resolved, and how developers can combine both APIs to build high-performance extensions.

The Dual-API Strategy in Manifest V3

When Manifest V3 was introduced, Google Chrome deprecated the blocking capabilities of the webRequest API in favor of the more restrictive, privacy-focused declarativeNetRequest API. Mozilla took a different path for Firefox.

To ensure cross-browser compatibility, Firefox implemented the DNR API so developers could easily port MV3 extensions built for Chrome. However, Firefox also retained full support for the blocking webRequest API (via the webRequestBlocking permission). This decision allows advanced privacy and content-blocking extensions to maintain full access to dynamic, programmatic request modification while still offering the performance benefits of DNR.

Architectural Integration and Execution

In Firefox, the declarativeNetRequest API does not operate as a completely separate network engine. Instead, it is built on top of the same underlying browser network interception architecture that powers webRequest.

Despite sharing this foundation, the two APIs execute differently in relation to the extension's lifecycle:

  • DeclarativeNetRequest: The extension registers structured JSON rulesets with the browser. The browser engine evaluates and enforces these rules natively. Because the browser handles the logic, the extension’s background script (or event page) remains dormant, saving system memory and CPU cycles.
  • webRequest: The extension registers JavaScript event listeners (such as onBeforeRequest or onBeforeSendHeaders). When a matching network request occurs, Firefox must wake up the extension's background page, pass the request details to the JavaScript environment, and wait for the extension to return a blocking response before the network request can proceed.

Precedence and Conflict Resolution

Because both APIs can be used simultaneously—either by different extensions installed in the same browser or within a single extension—Firefox follows strict precedence rules to resolve conflicts when both APIs attempt to act on the same network request:

  1. Blocking Always Wins: A block or cancel action is the highest-priority outcome. If a DNR rule dictates that a request should be blocked, and a webRequest listener attempts to allow or redirect it, the request is blocked. Conversely, if a webRequest listener returns { cancel: true }, the request is terminated regardless of any DNR rules.
  2. Isolation of Allow Rules: In the DNR API, allow and allowAllRequests rules are used to bypass other DNR blocking rules. However, these DNR allow rules only apply to the DNR engine. A DNR allow rule cannot override a block issued by a webRequest listener.
  3. Redirects and Upgrades: If neither API blocks the request, redirect actions are evaluated next. Scheme upgrades (such as upgrading HTTP to HTTPS via DNR) and URL redirects from both APIs are processed at the onBeforeRequest stage. If a conflict occurs between two different extensions, Firefox resolves it based on the extension installation order (more recently installed extensions generally take precedence).
  4. Header Modifications: Both APIs can modify HTTP request and response headers. DNR modifyHeaders actions and webRequest listeners (onBeforeSendHeaders and onHeadersReceived) are merged. If both APIs attempt to modify the exact same header in conflicting ways, the browser applies conflict resolution based on rule priority and extension load order.

Combining Both APIs in a Single Extension

Firefox allows a single Manifest V3 extension to declare both declarativeNetRequest and webRequestBlocking permissions in its manifest.json file. This hybrid approach allows developers to optimize their extensions for both performance and capability:

  • Baseline Filtering with DNR: Developers can offload tens of thousands of simple, static URL-blocking rules to the DNR API. The browser handles the bulk of standard ad and tracker blocking natively without waking up the extension's background script.
  • Advanced Filtering with webRequest: Developers can scope their webRequest listeners narrowly to specific URLs or resource types that require dynamic programmatic logic. This includes dynamically stripping tracking parameters using complex regular expressions, computing cryptographic tokens on the fly, or using Firefox's webRequest.filterResponseData API to directly inspect and modify the payload of an incoming HTTP response body—a capability that DNR cannot replicate.