Skip to content
HelalStart a project

My store slows down or crashes when ads go live

The store is fine on a normal day. Then a campaign, a launch or an email blast goes out, pages crawl, checkout throws errors, and the host sends a resource warning.

The store goes down when the ads go live

You plan a launch for weeks. The emails go out, the ads switch on, an influencer posts. For the first ten minutes everything looks good. Then pages take ten seconds. The cart spins. Some customers see a 502 or 503 error. Your host emails about CPU limits, or suspends the account. By the time it recovers, the peak is over.

This is the worst moment for a store to be slow. Every visitor in that spike cost money to bring in, and most of them came to buy right then. A normal day hides the problem, because the store never reaches its limit until the day it matters most.

Why it happens

Traffic arrives as a spike, not a curve

Ads, launches and email blasts don't send visitors evenly through the day. They send many at once, often within minutes of the send or the post. A server that handles a busy afternoon comfortably can fail when the same day's traffic arrives in a quarter of an hour.

Too many requests miss the cache

A cached page is cheap: the server or the edge sends a stored copy. An uncached page runs PHP and database queries. During a campaign, more requests miss the cache than you'd expect:

  • Tracking parameters. Ad clicks arrive with utm_*, fbclid and gclid in the URL. If the cache treats each unique URL as a new page, every click is a cache miss.
  • Cookies. Some plugins set a cookie on the first visit, and many caches skip any request with a cookie.
  • Logged-in and returning customers bypass the page cache.
  • Cart fragments and admin-ajax calls run on every page view, cached or not.
  • Cache purges. Editing a product or a price during the campaign can clear large parts of the cache at the worst moment.

Checkout can't be cached

Cart, checkout and payment are personal to each visitor, so every step runs on the server. A checkout that calls several plugins, recalculates shipping through a remote API and sends emails before it responds holds a PHP worker for a long time. Under load, that is where the queue forms.

Workers and database connections run out

Each uncached request holds one PHP worker. Hosting plans give a fixed number. When they are all busy, new requests wait, then time out. The database has its own limit on connections and memory, and slow queries hold locks that make the next queries wait. Once one layer saturates, the others follow.

Slow work happens in the request

Order emails, webhooks to the CRM or ERP, stock syncs and analytics calls often run while the customer waits. Each one adds time to the request and holds a worker. If a remote service slows down under its own load, your checkout slows with it.

What fixing it involves

1. Know the peak and the current limit

I start from what's planned: channels, expected visitors, the hour it starts, the landing pages. Then I find where the store breaks today. I load-test a staging copy that matches production, ramping up simulated visitors across the landing page, product pages, cart and checkout, and record which layer fails first: workers, database, a plugin, a remote API.

2. Raise the cache hit ratio

  • Full-page caching at the edge with Cloudflare for anonymous visitors on landing, category and product pages.
  • Cache keys that ignore tracking parameters, so every ad click hits the same cached page. The parameters still reach analytics in the browser.
  • No needless cookies on first visit, so anonymous pages stay cacheable.
  • Cart fragments only where needed.
  • Pre-warm the cache for the campaign pages before the send, and freeze product edits during the first hours.

I check the cache hit ratio in the edge analytics during the load test. A high ratio is what keeps the server free for checkout.

3. Make checkout lean

I profile checkout under load and remove what doesn't need to happen while the customer waits. Shipping rates get cached where the carrier allows. Plugins that run on checkout without a reason get disabled there.

4. Move slow work into queues

Order emails, webhooks, stock syncs and CRM updates move to background jobs: Action Scheduler running on a real server cron, or a proper queue for larger setups. The customer gets the order confirmation page fast, and the follow-up work runs a few seconds later without holding a worker.

5. Size the server for the peak

With the waste removed, I size what's left: PHP workers for the expected uncached load, database memory and connections, an object cache. If the host can't scale for the campaign, I say so early, while there is still time to move. See migrating off a slow host.

6. Protect the store from abuse at the same time

A spike is also when bots and card testers notice a store. Rate limits on checkout and login, and a challenge for automated traffic, keep that load off the server without slowing real buyers. See stopping a card-testing attack.

7. The week before the launch

  • Load test again after the changes, at the expected peak and above it.
  • No plugin, theme or PHP updates in the last few days.
  • A fresh backup, and a tested way back.
  • A simple holding page ready to serve from the edge if something fails.
  • Monitoring and alerts on response time, errors and workers, and someone watching during the first hour.
  • A clear rule for pausing the biggest campaigns if the store struggles.

8. Read the results afterwards

After the campaign I review the peak: response times, cache hit ratio, worker use, errors. That tells you how much headroom is left for the next one, and what to fix before it.

If the store is slow on normal days too, start with why WooCommerce slows down at scale. This work is part of my performance engineering service.

Related service: Performance engineering

01 / Proof

Where I've done this

Related performance work: for an Israeli jewelry store with a Hebrew, right-to-left storefront, I fixed LCP and preloading, cleaned up fonts and scripts, removed duplicate pixels and profiled the server.

Israeli jewelry store (Hebrew, right-to-left)

Live

Performance overhaul

Problem
Slow pages on mobile, heavy tracking scripts and a late-loading hero.
What I built
LCP and preload fixes, font and script cleanup, duplicate pixel removal, server-side profiling.
Outcome
Live in production; the hero image loads first and each tracking pixel fires once.
Stack
  • WordPress
  • WooCommerce
  • Cloudflare

02 / Questions

Questions owners ask

Can't I just upgrade my hosting plan for the campaign?
It helps if the limit is raw capacity, and some hosts make it easy to scale up for a week. But if pages miss the cache or checkout runs a slow query, a bigger server only moves the breaking point. I find the bottleneck first, then size the server for the expected peak with headroom.
How much traffic can my store handle?
Nobody can say from the outside. It depends on how many pages are cached, how heavy checkout is, and how many PHP workers and database connections the server has. A load test answers it for your store: I ramp up simulated visitors on a staging copy until something fails, so you know the number before the campaign does.
Will a CDN solve this?
A CDN serves images, scripts and fonts from the edge, which takes a lot of load off the server. With full-page edge caching for anonymous visitors, it can serve most product and landing pages too. It can't cache cart and checkout, so those still depend on the server. The CDN is the first layer, not the whole plan.
What should I do if the site goes down during a campaign?
Pause the campaigns that send the most traffic first, so you stop paying for visits to an error page. Then put up a simple holding page served from the edge, and find the bottleneck. If it's down right now, use the emergency page.

Want me to look at your setup?

I review your site before a short discovery call and come with the questions and risks I see.

Start a projectGet the free checklist