HTTP Request Interception and Modification in MV3 Extensions

Technical Implementation of HTTP Request Interception in a Browser Extension

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1287
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1248
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    984
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    1034
  • image_website-sbh_0.webp
    Website development for SBH Partners
    1108
  • image_website-_0.webp
    Website development for Red Pear
    555

Technical Implementation of HTTP Request Interception in a Browser Extension

A client comes with a requirement: block telemetry scripts, add authorization headers to internal APIs, and redirect all media requests to a fast CDN. Without HTTP request interception, it's impossible. We've implemented dozens of such extensions and know all the pitfalls—from Manifest V3 limitations to cross-browser compatibility nuances.

Previously, developers actively used chrome.webRequest with the blocking flag, but with the transition to Manifest V3, this method lost flexibility. The modern standard is declarativeNetRequest, a declarative API that shifts rule processing to the browser level. It's faster, more secure, and doesn't load the main thread, but imposes strict limits: no more than 5,000 rules can be active simultaneously. Let's dive into how to design a rule system to overcome these limits while keeping full control over traffic.

How to Intercept Requests in MV3?

The foundation is a declarative approach: you describe rules in JSON, and the browser applies them. The extension doesn't spend CPU analyzing each request, so Core Web Vitals are not harmed.

Static Rules

Rules defined in the rules/static.json file apply constantly. Example configuration for blocking analytics, modifying headers, and redirecting:

[ { "id": 1, "priority": 1, "action": { "type": "block" }, "condition": { "urlFilter": "||analytics.example.com^", "resourceTypes": ["script", "xmlhttprequest", "image"] } }, { "id": 2, "priority": 2, "action": { "type": "modifyHeaders", "requestHeaders": [ { "header": "X-Custom-Token", "operation": "set", "value": "my-token" }, { "header": "Referer", "operation": "remove" } ] }, "condition": { "urlFilter": "https://api.internal.corp/*", "resourceTypes": ["xmlhttprequest"] } }, { "id": 3, "priority": 1, "action": { "type": "redirect", "redirect": { "regexSubstitution": "https://cdn.example.com\\1" } }, "condition": { "regexFilter": "^https://slow-cdn\\.com(.*)", "resourceTypes": ["image", "media", "font"] } } ] 

Limits: up to 30,000 static rules total, with no more than 5,000 active at once. The rest can be dynamically activated via the service worker.

Dynamic Rules

If you need to add rules on the fly—use the service worker. For example, blocking/unblocking a domain or injecting an authorization token:

// background/sw.js async function blockDomain(domain) { const existingRules = await chrome.declarativeNetRequest.getDynamicRules(); const maxId = existingRules.reduce((max, r) => Math.max(max, r.id), 0); await chrome.declarativeNetRequest.updateDynamicRules({ addRules: [{ id: maxId + 1, priority: 10, action: { type: 'block' }, condition: { urlFilter: `||${domain}^`, resourceTypes: [ 'main_frame', 'sub_frame', 'script', 'stylesheet', 'image', 'xmlhttprequest', 'other' ] } }], removeRuleIds: [] }); } 

How to Modify the Request Body via Content Script?

declarativeNetRequest does not allow modifying the body. For that, use a content script with world 'MAIN', intercepting fetch and XMLHttpRequest. Example injecting a field into a POST request body:

const originalFetch = window.fetch; window.fetch = async function(input, init = {}) { const url = typeof input === 'string' ? input : input.url; if (url.includes('api.target.com')) { init.headers = { ...init.headers, 'X-Injected-Header': 'value', }; if (init.body) { const body = JSON.parse(init.body); body.extraField = 'injected'; init.body = JSON.stringify(body); } } return originalFetch.call(this, input, init); }; 

Note: monkey-patching does not work for requests from web workers and WebSocket. For full traffic control (enterprise proxies), Chrome's enterprise policy still allows MV2, but the public Chrome Web Store does not accept it.

Why is declarativeNetRequest Faster Than webRequest?

The main difference is native rule processing by the browser without JavaScript involvement. WebRequest requires synchronous handling of each request in the extension, which delays the response and worsens TTFB. declarativeNetRequest processes rules at the network stack level, reducing LCP by 10–20% in typical cases.

Characteristic webRequest (MV2) declarativeNetRequest (MV3)
Body modification Yes (via blocking) No
Performance Lower (JS processing) Higher (native browser)
Security Lower (potential XSS) Higher (isolated rules)
Dynamic rules Via listener updateDynamicRules
Redirects with substitution Yes Yes (regexSubstitution)

Additional Table: When to Use Static vs Dynamic Rules

Rule Type When to Use Example
Static Fixed scenarios not requiring frequent changes Block known trackers, modify headers for enterprise services
Dynamic Configuration changes: enable/disable on user request, temporary tokens Switch between staging and production, add authorization with limited lifespan

What Are the Limitations of declarativeNetRequest?

Besides the rule count limit (5,000 enabled), remember: dynamic rules can only be added from the service worker, not from the popup or content script. Also, all rules must be declared in advance—you cannot generate a rule based on arbitrary JS computation. For debugging, use chrome.declarativeNetRequest.getMatchedRules() and testMatchOutcome(). These methods help verify which rule will fire for a specific URL and identify conflicts.

What Our Implementation Includes

  • Architecture: designing a rule system (static + dynamic) respecting MV3 limits.
  • Content scripts: monkey-patching for request body modification when needed.
  • Debugging: testing rules via testMatchOutcome, logging firings.
  • Documentation: full description of all rules, redirection scheme.
  • Support: post-launch maintenance, updates when APIs change.

Our Work Process

  1. Analytics — study your application's request structure, identify interception targets.
  2. Design — create a rule specification, align with you.
  3. Implementation — write extension code, including service worker and content scripts.
  4. Testing — validate on real scenarios, catch edge cases.
  5. Deployment — publish to Chrome Web Store (or enterprise registry).

Timeline and Guarantees

Development timeline: from 5 to 15 working days depending on complexity. We guarantee stable operation and compliance with Chrome Web Store policies. Experience: over 50 browser extension projects.

For detailed information, refer to the official declarativeNetRequest documentation. Get a consultation for your project—contact us to discuss.