Marketing parameters like utm_source, fbclid, and gclid will quietly murder your CDN cache hit ratio. If you leave your edge defaults untouched, every newsletter send or ad campaign creates thousands of unique URLs for the exact same page. Here is how to configure StackPath EdgeEngine rules to strip out tracking junk while keeping legitimate application queries intact.

The Cache Fragmentation Problem
By default, most CDNs treat /about, /about?utm_source=twitter, and /about?utm_source=newsletter as three completely separate cached objects. When an email campaign goes out, every recipient hits a slightly different tracking URL, and your origin server ends up rebuilding the exact same markup hundreds or thousands of times.
We saw this firsthand during an email blast on one of our production sites: edge hit ratios tanked from 91% straight down to 14% in twenty minutes. Origin CPU jumped to 98% because the CDN treated every single visit as an edge cache miss. You can check how your edge behaves right now with curl:
curl -svo /dev/null "https://example.com/assets/app.js?v=123&utm_campaign=launch" 2>&1 | grep -iE "(x-cache|x-hw|age)"If you see X-Cache: MISS on repeated requests when you tweak that dummy parameter, your CDN is partitioning cache storage per query string instead of returning the already-cached resource.
Default StackPath Cache Key Settings
StackPath gives you a global setting under Sites > [Your Site] > CDN > Caching. In the Query String dropdown, you get three default modes:
- Cache with query string: The out-of-the-box default. Every unique query string gets its own unique cache key at the edge.
- Ignore query string: Strips every parameter before checking the cache key. A request for
/style.css?v=2gets mapped directly to/style.css. - Do not cache: Skips edge caching entirely whenever a query string is present.
Flipping the global switch to “Ignore query string” seems like an easy fix, but it usually causes collateral damage. It breaks internal search (/?s=query), product filters, and pagination. You need surgical rules: strip marketing garbage on static files and general pages, but leave dynamic app parameters alone.
Step 1: Configure an Edge Rule to Ignore Marketing Parameters
Skip the global toggle and build targeted Edge Rules in the portal instead. This strips out analytics noise while keeping functional query strings working.
- Log in to your StackPath Control Portal and select your CDN site.
- Click EdgeRules in the sidebar.
- Click Add EdgeRule in the top right.
- Name it something clear, like
Ignore Marketing Query Strings.
Now set up the condition. Under If, match incoming query strings using standard regex patterns defined in the MDN Regular Expressions reference:
Field: Request URL Query
Operator: Matches (Regex)
Value: (utm_|fbclid|gclid|_ga|mc_eid)Under the Then block, choose your edge action. Depending on your EdgeEngine setup, pick Modify Request Header or Custom Cache Key. On modern StackPath configurations, select Cache Key and configure parameter exclusions directly.
Step 2: Isolate Static Assets with Targeted Edge Rules
Static files—images, fonts, stylesheets, and scripts—should almost never fragment across query strings unless you are doing intentional cache busting. If you have already had to fix CORS font errors behind StackPath CDN, you know how it is to scope edge rules to exact file extensions to avoid weird edge-case bugs.
Set up a second edge rule purely for static media and assets:
Rule Name: Static Assets - Strip All Query Strings
If Request URL Path Matches (Regex): .(css|js|jpg|jpeg|png|gif|svg|woff2|webp)$
Then Perform Action: Ignore Query StringNow if a social scraper appends ?fbclid=xyz to a hero image or a browser extension injects tracking tags on your JS files, StackPath serves the asset straight from edge cache without touching your origin.
Step 3: Preserve Cache Busting for Developers
If you strip every query string indiscriminately from static files, you will eventually burn yourself by serving stale assets after a release. Modern bundlers like Vite, Webpack, or Next.js handle this cleanly by hashing filenames (like main.a8b1c2.js).
If your stack still uses traditional query-based version strings like style.css?ver=2.4.1, tell StackPath to respect ver or v while tossing out everything else. You can drop a lightweight EdgeEngine script in place to clean up the cache key before the CDN checks storage:
addEventListener('fetch', event => { event.respondWith(handleRequest(event.request));
}); async function handleRequest(request) { const url = new URL(request.url); const cleanParams = new URLSearchParams(); // Whitelist functional parameters const allowedParams = ['ver', 'v', 'page', 's']; for (const [key, value] of url.searchParams.entries()) { if (allowedParams.includes(key)) { cleanParams.set(key, value); } } url.search = cleanParams.toString(); const modifiedRequest = new Request(url.toString(), request); return fetch(modifiedRequest);
}The script iterates over incoming parameters. If someone hits /app.js?ver=1.2.0&utm_source=slack&fbclid=998877, it normalizes the path to /app.js?ver=1.2.0 before evaluating the cache layer.
Testing Edge Cache Hits with cURL
Do not test caching behavior in your browser. Disk caches and service workers will lie to you about what the edge actually did.
Use curl in your terminal instead. Fire two identical requests with different dummy tracking params:
# First request: Seeds or updates the edge
curl -I "https://example.com/wp-content/themes/theme/style.css?utm_medium=cpc&rand=9482" # Second request: Should report an immediate HIT
curl -I "https://example.com/wp-content/themes/theme/style.css?utm_medium=cpc&rand=5512"Check the response headers StackPath sends back. You are looking for something like this:
HTTP/2 200
server: StackPath
x-cache: HIT
age: 42
content-type: text/css; charset=UTF-8
cache-control: public, max-age=31536000Look closely at x-cache: HIT and an age header greater than zero. Even though we changed the parameter from rand=9482 to rand=5512, the edge served the exact same cached object.
If you deploy via CI pipelines, take a look at our walkthrough on how to automatically purge StackPath CDN cache with GitHub Actions so you never push a frontend release and wonder why stale files are still lingering.
Gotcha: Authentication Tokens in Query Strings
Stripping query strings without checking routes will break webhooks, signed S3 URLs, and one-time password links. Payment gateways like Stripe and PayPal pass transaction IDs in redirects (think /checkout/success?session_id=cs_live_123).
If an overly aggressive rule strips query parameters from that success page, Customer B might see a cached page containing Customer A’s order confirmation details. Always pair edge rules with an authentication bypass. See our guide to bypass StackPath CDN cache for logged-in WordPress users to see how to check cookie headers before firing edge cache directives.
Add an exception directly inside your Edge Rule conditions:
Condition Group 1: Request Path Matches: /checkout/.*
Action: Bypass CacheRemember that StackPath processes rules in order from top to bottom. Always put your bypass rules and API exclusions above your broad query-string rules.
Origin Header Tuning for Cache Control
StackPath respects your origin server’s Cache-Control headers per the RFC 9111 HTTP Caching specification. If your origin sends Cache-Control: private, no-cache, StackPath refuses to cache the asset regardless of how you configure query parameters.
If you run Apache or LiteSpeed, make sure your directives follow our guide to fix serve static assets with an efficient cache policy. For Nginx origins, verify your location block sends explicit max-age headers:
location ~* .(css|js|jpg|jpeg|png|gif|ico|webp|woff2)$ { expires 365d; add_header Cache-Control "public, no-transform"; access_log off;
}With an explicit public, max-age header, StackPath stores the asset across its edge nodes without needing to hit your origin on every variation of incoming tracking parameters.
Frequently Asked Questions
Does ignoring query strings break Google Analytics or tracking pixels?
No. Analytics scripts run in the browser and grab query parameters directly via JavaScript (window.location.search). StackPath evaluates edge rules on its servers before serving the page, so the full URL in the visitor’s address bar stays untouched.
Can I ignore query strings for specific directories only?
Yes. Add a condition for Request URL Path Matches (like ^/wp-content/uploads/.*) and set the action to Ignore Query String. That leaves all dynamic app routes alone while stripping query noise from media directories.
What is the difference between stripping and ignoring query strings?
Ignoring means the CDN uses the base URL for the cache key, but on a cache miss, it may still forward the full query string to your origin. Stripping removes the parameters entirely before forwarding the request to your backend.
Why does my cache hit ratio still show misses after enabling the rule?
Edge caches are distributed across regions. A request hitting London will be a cache miss until that specific PoP gets warmed, even if New York already has it cached. Give it 24 to 48 hours for traffic to warm the edge fleet before judging your aggregate hit ratio.
Next Steps
Keep an eye on your hit ratio under the StackPath Analytics tab over the next couple of days. If you run into odd redirect loops while testing, check out our guide on how to fix WordPress ERR_TOO_MANY_REDIRECTS behind StackPath CDN to square away edge-to-origin SSL handshakes.

