Cache Query Strings
Extend page cache coverage to URLs with query string parameters instead of bypassing them.
Metrics
This technique can move up to 67% of LCP's share of the Lighthouse score.
This technique does not move TBT.
This technique does not move CLS.
This technique can move up to 67% of FCP's share of the Lighthouse score.
This technique can move up to 33% of SI's share of the Lighthouse score.
This technique can move up to 100% of TTFB's share of the Lighthouse score.
Overview
Most page caches bypass caching entirely when a URL contains a query string — ?utm_source=newsletter, ?page=2, ?color=red — because query strings might indicate dynamic or user-specific content. In practice, the vast majority of query strings on WordPress sites are tracking parameters (UTM), pagination, or filter values that produce the same HTML for all users. Caching these URLs delivers the same performance gains as page cache while also covering the large share of traffic that arrives via tracked links.
Impact grade, A+ to D: how much of the Lighthouse score this technique can move. Unaffected: TBT, CLS.
The Problem
A marketing campaign sends 10,000 visitors to /landing-page/?utm_source=facebook&utm_campaign=spring. Without query string caching, every single visit bypasses page cache, executes full PHP, and hits the database. The page takes 800 ms to generate instead of 10 ms from cache. The traffic spike — the moment when performance matters most — hits the server completely uncached. Affiliate link traffic, email campaign recipients, and paginated archives all suffer the same fate.
Performance Impact
LCP
High
tracked and paginated URLs serve from cache instead of requiring full PHP execution per visit
FCP
High
campaign traffic and paginated archives all receive full cache-speed responses
SI
Moderate
cached pages render faster and more completely for all query-string-bearing URLs
TTFB
700ms–1.5s
server response drops from full PHP execution time to cached page read time
Risk: Medium
caching pages with user-specific query strings risks serving wrong content — configure exclusions carefully
How it works
01
Identify which query strings are safe to cache
UTM parameters (
utm_source,utm_medium,utm_campaign), click IDs (fbclid,gclid,msclkid), and pagination (page,paged) do not affect page content and are safe to cache. Query strings that affect content — WooCommerce filters, search queries, session tokens — should remain uncached.02
Configure the cache to ignore tracking parameters
Most cache plugins support a list of query string parameters to ignore when building the cache key. Add UTM parameters and click IDs to this list — the cached page for
/blog/is then served for both/blog/and/blog/?utm_source=emailwithout generating a separate cache entry.03
Create separate cache entries for content-affecting parameters
For filter parameters that do change content (
?color=red&size=Lon a WooCommerce shop), create separate cache entries per unique parameter combination. This requires more cache storage but delivers full cache performance for filtered pages.04
Strip irrelevant parameters server-side
At the Nginx or CDN level, strip known tracking parameters from the cache key while passing them through to the application. This ensures one cache entry per real page while tracking data is still available to analytics.
Code Example
# Default: any query string bypasses page cache
# /landing-page/?utm_source=newsletter → PHP execution on every visit
# /shop/?page=2 → PHP execution on every visit# Nginx: normalize cache key by removing tracking parameters
map $query_string $normalized_query {
~*(?:^|&)(?:utm_[^&]*|fbclid=[^&]*|gclid=[^&]*)(?:&|$) "";
default $query_string;
}
fastcgi_cache_key "$scheme$request_method$host$request_uri";
# WP Rocket / LiteSpeed: add to "Never Cache Parameters" exclusion list:
# utm_source, utm_medium, utm_campaign, utm_term, utm_content, fbclid, gclid, msclkidIn WP Rocket: Settings → Cache → Cache query strings. In W3 Total Cache: Page Cache → Ignored query stems. Add UTM parameters and click IDs to the ignored list, not the excluded list.
Limitations
- Caching pages with WooCommerce cart or checkout query strings risks serving one user’s cart state to another. Always exclude
wc-ajax,add-to-cart, and any authentication-related parameters. - The number of cache entries grows with each unique parameter combination that is cached rather than ignored. On a large site with many filter combinations, this can significantly increase cache storage requirements.
- Cache invalidation becomes more complex when the same content exists under multiple URLs — a post update must invalidate all cached variants of its URL.
Common Mistakes
Caching all query strings without exclusions
Always define an exclusion list for user-specific and security-sensitive parameters before enabling query string caching. Test with a logged-in user adding items to cart to verify personalized content is not cached.
Creating separate cache entries for UTM parameters
UTM parameters do not change page content. Stripping them from the cache key means all tracked traffic hits the same cached page — fewer cache entries, higher cache hit rate, and no stale content risk.