Black Friday email campaigns: how to avoid overloading WordPress

Black Friday is approaching. You will prepare the offer, landing page, email campaign and ads, and perhaps even check that the server has enough resources to handle the spike in traffic.

But there is one very simple check that is easy to overlook:

what happens to the cache when someone visits your website through a link in the email?

A website that works perfectly every day can become overloaded within minutes of sending an email campaign. And not necessarily because thousands of people have arrived at once.

The problem may be the parameters your email platform adds to links.

Depending on the cache configuration, a URL with these parameters may bypass the cache or create a separate cached version. If the platform also adds a unique identifier for each subscriber, a few dozen seemingly harmless visits can turn into a few dozen dynamic requests to WordPress.

When many people click at the same time, that can be enough to overload the hosting.

In a recent case, just 22 clicks per minute were enough to cause problems on the website.

The problem may be invisible before you send

This is probably the most misleading part.

You visit the landing page before sending the email, check that everything works, see it load in a fraction of a second and give it the go-ahead.

But you are testing a clean URL:

https://example.com/black-friday-offer/

When the campaign goes out, a subscriber may arrive at an address like this:

https://example.com/black-friday-offer/?utm_source=newsletter&utm_campaign=blackfriday&_mrSubscriber=123456

And another person may arrive at:

https://example.com/black-friday-offer/?utm_source=newsletter&utm_campaign=blackfriday&_mrSubscriber=789012

To a person, these are exactly the same page.

To the cache, depending on its configuration, they may not be.

Each subscriber may arrive with a URL that the cache does not recognise as the page it has already stored.

Why is caching so important?

Most WordPress websites use a cache.

Once a page has been generated, the server can store a static copy. When the next visitor arrives, instead of running WordPress, PHP and database queries again, it can return that copy directly.

Put very simply:

Visitor
   ↓
Cache
   ↓
Previously generated HTML

requires far fewer server resources than:

Visitor
   ↓
PHP
   ↓
WordPress
   ↓
Plugins
   ↓
Database
   ↓
HTML

A modest website can handle many simultaneous visits if most are served from the cache.

The same website may struggle with much less traffic if every visit requires WordPress to run in full.

Which parameters do email platforms add?

Email platforms usually add parameters to links to measure campaigns.

The best-known are Google Analytics UTM parameters:

utm_source
utm_medium
utm_campaign
utm_content
utm_term
utm_id

These values are normally the same for every recipient of a campaign.

The problem can be greater when the platform also adds a unique identifier for each subscriber.

Platform Platform-specific parameters May be unique to each subscriber
HubSpot _hsenc, _hsmi _hsenc
Mailchimp mc_cid, mc_eid mc_eid
Mailrelay _mrMailingList, _mrSubscriber _mrSubscriber
Klaviyo _kx _kx
ActiveCampaign vgo_ee vgo_ee
Brevo, MailerLite, Acumbamail Mainly utm_* Usually not

Names may vary by platform, version or configuration.

That is why I would never rely solely on a list found online.

The most reliable test is to send yourself a test email, click the link and inspect the final URL.

UTM parameters can cause problems too

Being the same for everyone does not make UTM parameters harmless in every case.

If the caching system excludes any URL containing parameters, this:

/offer/

may be served from the cache, while this:

/offer/?utm_source=newsletter

may force the server to generate the page again.

A unique subscriber identifier can multiply the problem further because each person arrives with a different URL.

A real case: just 22 clicks per minute

I recently saw this on a website I manage.

After an email campaign went out, traffic peaked at just 22 clicks per minute.

That does not sound excessive.

But the links contained a different identifier for each subscriber, and visits were not being served correctly from the cache.

Many requests had to run through PHP and query the database.

The hosting became overloaded, and some visitors started seeing an error page from the CDN/Varnish layer.

The most puzzling part was that WordPress appeared to have no serious errors.

The WordPress logs may contain no fatal error or warning in debug.log.

WordPress is not necessarily ‘failing’: the server may run out of available PHP processes — workers— or other resources while repeatedly generating the same page with different parameters.

The usual reaction is to think that ‘the server cannot cope’, when the problem may simply be how the cache handles these parameters.

This also explains why the issue can go unnoticed for years: while the hosting absorbs the dynamic requests, everything appears to work. The problem emerges when enough clicks arrive close together.

How to check before sending

The test is straightforward and requires no special software.

Windows 10 and Windows 11 already include curl.

Open Command Prompt (CMD).

First check the page without parameters:

curl.exe -s -D - -o NUL "https://example.com/black-friday-offer/"

This command makes a normal HTTP request, discards the HTML content and shows only the response headers.

Repeat exactly the same command:

curl.exe -s -D - -o NUL "https://example.com/black-friday-offer/"

The first request may have generated the page.

The second, if everything works correctly, may already be served from the cache.

Now test the URL reached from the email:

curl.exe -s -D - -o NUL "https://example.com/black-friday-offer/?utm_source=newsletter&utm_campaign=blackfriday&_mrSubscriber=123456"

Run it again.

Finally, change only the subscriber identifier:

curl.exe -s -D - -o NUL "https://example.com/black-friday-offer/?utm_source=newsletter&utm_campaign=blackfriday&_mrSubscriber=789012"

This simulates another subscriber clicking the same link for the first time.

The question is: when the subscriber identifier changes, can the server still return the same page from the cache, or does WordPress have to generate it again?

macOS and Linux

The command is almost identical. Simply replace:

-o NUL

with:

-o /dev/null

Why do I not use curl -I?

You will often see examples like this:

curl.exe -sI "https://example.com/black-friday-offer/"

It is shorter and works perfectly on many servers.

But the -I option makes an HTTP HEAD request.

A normal visitor opening the page makes a GET request.

Some servers, proxies, CDNs or caching systems may treat HEAD and GET differently.

So, to check real behaviour before an important campaign, I prefer:

curl.exe -s -D - -o NUL "URL"

The request uses GET, but we discard the page body and keep only the headers.

What should you look for in the headers?

It depends on the caching system.

LiteSpeed

x-litespeed-cache: miss

followed by:

x-litespeed-cache: hit

Cloudflare

cf-cache-status: MISS

or:

cf-cache-status: HIT

Varnish or a CDN

You may see an Age header:

Age: 0

and, in a response that has already been cached:

Age: 125

But not every system gives you a HIT or MISS that is so easy to interpret.

W3 Total Cache with Disk: Enhanced

With W3 Total Cache in Disk: Enhanced mode you may not find an explicit header telling you whether the page was served from the cache.

In that case, compare other signals.

A cached page may show a header such as:

Last-Modified: Sat, 26 Sep 2026 12:02:47 GMT

with an earlier timestamp, and omit:

X-Powered-By: PHP/...

By contrast, a request that ran through PHP may show:

X-Powered-By: PHP/8.3

or the relevant version.

This is not a universal rule for every server, but it is a useful clue when comparing two responses from the same website.

The point is not to fixate on the word HIT.

The point is to compare what happens with:

/page/

and with:

/page/?parameter=value

Remember: you may have two caches at once

This is another source of misleading conclusions.

A website may have an architecture like this:

Visitor
   ↓
CDN / Varnish
   ↓
W3 Total Cache
   ↓
PHP + WordPress
   ↓
Database

The CDN may always return:

Age: 0

or show a MISS.

But that does not necessarily mean WordPress had to run PHP.

The CDN may not cache the HTML while W3 Total Cache still returns a static file.

A CDN MISS does not necessarily mean a WordPress cache MISS.

You need to examine both layers.

For example, if you see Age: 0, but there is no X-Powered-By: PHP and Last-Modified refers to an earlier copy, the CDN may not have served the page from its cache while W3 Total Cache did.

The final question is always the same:

did this visit require WordPress to run PHP?

How to fix it

The usual solution is to configure the caching system so that certain tracking parameters do not force the page to be generated again.

In other words, so that:

/black-friday-offer/

and:

/black-friday-offer/?utm_source=newsletter&_mrSubscriber=123456

can use the same copy of the page.

The parameters remain in the browser URL, so Google Analytics and email platforms can still use them.

We are preventing parameters used only for tracking from forcing WordPress to regenerate the same content.

System Where to check
W3 Total Cache Performance → Page Cache → Advanced → Accepted query strings
LiteSpeed Cache Cache → Advanced → Drop Query String
WP Rocket Ignores many common tracking parameters by default; review any it does not recognise
Cloudflare Review cache rules and the cache key
Varnish or the hosting provider’s CDN Ask the provider how it handles query strings

Parameters I usually review

utm_source
utm_medium
utm_campaign
utm_content
utm_term
utm_id
fbclid
gclid
msclkid
_hsenc
_hsmi
mc_cid
mc_eid
_mrSubscriber
_mrMailingList
_kx
vgo_ee

I would not copy this list blindly.

The correct process is:

  1. Send yourself a test email.
  2. Click the link.
  3. Copy the full URL.
  4. Identify the parameters present.
  5. Check which change the content and which are only used for tracking.
  6. Configure only the latter so that they do not affect caching.

Do not ignore every parameter

It may be tempting to tell the cache to ‘ignore everything after the ?’.

Do not do this without understanding how the website works.

Some pages depend on those parameters.

For example, WordPress search uses:

?s=word

A shop may use parameters to filter products.

A gallery may use them for pagination.

A search tool, configurator or comparison tool may need them to display different content.

Ignoring all parameters indiscriminately can mean serving the same content at URLs that should show different results.

Ignore only parameters you know are used for tracking and do not change the page content.

Watch out for duplicate UTMs too

This review often reveals another problem.

Some email platforms can add Google Analytics UTM parameters automatically.

If you have already added them manually, you may end up with a URL like:

?utm_source=newsletter&utm_campaign=blackfriday&utm_source=mailing&utm_campaign=campaign123

This does not usually cause the same performance issue as a misconfigured cache.

But it can muddy Analytics data and split a single campaign across different names.

Always check who adds the UTM parameters:

either you or the email platform, preferably not both.

Before pressing ‘Send’

  • I have sent a test email from the actual platform.
  • I have clicked one of the links.
  • I have checked the full final URL.
  • I know which parameters the platform adds.
  • I have checked the page without parameters using curl.
  • I have repeated the test with the email parameters.
  • I have changed the subscriber identifier to simulate a new visit.
  • I have checked whether there is one caching layer or more.
  • I have verified that tracking parameters do not force WordPress to run PHP again.
  • I have not configured the cache to ignore all parameters indiscriminately.
  • I have checked that UTM parameters are not duplicated.
  • I have cleared the cache after the final changes.
  • I have reopened the landing pages to warm the cache again.
  • I have repeated the final test.

A website can handle many visits when serving cached pages and struggle with just a few dozen when each requires WordPress to run PHP.

Before Black Friday, a sale, a ticket release, registration opening or any email campaign that may bring many visitors within minutes, it is worth spending five minutes checking this.

It may prevent the website from failing precisely when those visits matter most.

If you are preparing an important campaign and are unsure how WordPress will respond to many simultaneous visitors, this is one of the checks worth making before pressing ‘Send’.