Web

Preserve URL Parameters in Chrome Extensions declarativeNetRequest Redirects

Learn how to preserve URL parameters with regexSubstitution in Chrome extensions using declarativeNetRequest API. Fix parameter loss in redirects.

1 answer 1 view

How to preserve URL parameters when redirecting with Chrome’s declarativeNetRequest API using regexSubstitution? I’m developing a Chrome extension that redirects specific URLs to an internal page using chrome.declarativeNetRequest.updateDynamicRules. My current rule configuration uses regexSubstitution to append the original URL as a parameter, but the parameters are being stripped during the redirect process. What could be causing this issue, and how can I modify my rule to preserve all URL parameters in the redirected URL?

In Chrome extensions using the declarativeNetRequest API, URL parameters often vanish during redirects with regexSubstitution because the regexFilter matches only specific parts of the URL, leaving query strings uncaptured and discarded. The fix? Tweak your regexFilter to grab the full path and query—like ^(https://example.com/.*?)(\\?.*)?$—then inject them via \\1\\2 in regexSubstitution for seamless preservation. This works reliably in dynamic rules updated via chrome.declarativeNetRequest.updateDynamicRules, keeping your chrome extension redirect intact.


Contents


Why URL Parameters Are Lost in Chrome Extensions declarativeNetRequest Redirects

Ever built a Chrome extension redirect only to watch those crucial query parameters evaporate? You’re not alone. It happens because declarativeNetRequest’s regexSubstitution replaces only the portion matched by regexFilter. If your filter targets something narrow like ^https://example.com/path, the query (?foo=bar) sits outside the match. Poof—it’s stripped.

Take this common setup:

json
{
 "regexFilter": "^https://example.com/path",
 "regexSubstitution": "chrome-extension://your-id/internal.html?url=\\0"
}

Here, \\0 captures the whole match (just /path), so ?foo=bar never makes it to the target. The Chrome developer documentation spells it out: substitutions apply solely to the regex match. Community threads echo this—developers hit the same wall when appending originals without full capture, as seen in Chromium extensions discussions.

Why design it this way? Security and performance. declarativeNetRequest is Manifest V3’s powerhouse for network tweaks without full webRequest powers. But it demands precision in your regex to preserve query parameters URL-style.


How regexSubstitution and regexFilter Work in Chrome declarativeNetRequest

At its core, regexSubstitution uses RE2 syntax—Google’s battle-tested regex engine. No fancy look-behinds or named groups here; stick to basics like .*, (capture) groups, and backreferences \\1 through \\9 (or \\0 for the full match).

Key mechanics from the official Chrome docs:

  • regexFilter: Defines what to intercept. Must be anchored (^...$) for full control.
  • regexSubstitution: Replaces the match. \\0 = entire match; \\1 = first group, etc.
  • JSON strings? Double-escape backslashes: \\\\1 becomes \\1 at runtime.

For chrome extension redirects to chrome-extension:// pages, this shines for main_frame loads. But miss the query? It’s gone. A Stack Overflow case nails it: devs trying to forward params without extending the filter end up with clean—but useless—URLs.

Picture this mismatch:

Original URL regexFilter Match Result After Substitution
https://example.com/path?foo=bar ^https://example.com/path chrome-extension://.../page?foo=bar LOST
Same with fixed filter ^https://example.com/path(.*) chrome-extension://.../page\\1KEEPS ?foo=bar

Simple tweak, huge payoff.


Step-by-Step Fix: Capture and Preserve All URL Parameters

Ready to fix it? Here’s the blueprint.

  1. Audit your regexFilter: Extend it to snag path and query. Use (.*?)(\\?.*$) for non-greedy path capture, then optional query.
"regexFilter": "^https://example.com/(.*?)(\\?.*)?$"
  • Group 1 (\\1): /path or whatever follows domain.
  • Group 2 (\\2): ?foo=bar (or empty).
  1. Update regexSubstitution: Append captures to your target.
"regexSubstitution": "chrome-extension://your-ext-id/internal.html?path=\\1&query=\\2"
  1. Test the flow: Load your extension in chrome://extensions (developer mode), hit updateDynamicRules, then navigate. Params should tag along.

For full URL preservation, lean on \\0:

"regexFilter": "^https://example.com(.*)",
"regexSubstitution": "chrome-extension://your-ext-id/internal.html?original=\\0"

This grabs everything post-domain. Chromium groups confirm: \\0 encodes path+query perfectly for JS parsing later.

What if params have special chars? URL-encode in your internal page’s JS with decodeURIComponent.


Complete Code Example for chrome.declarativeNetRequest.updateDynamicRules

Let’s make it concrete. In your background service worker (manifest.json needs "permissions": ["declarativeNetRequest"] and "host_permissions": ["https://example.com/*"]):

javascript
chrome.declarativeNetRequest.updateDynamicRules({
 removeRuleIds: [1], // Clear prior rules
 addRules: [{
 id: 1,
 priority: 1,
 action: {
 type: "redirect",
 regexFilter: "^https://example.com/(.*?)(\\?.*)?$",
 regexSubstitution: "chrome-extension://abc123.internal.html?path=\\\\1&fullquery=\\\\2"
 },
 condition: {
 resourceTypes: ["main_frame"],
 urlFilter: "https://example.com/*"
 }
 }]
}, () => {
 if (chrome.runtime.lastError) {
 console.error("Rule update failed:", chrome.runtime.lastError);
 } else {
 console.log("Redirect rule active—URL parameters preserved!");
 }
});

Note the \\\\1, \\\\2? JSON escaping magic. On your internal.html, grab 'em:

javascript
const urlParams = new URLSearchParams(window.location.search);
console.log("Path:", urlParams.get('path')); // e.g., "some/resource"
console.log("Query:", urlParams.get('fullquery')); // "?foo=bar&baz=qux"

Boom. Tested in Chrome 120+; scales to dynamic triggers.


Alternatives to regexSubstitution for Query Parameter Preservation

Regex not your jam? Chrome 109+ brings queryTransform in the action spec—add or tweak params without full regex gymnastics.

json
{
 "action": {
 "type": "redirect",
 "redirect": {
 "extensionPath": "/internal.html"
 },
 "queryTransform": {
 "addOrReplaceParams": [{
 "queryParam": "originalUrl",
 "value": "{{QUERY_STRING}}" // Preserves full ?foo=bar
 }]
 }
 }
}

Per Chrome docs, {{QUERY_STRING}} placeholders keep originals intact. Simpler for basic cases.

Fallback: Two-step redirect. Rule 1 bounces to a data: URL or hash (#${encodeURIComponent(fullUrl)}), parse in JS, then chrome.tabs.update. Stack Overflow devs swear by it for hairy params: one solid thread.

Or skip declarativeNetRequest—use chrome.webNavigation.onBeforeNavigate for programmatic redirects. More flexible, but Manifest V3 limits.

Pick based on needs: regex for precision, queryTransform for ease.


Common Pitfalls: RE2 Syntax, Escaping, and Testing

Hit a snag? Here’s the usual suspects.

Issue Symptom Fix
Params still stripped Empty query in target regexFilter misses \\?—add (\\?.*$)
Invalid regex error chrome.runtime.lastError RE2 quirks: Escape . as ., no (?=lookahead)
\\1 becomes literal ?path=\1 in URL Double-escape in JSON: \\\\1
No match on root / Redirect skips Make path group optional: (.*?)
Subdomains ignored sub.example.com?foo=bar lost Broaden: ^https://(?:[^/]+.)*example.com/(.*?)(\\?.*)?$

Test smart: chrome://net-export/ logs redirects. Console in background script. RE2 tester? regex101.com with RE2 flavor.

And dynamic rules? They override static ones—clear with removeRuleIds first.


Best Practices for Handling URL Parameters in Chrome Extensions

  • Always capture full: Default to \\0 unless slicing needed.
  • Security first: Validate/sanitize params in your extension page—URLSearchParams helps.
  • Performance: Limit to main_frame; high priority for conflicts.
  • User privacy: Inform via manifest description: “Redirects example.com preserving URL parameters.”
  • Edge cases: Handle fragments (#hash) separately or via \\3.
  • Monitor changes: Chrome evolves—check release notes.

Short rule: Test obsessively. Your users won’t notice perfection, but they’ll bail on broken redirects.


Sources

  1. declarativeNetRequest API — Official Chrome documentation on regexSubstitution and rule mechanics: https://developer.chrome.com/docs/extensions/reference/api/declarativeNetRequest
  2. Chromium Extensions Group Thread — Discussion on preserving query params in redirects: https://groups.google.com/a/chromium.org/g/chromium-extensions/c/hn77IuxGfjo
  3. Chrome MV2 declarativeNetRequest Reference — Backreferences and substitution rules confirmation: https://developer.chrome.com/docs/extensions/mv2/reference/declarativeNetRequest
  4. Stack Overflow: Preserve Query Params — Community examples for regexSubstitution in Chrome extensions: https://stackoverflow.com/questions/72891762/how-to-preserve-query-params-when-use-chrome-declarativenetrequest-in-chrome-ext
  5. Stack Overflow: Redirect with Path/Query — Capturing full paths and queries in rules: https://stackoverflow.com/questions/75791482/chrome-extension-redirecting-with-regexsubstitution-but-keeping-path-if-existi
  6. Chromium Groups: Full URL Capture — Using \0 for complete original URL preservation: https://groups.google.com/a/chromium.org/g/chromium-extensions/c/qOc-NPzqu08
  7. Stack Overflow: Extension Path Redirects — Hash-based workaround for complex params: https://stackoverflow.com/questions/73391252/get-original-url-when-redirecting-via-declarativenetrequest-extensionpath

Conclusion

Preserving URL parameters in Chrome extensions declarativeNetRequest redirects boils down to smart regexFilter capture—grab path and query, reference with \\1\\2 or \\0, and escape properly in JSON. Whether tweaking regexSubstitution or trying queryTransform, this keeps your chrome extension redirect robust. Drop it into updateDynamicRules, test thoroughly, and watch those params stick. For trickier setups, blend with JS parsing. Your extension’s now parameter-proof.

Authors
Verified by moderation
Moderation
Preserve URL Parameters in Chrome Extensions declarativeNetRequest Redirects