A Chrome/Edge DevTools extension that intercepts network responses and replaces their content during debugging. It uses chrome.debugger and the Chrome DevTools Protocol (Fetch domain) to pause requests, then returns a mocked body or redirects to a different URL based on configured rules.
π Chrome Web Store: Network Overrides API (DevTools)
| Live API capture | Override editor |
|---|---|
![]() |
![]() |
| Reusable override rules | Save and apply feedback |
|---|---|
![]() |
![]() |
- Enable/disable overrides per active tab via a toggle switch.
- Per-rule enable/disable toggle: disable an individual rule without deleting it; it stays visible (dimmed) and is skipped by the background worker until re-enabled.
- HTTP method matching: scope a rule to
GET/POST/PUT/PATCH/DELETE, or leave it atAnyto match every method (default, pre-filled from the captured request when available). - Import/export rules as JSON: back up or share the current domain's rules as a downloadable file, and load them back in with a merge-or-replace choice.
- Rule Profiles & Presets: save and load named rule presets per domain to switch quickly between different testing scenarios.
- Duplicate Rules: 1-click clone any override rule directly in the rules list.
- Request Headers & Response Headers Overriding: inject or modify request headers (e.g.
Authorization: Bearer token) during the request stage or extra response headers during the response stage. - Response Image & Visual Preview: instant image preview (Base64 PNG/JPG, SVG) directly inside the editor modal.
- Dynamic Captured Resource Filters: toggle body capture for XHR, Fetch, Document, Script, or Stylesheet resources.
- Three pattern matching modes for override rules:
- URL substring match (e.g.
/api/users) - Wildcard
*glob (e.g.https://old.com/api/*/usersβ*captures matching segments) - Regex
/pattern/flags(e.g./api\/v1\/users\/\d+/i) *orallmatches every request.
- URL substring match (e.g.
- Three override types:
- Override body: Replace the response body with custom text or raw base64 content.
- Redirect URL: Redirect the request to a different URL (supports
*wildcard substitution from captured groups). - Fail request: Kill the request at the network layer with a chosen error reason β the page's
fetch/XHR rejects as if the network failed.
- Status, headers, delay, and fail mocking: a body rule can force the response status (100β599), add or overwrite response headers, and delay the response up to 120 s; a fail rule kills the request at the network layer (
Failed,TimedOut,ConnectionRefused,NameNotResolved,InternetDisconnected). - View captured APIs, grouped by resource type (XHR, Fetch, JS, CSS, Img, Doc, WS, etc.), with real-time updates from the background service worker.
- Search APIs by URL substring.
- One-click override creation: Click any API in the list to open the modal and create/edit an override rule.
- Auto-fill response body: When creating a new override, the current response body is automatically fetched from the background worker and pre-filled into the editor.
- JSON formatting: Auto-detect and format JSON bodies with a single button.
- Copy cURL: Copy any API request as a cURL command.
- Manual rule editor (DevTools panel only): Quickly add a rule without opening the modal.
- Persistent storage: All rules, profiles, and settings survive browser restarts via
chrome.storage.local.
src/
βββ background.ts # Service-worker bootstrap
βββ background/ # Debugger lifecycle, interception, encoding, capture, message routing
βββ ui.ts # Shared UI state and controller orchestration
βββ ui/ # Reusable modal, rules, headers, dialogs, notifications, profiles, import/export
βββ shared.ts # Shared OverrideRule, ApiEntry, and header types
βββ tab-state.ts # Per-tab state, session persistence, and worker rehydration
βββ panel.ts # DevTools panel initialization and HAR streaming
βββ popup.ts # Action popup initialization
βββ utils.ts # Pattern matching, wildcard, and origin helpers
styles.css # CSS entrypoint
styles/ # Base, feature, modal/rules, primitive, and guide styles
scripts/ # Smoke, Store screenshot, and packaging automation
store-assets/screenshots/ # Chrome Web Store-ready screenshots
dist/ # Compiled JavaScript (generated by TypeScript)
panel.html # DevTools panel shell
popup.html # Action popup shell
manifest.json # Manifest V3 configuration
-
Initialization:
devtools.tscreates a DevTools panel βpanel.tsfires up UI + listens tochrome.devtools.networkevents (HAR +onRequestFinished). Popup usespopup.tsinstead, without HAR or manual editor. -
Debugger attachment: When "Enable Overrides" is checked,
background.tscallschrome.debugger.attachon the active tab, then enablesNetworkandFetchdomains (both Request and Response stages). Detachment happens on disable, tab close, or debugger disconnect. -
Request interception (
Fetch.requestPaused):- Request stage: Checks override rules in precedence order. A rule with
failReasonkills the request viaFetch.failRequest(afterdelayMs, if set). Otherwise a rule withredirectUrlredirects viaFetch.continueRequestwith a modified URL β wildcards (*) in the redirect URL are substituted with captured groups from the pattern match. - Response stage: Checks override rules for a body replacement. If found,
Fetch.fulfillRequestsends the custom body (base64-encoded) with the original status and headers β unless the rule overrides them viastatusCode/responseHeaders(same-name headers overwritten case-insensitively) β plus thex-network-overrides: trueandx-network-overrides-patternmarkers, delayed bydelayMsif set. If no rule matches, XHR/Fetch response bodies are stored for later auto-fill viaFetch.getResponseBody.
- Request stage: Checks override rules in precedence order. A rule with
-
Recent API tracking:
Network.requestWillBeSentcaptures request metadata into an in-memory Map (per tabId), mirrored tochrome.storage.sessionunder keytabState_{tabId}(debounced). Capped at 500 URLs and 100 bodies. On worker startup, this state is rehydrated fromchrome.storage.sessionand the debugger is re-attached to tabs that were enabled; any legacyrecentApis_{tabId}/recentApiBodies_{tabId}keys left over from older versions inchrome.storage.localare removed automatically. -
UI state:
enabled, per-domain rules (overrides_{origin}), andapiSearchTermare persisted inchrome.storage.localand survive across DevTools sessions and browser restarts.
Rule and UI state is stored in chrome.storage.local (permanent); per-tab runtime state is stored in chrome.storage.session (cleared when the browser exits):
| Key | Type | Persistence |
|---|---|---|
enabled |
boolean |
Permanent β survives browser restart |
overrides_{origin} |
OverrideRule[] (rules for one domain, e.g. overrides_https://a.test) |
Permanent β survives browser restart |
apiSearchTerm |
string |
Permanent β survives browser restart |
tabState_{tabId} |
per-tab snapshot (enabled, origin, overrides, captured APIs/bodies) |
chrome.storage.session β cleared when the browser exits; rehydrated and re-attached on worker startup |
Important: Override rules are never lost. Recent API data is keyed by tabId, lives only for the current browser session, and is only visible when the same tab is active. Legacy keys from older extension versions are migrated automatically: a flat overrides list is moved to the current domain's overrides_{origin} key on UI load, and recentApis_{tabId} / recentApiBodies_{tabId} keys are removed from chrome.storage.local on worker startup.
Override rules are evaluated in order; the first matching rule for a URL is used.
| Pattern | Matches |
|---|---|
/api/users |
Any URL containing /api/users |
* or all |
Every request |
https://site.com/api/*/list |
URLs matching the glob; * captures zero or more characters |
/\/api\/v\d+\/users/ |
Regex match (literal / delimiters, no flags) |
/\/api\/user\/(\d+)/gi |
Regex with flags g and i |
In redirect URLs, * substitutes captured wildcards in order. For example:
- Pattern:
https://old.com/api/*/item/* - Redirect:
https://new.com/api/*/product/* - Request URL:
https://old.com/api/v2/item/5 - Redirected to:
https://new.com/api/v2/product/5
Optional fields on an override rule:
| Field | Type | Description |
|---|---|---|
statusCode |
optional integer 100β599 | Forces the mocked response status (body rules only). |
responseHeaders |
optional {name, value}[] |
Added to the mocked response; same-name headers are overwritten case-insensitively (body rules only). |
delayMs |
optional number 0β120000 | Delays the response/failure by N ms (body and fail rules). |
failReason |
optional enum | Makes the rule fail the request at the network layer instead of answering. |
Two entry points:
- Popup: Click the extension icon in the toolbar. Shows "Captured APIs", "Overridden", and "Rules" tabs.
- DevTools panel: Open DevTools (F12) β "Overrides" tab. Same UI plus a manual rule editor row at the top of the "Rules" tab.
Toggle Enable Overrides on. The extension attaches the debugger to the current tab.
Browse your application as normal. Requests appear in the Captured APIs tab, grouped by resource type (XHR, Fetch, JS, CSS, etc.). Use the search bar to filter by URL.
Click any API in the list to open the override modal. You can also add a rule manually (DevTools panel only) by filling in the pattern, body, and clicking "Add override".
In the modal, choose:
- Override body: Enter custom response body text. Use
Textmode for raw text orRaw base64for pre-encoded content. The Format JSON action appears when the body contains valid JSON. - Redirect to URL: Enter the target URL. Use
*to substitute wildcards captured from the pattern match. - Fail request: Pick a fail reason (
Failed,TimedOut,ConnectionRefused,NameNotResolved,InternetDisconnected) β the request fails at the network layer instead of receiving a response.
The advanced fields can override Request Headers and Response Headers in either KeyβValue or Raw mode, force a Status (100β599), and set a Delay in milliseconds. Body and fail rules can use delay; combine TimedOut with a long delay to simulate a real timeout.
Switch to the Rules tab to edit, copy, delete, or enable/disable saved rules. A disabled rule stays visible but dimmed and is skipped by the background worker. Use Export/Import to share the current domain's rules; import provides explicit Append rules and Replace rules choices when rules already exist. The Overridden tab shows captured APIs currently matched by a rule.
Each API entry has a "cURL" button that copies the request as a cURL command (method, headers, and post data included).
Requirements: Node.js 22+, Chrome or Edge.
npm install
npm run buildLoad the extension:
- Open
chrome://extensionsoredge://extensions - Enable Developer mode
- Click Load unpacked
- Select the project root (the folder containing
manifest.json)
The manifest.json points to files in dist/, so re-run npm run build after any TypeScript changes.
npm run build # Compile TypeScript β dist/
npm run lint # ESLint over src/
npm test # Build + run test suite
npm run coverage # Build + run tests with coverage report
npm run ci:test # CI pipeline (same as coverage)
npm run smoke # Real-browser smoke test (loads the unpacked extension into Chromium)
npm run store:screenshots # Create versioned Store screenshots, promo tiles, and description note
npm run package:store # Create a ZIP for Chrome Web Store / Edge Add-ons- Formatting: Prettier via lint-staged (pre-commit hook).
- Commit messages: Conventional Commits enforced by commitlint + Husky hooks.
- Commit types:
add,feat,fix,docs,style,refactor,perf,test,chore,ci,revert,build.
Tests live in tests/ and cover:
- Pattern matching logic (
helpers.test.mjs) - UI behavior with DOM mocks (
ui-behavior.test.mjs) - Background debugger event handling (
background-flow.test.mjs) - Per-tab state store: session mirror, caps, dispose, rehydrate (
tab-state.test.mjs) - Entrypoint bootstrapping (
entrypoints.test.mjs)
npm run smoke (scripts/smoke.mjs) additionally drives the real unpacked extension in Chromium via Playwright β attach status, interception, status override, network-layer fail, worker-restart recovery, cross-origin navigation, and attach failures. Run it before releases; it needs a display (headed browser) and downloads Chromium on first use.
npm run store:screenshots (scripts/capture-store-screenshots.mjs) loads the real extension with deterministic demo API data and recreates the four 1280x800 PNG files in store-assets/screenshots/. It also needs a headed Chromium session.
GitHub Actions (.github/workflows/ci.yml) installs dependencies, checks formatting with Prettier, lints commit messages with commitlint, runs tests with coverage, and uploads the coverage report as an artifact.
npm run package:storeProduces a ZIP in release/ containing only the runtime files (manifest.json, *.html, styles.css, dist/, icons/) plus privacy_policy.md. dist/ is cleaned and rebuilt first so stale compiled files never ship.
debuggerβ required to intercept and modify network requests via Chrome DevTools Protocol.storageβ required to persist override rules, settings, and recent API data.host_permissions: <all_urls>β required to attach the debugger to any tab.
- Overrides only apply to the tab currently attached to the debugger.
- Recent API data is capped at 500 URLs and 100 response bodies per tab.
- Recent API bodies are only stored for XHR and Fetch resource types by default. Configure
CAPTURED_BODY_TYPESinsrc/background.tsto add more types. - Recent API lists are keyed by
tabIdand reset when the tab is closed and reopened. - The extension is designed for developer debugging only, not for end-user production use.



