How to Normalize Cache Keys to Raise CDN Hit Rate

This guide belongs to CDN Edge Caching Configuration in Advanced Caching Strategies & CDN Architecture. A CDN stores and looks up responses by a cache key — by default, usually the full URL including the query string, plus the host and sometimes selected headers. Two requests that should receive the same response but differ in any part of the key are cached separately. Each copy must be fetched from the origin at least once per location, and copies that are requested rarely expire before they are reused.

The usual culprits are mundane: ?utm_source=newsletter on a campaign link, ?fbclid=… appended by social platforms, parameters in a different order, mixed-case paths, trailing slashes, and Vary headers on values that do not change the content. On marketing-heavy sites, a large fraction of HTML requests carry at least one tracking parameter, so every campaign spreads one page across thousands of cache entries — and every one of those visitors pays origin TTFB.

Normalising a request into a cache key Steps that turn a raw request URL into a normalised cache key by removing tracking parameters, sorting, lowercasing and dropping irrelevant headers. Normalising a request into a cache key Raw URL params + utm_ Drop tracking utm_, gclid, fbclid Sort params ?a=1&b=2 Normalise path case + trailing slash Cache key one entry per page

Rapid Diagnosis

  • Sample CDN logs for one popular page. Count distinct cache keys (full URLs) for the same path. Dozens or hundreds of variants indicate fragmentation.
  • Group query parameters by name across HTML requests. Tracking parameters (utm_*, gclid, fbclid, msclkid, mc_eid) are typically the largest group.
  • Check hit ratio by "has query string". A large gap between URLs with and without query strings is a strong signal.
  • Inspect Vary on HTML and API responses. Vary: User-Agent, Vary: Cookie or Vary: Accept-Language multiply entries.

Root Cause Analysis

1. Tracking parameters. Added by marketing tools and ad platforms, they never change the response but always change the key.

2. Parameter order and casing. ?color=red&size=m and ?size=m&color=red are different keys unless sorted.

3. Path inconsistencies. /Shoes vs /shoes, /shoes vs /shoes/, and duplicate slashes.

4. Overly broad Vary. Headers with many distinct values, especially user agent and cookie, create per-browser or per-user entries.

Cache entries per landing page during a campaign Bar chart of distinct cache keys observed for one landing page under default keys and after each normalisation step. Cache entries per landing page during a campaign Default (full URL) 1840 Tracking params removed 12 + params sorted 7 + path normalised 3

Step-by-Step Resolution

1. Strip tracking parameters from the key (not the URL)

Remove marketing parameters from the cache key while leaving them in the request the origin or analytics sees, so attribution keeps working.

javascript
// Cloudflare Worker: normalised cache key, original URL untouched.
const TRACKING = /^(utm_\w+|gclid|fbclid|msclkid|mc_eid|_ga|ref)$/i;
function cacheKeyFor(request) {
  const url = new URL(request.url);
  for (const k of [...url.searchParams.keys()]) if (TRACKING.test(k)) url.searchParams.delete(k);
  url.searchParams.sort();
  url.pathname = url.pathname.toLowerCase().replace(/\/+$/, '') || '/';
  return url.toString();
}
const response = await fetch(request, { cf: { cacheKey: cacheKeyFor(request) } });
// trade-off: lowercasing paths is only safe if your origin treats paths
// case-insensitively. If /Docs and /docs are different pages, skip that step.

Expected outcome: all campaign variants of a page share one cache entry.

2. Allow-list parameters for API and search routes

For routes where parameters matter, include only the ones the origin actually reads (for example q, page, sort) and drop everything else from the key.

3. Redirect inconsistent paths at the edge

Issue a single 301 from non-canonical paths (uppercase, missing or extra trailing slash) to the canonical one, cached at the edge, so variants converge on one URL.

nginx
# Canonicalise trailing slash with a single cached redirect.
rewrite ^([^.]*[^/])$ $1/ permanent;
# trade-off: redirects add a round trip for the visitor who followed the
# non-canonical link. Fix internal links so redirects are rare.

4. Replace broad Vary headers with explicit keys

Instead of Vary: User-Agent, derive a coarse device class at the edge if the HTML truly differs, and put that in the key. Better still, serve one responsive document. See Vary header pitfalls that destroy CDN hit rate.

Key normalisation rules by route type Recommended cache key normalisation for HTML pages, search pages, API routes and static assets. Key normalisation rules by route type Route type Query params in key Other normalisation Marketing / content HTML none (strip all) lowercase path, trailing slash Search / listing HTML allow-list q, page, sort sort params API GET routes allow-list documented params sort params Hashed static assets ignore query entirely immutable, no Vary

Verification

Request a page with several combinations of tracking parameters and parameter orders; after the first request, all should return a cache HIT. In CDN analytics, the number of distinct keys per popular path should collapse and the HTML hit ratio should rise — on campaign-heavy sites, often from below 40% to above 85%. Confirm analytics still records campaign parameters, since the origin and client still see the full URL.

Worked Example: A Campaign Launch

A retailer launched a campaign with links carrying utm_source, utm_medium, utm_campaign and per-recipient mc_eid values. The landing page's hit ratio dropped from 92% to 9% during the send, and origin CPU spiked; TTFB p75 for campaign visitors was 840ms. After adding key normalisation that stripped tracking parameters, the next campaign's landing page held a 94% hit ratio, campaign visitors' TTFB p75 was 70ms, and the origin barely noticed the traffic spike.

Common Mistakes

  • Removing parameters from the URL instead of the key. That breaks analytics attribution; normalise only the key.
  • Stripping parameters the origin uses. Use allow-lists on routes where parameters change content.
  • Lowercasing case-sensitive paths. Check origin behaviour first.
  • Ignoring HTML caching altogether. Key normalisation only matters if HTML is cacheable; many sites must fix that first.

Edge Cases

Signed URLs. Image and file URLs with signature parameters must keep them in the key, or one user's signed URL could be served to another.

Hash fragments. Fragments (#section) never reach the server and do not affect keys.

Single-page apps. Client-side routing may append parameters that the server ignores; normalise them out of HTML keys.

Multiple CDNs. Each layer (a CDN in front of another CDN or a load balancer cache) has its own key; normalise consistently at the outermost layer.

FAQ

Will stripping utm parameters break Google Analytics?

Not if you strip them only from the cache key. The browser still loads the original URL, so client-side analytics reads the parameters from location.search as usual.

Should static assets include query strings in the key?

For content-hashed assets, no — the hash is in the filename. Some build setups use ?v=123 for cache busting; if so, keep that parameter in the key and drop the rest.

How do I find which parameters my origin actually uses?

Search the server code for query parameter reads per route, and cross-check with access logs: parameters that never change the response body (same ETag) for the same path can be dropped from the key.

Does normalisation help with bot traffic?

Yes. Crawlers and monitoring tools often append random parameters; normalising them out prevents bots from filling the cache with useless entries and from bypassing it to hit your origin.

Is the cache key configurable without edge compute?

Most CDNs offer cache-key settings in their configuration UI or rules engine — query string allow/deny lists, header inclusion, case handling. Edge compute is only needed for logic beyond those options.

How do I roll out key normalisation safely?

Start with HTML routes that take no meaningful parameters (marketing and content pages), where stripping every parameter is safe. Monitor for any page that renders differently with and without a parameter before extending to listing and search routes with allow-lists. Keep a per-route switch so a mistake can be reverted without touching the rest of the configuration.

What hit ratio should HTML reach after normalisation?

For public content pages with tag-based purging and multi-minute TTLs, 85–95% at the edge is typical. Lower numbers usually point to remaining fragmentation, cookies forcing bypass, or TTLs too short for the traffic level per location — which tiered caching addresses.