We monitor real-user Core Web Vitals for every page across the site. When we reviewed the data, a strange pattern stood out. Most pages had a server response time of 200-500 ms. But a specific group – the homepage, product pages, and demo request pages – showed 4-6.6 s. For the same content, that made no sense.
The signature pointed to the server, not the front end. TTFB (time to first byte) was slow, and everything after it inherited the delay. But when we tested those exact pages ourselves, they were fast. Cache hit, instant response.
So what was different about the real visitors?
What we found
The slow pages had one thing in common: they were landing pages for paid campaigns and marketing emails. Those clicks don’t arrive at a clean URL. An organic visitor requests this:
https://client.com/product-page/
The exact same page looks like this when someone clicks a Google Ads campaign managed through HubSpot:
https://client.com/product-page/?utm_source=google&utm_medium=cpc
&utm_campaign=identity-es&utm_term=verificacion
&gclid=Cj0KCQjw4vKpBhCZARIsAOKHoWTn...
&hsa_acc=1234567890&hsa_cam=20456789012&hsa_grp=1567890123
&hsa_ad=678901234567&hsa_src=g&hsa_tgt=kwd-345678901234
&hsa_kw=identity%20verification&hsa_mt=b&hsa_net=adwords&hsa_ver=3
A click from a HubSpot marketing email looks like this:
https://client.com/request-a-demo/?_hsenc=p2ANqtz-_8FhTr2vXq...&_hsmi=987654321
Caching layers keep a list of “safe” parameters they can ignore. WP Rocket ships with a solid default list – utm_source, utm_medium, gclid, fbclid, msclkid and about 70 others. But look closely at the ad URL above. gclid and utm_* are on that list. HubSpot-managed Google Ads campaigns also append ten hsa_* parameters, which are not on the list. Neither are the email tokens _hsenc / _hsmi or HubSpot’s CTA parameters (hubs_content, hsCtaTracking, …).
One unrecognized parameter is enough to poison the whole URL. The cache then treats it as a unique, dynamic page:
- Cloudflare bypasses the edge cache (
cf-apo-via: origin,qsin the response headers). - WP Rocket refuses to serve its stored copy.
- Every single click pays a full, uncached WordPress render – 4 to 8 seconds, measured.
Every click carries a unique tracking token (no two gclid or _hsenc values are ever the same), so the cache never warms up for this traffic. It’s not a cold cache that eventually fills – it’s a permanent bypass.
We confirmed this by pulling the actual query strings from Cloudflare’s request analytics. Over 11,000 requests per week arrived with parameters outside WP Rocket’s known list. The slowest pages in the RUM data mapped one-to-one to the pages receiving that traffic. The fast pages? Organic search visitors with clean URLs.
The irony is hard to miss: the most expensive traffic – the clicks the client pays for – was consistently getting the slowest version of the website.
The fix
Analytics JavaScript in the browser consumes all of these parameters. The server renders identical HTML with or without them, so it’s completely safe to tell the cache to ignore them. WP Rocket has a filter for this exact job – rocket_cache_ignored_parameters. All it takes is a small must-use plugin:
<?php
/**
* Plugin Name: WP Rocket Extra Ignored Query Params
* Description: Serve cached pages for tracking params that never change the HTML.
*/
defined( 'ABSPATH' ) || exit;
add_filter(
'rocket_cache_ignored_parameters',
function ( $params ) {
$extra = array(
// HubSpot-managed Google Ads.
'hsa_acc', 'hsa_cam', 'hsa_grp', 'hsa_ad', 'hsa_src',
'hsa_tgt', 'hsa_kw', 'hsa_mt', 'hsa_net', 'hsa_ver',
// HubSpot content/CTA links.
'hubs_content', 'hubs_content-cta', 'hubs_signup-cta',
'hubs_signup-url', 'hubs_post', 'hubs_post-cta',
'hsCtaTracking', 'hsCtaAttrib',
// HubSpot email tracking.
'_hsenc', '_hsmi',
// Other marketing params seen in real traffic.
'utm_referrer', 'mkt_tok', 'li_fat_id',
);
return array_merge( (array) $params, array_fill_keys( $extra, 1 ) );
},
20 // after WP Rocket's own dynamic list, so nothing gets lost
);
Two gotchas cost us time. Here’s how to avoid them:
- The list is baked into a config file. WP Rocket writes the ignored parameters into
wp-content/wp-rocket-config/{domain}.php. Its early-cache layer reads this file before WordPress even loads. Dropping in the mu-plugin isn’t enough – regenerate the config afterwards:
wp eval "rocket_generate_config_file();"
- OPcache can hide your change. If your server caches PHP files with a revalidation interval (ours checks every 300 seconds), it keeps serving the old config for a few more minutes. Don’t panic-debug a fix that hasn’t propagated yet – wait out the interval before testing.
Before rolling out, check what’s already covered. WP Rocket updates its list remotely, and it already included two parameters we planned to add (gad_source, gad_campaignid).
Here are the before and after results, measured on real campaign URLs through Cloudflare:
| Request | Before | After |
|---|---|---|
| Ad click with full hsa_* + gclid + utm_* set | 4.0 s | 0.5 s |
| Marketing email click (_hsenc / _hsmi) | 6.6 s | 0.13 s |
| CTA click to the homepage (hubs_*) | 4.1 s | 0.2 s |
| Control: genuinely unknown parameter | 7.4 s | 7.4 s (correct – still renders fresh) |
Why real user monitoring matters
No lab test would have caught this. Synthetic tools request clean URLs, usually against a warm cache. That’s exactly the scenario that was already fast. The averages also looked fine because organic traffic diluted the numbers.
RUM data exposed it: real visitors, real URLs, broken down per page. Only field data revealed the pattern: “the pages we advertise are the pages that are slow.”
Spot problems early. Fix them fast. Before they quietly burn your ad budget on visitors who bounce before the page renders.
Want us to look at what your real visitors are actually experiencing? Get in touch with us.