Where does your store lose the seconds?
Every page load is a relay. Hover any leg to see what breaks there - or run the two-question diagnosis and the map points at the leg that’s likely costing you.
1 · Where does the slowness show up?
Part of “Why Your WooCommerce Store Is Slow” on tomherudek.com. The map is a teaching model, not a measurement - confirming a suspect takes real profiling.
A tenth of a second, 8.4% of your conversions
A tenth of a second, barely more than a customer can perceive, lined up with an 8.4% conversion swing in a 30-million-session study. That's a line on your revenue statement: across 37 brands and 30 million mobile sessions, a 0.1-second improvement in mobile load time coincided with an 8.4% lift in conversions and a 9.2% lift in average order value (Deloitte, "Milliseconds Make Millions," 2020).
Put it in dollars. Take a $10,000/month store, roughly $6,000 of it mobile, and a fix that pulls the mobile product page from 2.5 s down to 1.0 s. One 0.1-second increment: $6,000 × 8.4% ≈ $500 a month. I credit at most three increments - my cap, not the study's - because the relationship is a threshold curve, not a straight line, and past ~0.3 s of improvement the study says nothing. Capped ceiling: about $1,500 a month. Print the floor: $500 a month, roughly $6k a year. A scenario, not a forecast. (The interactive map above runs it on your numbers.)
All the caveats, once, in one place: the study is Google-commissioned, correlational, mobile-only, built on 2019 data, and the arithmetic above is back-of-envelope, low confidence - a direction and a ceiling, not a meter. The direction is enough.
You already suspect this. It's why you keep loading your own product page on your phone, watching it hang, unable to tell which of roughly 35 possible causes you're looking at. Two of them almost nobody weighs: the cart/checkout exclusion every cache plugin documents but almost nobody prices; and sometimes the slowness has nothing to do with your site at all.
So speed is a money problem, which makes it a milliseconds problem: where does the time actually go?

A page load is a relay, and the legs add up
Follow one request. It leaves your customer's phone, crosses the network and any edge layer to your server, hits a gatekeeper that decides cached-or-built (the cache decision), waits for a PHP worker (server), runs WooCommerce against the database (PHP + DB), sometimes waits on an outside service (third-party APIs), and hands the page to the browser to render. On the critical path to the largest visible element (LCP) these legs are additive: Google's performance docs describe the sub-parts of Largest Contentful Paint as having "no overlap or gap between them" (web.dev). Assets download in parallel; the critical path doesn't. The legs add up, and the biggest leg is the biggest lever.
The biggest leg usually has a name. In the 2024 Web Almanac, server response time (TTFB) is the largest LCP sub-part in every cohort: about 45% of the total on fast pages, 53% on slow ones. Google calls TTFB good under 0.8 s and poor past 1.8 s (web.dev). My working band: 0.5-1 s is acceptable for a real, uncached WooCommerce render on budget hosting - straddling Google's good line, which is the point. Acceptable because raw WooCommerce on budget hosting rarely beats it, not because it's free: the gap from 1.0 s to 0.5 s is five 0.1-second increments; the cap credits three. A cached page answers in tens of milliseconds (~10-100 ms).
Credit where due: for the cached majority of pageviews, the browser leg dominates perceived speed. The Almanac's TTFB share aggregates a mostly-uncached web, and a working cache collapses that share so the browser leg becomes the bottleneck, so the images-and-JavaScript advice in every speed listicle is correct for constant slowness on cacheable pages. This article weighs legs by the buyer's path instead, and by the intermittent and sudden-onset slowness the checklists ignore. They list by pageview; we rank by dollar.
Every cause of WooCommerce slowness lives on one of six legs - or in who shows up at all:
| Leg | What happens there | Causes that live here |
|---|---|---|
| 1. Edge | the request crosses the network | no CDN · server far from customers · DNS/TLS overhead · no HTTP/2/3 |
| 2. Server | a PHP worker picks it up | capped/contested hosting slice · too few PHP workers · concurrency choking · slow disk · old PHP · no opcache/object cache |
| 3. Cache decision | a cached copy is served, or not | no page cache · money pages uncacheable by design · cookie-bypass amplifier · cart-fragments AJAX (theme-dependent since Woo 7.8) · WP-Cron riding visitor traffic |
| 4. PHP + database | WooCommerce builds the page | autoload bloat · postmeta explosion (pre-HPOS) · Action Scheduler backlog · transients · sessions table · unindexed faceted filtering · plugin-executed work · hook loops · page builders · scans/backups at peak |
| 5. Third-party APIs | the request waits on outsiders | payment gateways · live shipping rates · inline SMTP email |
| 6. Browser/device | the page renders | images · render-blocking JS/CSS · fonts · third-party scripts · heavy DOM on cheap phones |
| ✚ Traffic & abuse | who is sending requests at all | bots on faceted URLs · card-testing on checkout · malware |
So: which legs do the dollar-carrying visitors actually run? The cache decides.
Running a WooCommerce store?
A decade of keeping WooCommerce stores fast, stable, and quietly making more money. Here is how I think about the technical side of running one.

The pages that make you money can't be cached
WooCommerce core forces the cart, checkout, and my-account pages to bypass every page cache. The function is literally called prevent_caching(), and it sets DONOTCACHEPAGE (WooCommerce source). Tier one, universal: the pages that make you money are the pages no correctly configured cache will ever serve - cheapest shared host and priciest managed host alike. Working as designed.
Tier two is the amplifier. On cookie-bypass hosts like Kinsta and WP Engine, adding anything to a cart sets the woocommerce_items_in_cart cookie and the page cache switches off for that visitor site-wide (WP Engine support docs): every HTML page a cart-holder views afterward gets built from scratch.
Now derive who lives on the slow path (medium confidence - typical values from primary benchmarks; tier 1 is by-design fact, tier 2 architecture-dependent). Littledata's 2,800-store panel and Dynamic Yield's benchmark together put add-to-cart at 4.6-6% of sessions, small stores at the low end; Baymard's meta-analysis puts cart abandonment at 70.2%, so buyers are a subset of cart-holders, and 70.2% says how small a subset. That add-to-cart rate is a proxy for the cookie's share of sessions, not a direct measure. Call cart-holders your highest-intent ~5% of sessions (often fewer), buyers included. Tier 1 puts them on raw PHP for cart, checkout, and account on every host. Tier 2 extends it: on bypass hosts they run raw PHP on every page they touch after add-to-cart, while the ~95% who never set the cookie ride the cache their whole visit. Bots and logged-in customers stack on top.
That prices the first of the two neglected causes from the top of this article: the page cache protects your window-shoppers, and on bypass hosts it abandons your highest-intent sessions, buyers included.
The cliff, a worked illustration rather than a guarantee: cached pages answer in ~10-100 ms; uncached WordPress renders run 600-900 ms (band 0.3-2 s, practitioner-observed). Roughly 10×. Woo core decides which side a money-page view stands on; on bypass hosts, a cookie does.
Two sub-plots on this leg. Cart-fragments AJAX used to refresh the mini-cart on every page load - "severe impact on the load on the server" on high-traffic stores, per Woo's own dev blog; since Woo 7.8 (June 2023) it's no longer loaded everywhere by default, though themes that hard-code the cart widget re-trigger it. And WP-Cron, WordPress's task runner, fires on visitor page loads rather than on a clock; it returns in the ranking.
My position - two documented architectures exist, and I side with the second: cache every page even with items in the cart, fetch cart state client-side with a small AJAX call, and exclude cart, checkout, account, plus any genuinely personalized routes. That's WP Rocket's default; LiteSpeed's recommended ESI setup is a related but distinct server-side variant; Woo's own Mini-Cart Block points the same way. The AJAX fetch shrinks and isolates the dynamic work rather than eliminating it; tier 1 stays untouched. The documented downside is a stale mini-cart - exactly why the bypass hosts bypass.
Either way, your highest-intent visitors run raw PHP and real database queries, which puts the server itself on their critical path. And on cheap hosting, your slice of it is smaller than you think.

Your slice of the server is capped - and contested
On shared or entry-level hosting your store runs on a slice of a machine with two properties the sales page never mentions - your own account's limits cap it, and other tenants contest it - and from inside, the two look identical. Three mechanisms hide under "the server is slow"; keep them apart.
Hypervisor CPU steal (VPS). Steal time is CPU your virtual machine wanted but the physical host handed to someone else, visible as st in /proc/stat (Red Hat's definition; Datadog shows what it does to latency). Rule of thumb, and only that: sustained steal above ~10% suggests a contended machine. It's measured - Netflix traced one noisy container causing a 131 ms p99 latency spike in its neighbor (Netflix Tech Blog). An existence proof from a container fleet; no shared-hosting magnitude claim follows.
LVE self-throttling (cPanel shared hosting). On shared cPanel hosting running CloudLinux, the OS caps each account's CPU, disk IO, and concurrent processes; a throttled site will "start responding slower" and throw 508/503 errors (CloudLinux docs). Read that carefully: this is your own ceiling, not neighbor theft. Your $5 plan came with a ration book.
Plain contention. Oversold boxes, shared disks, shared database servers - the residual everyone pictures when they say "bad host."
All three share a signature: intermittent slowness that correlates with nothing you can see, hitting wp-admin and the storefront alike. One split worth keeping: LVE throttling follows your own load; neighbor pressure doesn't have to. For this piece I profiled the 11 top-ranking "speed up WooCommerce" guides; 0 of 11 mention any of this. That measures neglect, nothing else - no incidence data exists, and I'm not inventing any. Meanwhile the $3-11/month shared tier (versus $25-35 managed entry, public pricing as of July 2026) is exactly what a budget-constrained store buys into. Most neglected cause on the list, hardest to diagnose from inside. That prices the second of the two neglected causes from the top of this article - the one where the slowness has nothing to do with your code.
The slice is also capped in a way you can count: PHP workers. Each worker handles exactly one request at a time, and cached pages bypass workers entirely (Kinsta), so the cache decision matters twice. Kinsta's entry plan ships 2 workers, with 4 recommended for e-commerce (their own docs); most competitors don't publish a count.
Run the numbers. 2 workers ÷ 0.6-0.9 s per uncached render ≈ 2-3 uncached requests per second, a theoretical ceiling - and queues form earlier (the latency knee arrives around 70-80% utilization; a worker blocked on a slow database query or external API call takes it lower still). A handful of simultaneous cart-holders - the exact visitors the cache pushed onto the raw-PHP path - plus one bot wave equals a queue, then 502s once upstream timeouts are exceeded. Confidence: medium; exact arithmetic, practitioner-observed render band. On shared cPanel the same wall wears a different label: "CPU seconds" or "entry processes limit reached."
Also on this leg: old PHP (7.4 → 8.2 ≈ +23% WooCommerce throughput, Kinsta's benchmarks), slow disk, missing opcache/object cache.
You now know where the time goes and what each cause costs when it fires. Time to rank.

Journey order is not rank order: the shortlist, weighted in dollars
The rules, on the page: likelihood (mechanism base-rate; no incidence statistics exist, so none are claimed) × impact once triggered, and I lean the impact toward the buyer's path - where the dollars are - rather than the raw pageview count. Where likelihood is honestly unquantifiable, I rank by impact plus the cost of never diagnosing it. The sections above followed the request; this re-sorts.
1. The uncacheable money path - cart, checkout, and account running raw PHP on every host. Likelihood: universal, by Woo core design. Impact: every dollar crosses it. It ranks first because it can't be removed: architecture limits how much traffic reaches the raw path, while items 2-8 decide how fast and resilient that path is.
2. The capped, contested server slice + concurrency. Likelihood: tied to cheap hosting, honestly unquantified. Impact: high once triggered, with the highest diagnosis cost on the list.
3. Autoload bloat. Every uncached request loads every option marked autoload=yes in one blob via wp_load_alloptions(), before any page logic runs; an object cache skips the query but still fetches and unserializes the blob each time. Since WP 6.6, Site Health flags total autoload above 800 KB as critical; WordPress VIP enforces a 1 MB ceiling (past it, 503s). Now the bytes, and the loudest caveat in this article (low confidence): the ~3.4 MB average reported for aged Woo stores is secondary and informal. Take 1,000 uncached requests a day; money-page views, cart-holders on bypass hosts, logged-in customers, and bots get you there fast. At that rate, 3.4 MB ≈ 3.4 GB of options data shuffled and processed in memory daily, none of it shown to anyone. No milliseconds claim follows; no published per-MB benchmark exists.
4. Action Scheduler backlog (the cron inversion). The folklore here runs backwards. WP-Cron fires on page loads, so a low-traffic store may never fire its scheduled cleanup - and WooCommerce's June 2026 post admits Action Scheduler tables "could grow without bound and never recover on their own" (Woo dev blog). AS 4.0 adds failed-action cleanup (3-month retention) and a daily job. No official row threshold exists; my own unscientific line: hundreds of thousands of rows deserves a look. Coverage in those 11 guides: zero.
5. Plugin-executed work. Plugin count is folklore too; the mechanism is the work plugins execute - queries, hooks, remote calls, assets. One plugin making an uncached remote call per request outweighs thirty tidy ones. The family: theme-plugin conflicts, hook loops (the save_post infinite-loop pattern is documented in core's own reference), inline phone-home license checks, page builders, and security/backup jobs at peak - Wordfence itself recommends scanning 8 PM-5 AM. The gotcha with those free backup-and-security tiers: they schedule by interval and WP-Cron needs traffic, so your "nightly" backup drifts to Tuesday lunchtime.
6. Third-party APIs at request time. Likelihood: unquantified; impact lands exactly on checkout, maximum dollar weight. Stripe's PHP SDK ships a default timeout of 80 seconds (SDK source): a hung gateway can hold one of your two workers until your host's execution limit (typically 30-60 seconds) kills the process. Woo core caches shipping rates in the session "to avoid recalculation" - an admission the recalculation costs something. Inline SMTP email freezes the checkout submit while the mail server thinks.
7. Bots and abuse. Google's own crawl docs say faceted-navigation URLs tend to "cost sites large amounts of computing resources" (Google); every query-string permutation is uncached on first hit - a distinct cache variant on some hosts, a straight bypass on others (WordPress VIP docs). Put together (my synthesis of the two), a crawler wave on filtered category pages is a raw-PHP flood. Card-testing fraud hammers checkout directly: Stripe warns it "can overload your infrastructure" (Stripe docs); Woo 9.6+ ships rate limiting for this, off by default. And sometimes "slow" just means "hacked" - Sucuri lists sluggishness among infection symptoms; server-side cryptominers eat your server, browser-side miners your visitor's device.
8. The legacy scar tissue. These bite stores running old versions, broken cron, or plugins that bypass core protections; modern core has closed most of them, with dates. Pre-HPOS orders in postmeta: Woo itself calls the postmeta model a performance issue (HPOS docs), and meta_value queries force row scans (VIP docs); HPOS is default for new stores since Woo 8.2, existing stores must opt in. Cart-fragments-everywhere ended in Woo 7.8. Expired transients: core deletes them daily since WP 4.9. Sessions tables: retention capped at 30 days since Woo 10.1. Action Scheduler self-cleanup: AS 4.0. Attribute filtering: lookup table default-on for new installs since WC 6.3; older stores may need to enable and backfill it. The tail is the leg-table causes I concede to the standard checklists - one line each, no apology. No CDN or a server far from your customers is a fixed latency tax on every network leg; render-blocking JS and CSS, unoptimized images, and web fonts each stretch the browser leg, worse on a cheap phone with a heavy DOM.
The case against this ranking deserves its say. The front-end camp (DebugBear and others) notes TTFB is often a minority of LCP on healthy sites; one agency insists "it's almost always the database"; another blames a single bad plugin for 1-3 s. All three are right about the cases they see, and the standard checklist fixes most constant slowness. The objection that checkout buyers will tolerate more delay - buyers at checkout have already decided, so seconds matter least there - cuts the other way under dollar-weighting: patience survives a slow checkout, not a hung one, and a lost checkout costs the whole order, a lost browse costs a pageview. I'll commit anyway: generic lists explain constant slowness on cacheable pages; they systematically fail on intermittent, checkout-specific, and sudden-onset slowness, exactly where the checklist leaves you stranded.
If your store is slow all the time, everywhere, run the standard checklist first; it will probably work. This article is for when it didn't.
So the last useful step is turning your pattern into a shortlist of suspects.

Your symptom pattern names the suspects
First split: slow for customers, or slow for you? wp-admin crawling while the storefront runs fine is a diagnostic gift - it usually points at backend work (Action Scheduler backlog, autoload, plugin-heavy admin queries) and costs you time rather than revenue. The four patterns below map the buyer's path; each yields suspects plus the observable that confirms or clears them.
Always slow, everywhere - cache, runtime, autoload, or front-end weight → cache absent or defeated · autoload bloat · old PHP, no opcache · front-end weight. Check: TTFB on a logged-out repeat view (a working cache answers in tens of ms) · Site Health's autoload flag · the PHP version in your hosting panel.
Randomly slow, correlates with nothing you can see - your own schedules, bots, or host contention → check your own scheduled work first (the cheapest check, and the only cause on this list you fully control): backup and scan schedules, WP-Cron and Action Scheduler pileups · then bot waves · then host contention. Check, in that order: plugin schedules against the slowness times · access logs for crawler bursts on faceted URLs · host resource graphs, 508 errors in cPanel, st on a VPS.
Slow on specific pages - faceted filtering, page builders, or pre-HPOS postmeta → faceted category pages (filtering + bots) · page-builder-heavy pages · postmeta-heavy pre-HPOS views. Check: which URLs exactly · query-string variants in the logs · your Woo version and HPOS status.
Slow at checkout or cart only - APIs, the raw-PHP floor, or abuse → third-party APIs · the tier-1 floor (cart and checkout uncacheable by Woo core design) working as designed · card-testing · sessions/Action Scheduler load. Check: gateway and shipping status pages · failed-order spikes at odd hours · sessions table size.
Naming suspects is hypothesis generation; convicting one takes measurement - a separate and shorter job than most owners expect.
The cache answers your window-shoppers in a tenth of a second; your money pages never get that shortcut, and on cheap hosting they run on a capped, contested slice. Every tenth of a second there matters - run the scenario on your own numbers.
Key takeaways
- In a 30M-session study, 0.1 s coincided with an 8.4% conversion swing (Deloitte, 2020, correlational). Speed is a revenue line; the number is a direction and a ceiling, never a meter.
- The critical-path legs add up - find your biggest leg before buying any fix, and weigh it in dollars, not pageviews.
- Cart, checkout, and account bypass any correctly configured page cache on every host, by Woo core design; bypass hosts extend that to every page a cart-holder views. Cache the rest, fetch the cart client-side, exclude the money pages plus personalized routes.
- Intermittent slowness on cheap hosting that correlates with nothing you can see points at a capped, contested server slice - your own limits (which follow your load) or the neighbors' (which needn't), near-identical from inside. The most neglected cause: 0 of 11 top guides teach it.
- 2 PHP workers on Kinsta's entry plan ≈ 2-3 uncached requests/second in theory; queues form earlier. A few cart-holders plus one bot wave is a queue.
Next in the series: "The 20-minute WooCommerce speed audit" - measurement, so these suspects can face evidence.
Where the numbers come from
All sources accessed July 2026. Volatile figures (hosting prices, plan specs) are stated "as of July 2026"; version-gated behavior is stamped inline (Woo 7.8, 8.2, 9.6, 10.1, AS 4.0, WP 4.9, WP 6.6, WC 6.3).
- Deloitte / Google, "Milliseconds Make Millions" (2020) - 0.1 s ↔ +8.4% conversions, +9.2% AOV; 37 brands, ~30M sessions; correlational, 2019 data. Summary: web.dev case study.
- web.dev - Optimize LCP (additive sub-parts) · web.dev - TTFB (good ≤0.8 s, poor >1.8 s).
- HTTP Archive Web Almanac 2024 - Performance - TTFB share of LCP (~45-53% at p75).
- WooCommerce source - class-wc-cache-helper.php (
prevent_caching()on cart/checkout/account). - WP Engine - WooCommerce support (site-wide cookie bypass) · LiteSpeed - LSCache docs (recommended ESI setup).
- Woo dev blog - cart fragments best practices (2023) · Woo dev advisory - sessions & cron in 10.1 (2025) · Woo dev blog - Action Scheduler changes (June 2026) · Woo HPOS docs.
- WordPress Plugin Handbook - Cron ·
wp_load_alloptions()reference ·save_postreference · WP 6.6 Site Health autoload threshold: Make WordPress Core - Options API: disabling autoload for large options (WP 6.6). - Kinsta - PHP workers/threads (2 workers on Kinsta's entry plan; cached content bypasses workers; other hosts' counts largely unpublished) · Kinsta - PHP benchmarks (Woo 7.4→8.2 ≈ +23% throughput).
- Red Hat - steal time definition, RHEL 6 Virtualization Guide §14.4 · CloudLinux - LVE limits · Netflix Tech Blog - noisy neighbor detection with eBPF (131 ms p99, existence proof).
- Google Search docs - faceted navigation · WordPress VIP - query-parameter caching · WordPress VIP - querying on meta_value.
- Stripe - card testing · stripe-php SDK - CurlClient.php (80 s default timeout).
- Typicals: Littledata store benchmarks - add-to-cart rate (add-to-cart 4.6-6% jointly with Dynamic Yield's 6.07%; conversion 1.4-2% small-store) · Baymard Institute - cart-abandonment meta-analysis (70.2%).
- Hosting price split ($3-11 shared vs $25-35 managed entry): Hostinger, Bluehost, Kinsta, WP Engine public pricing pages, as of July 2026.
- Wordfence - scan scheduling (recommends scanning 8 PM-5 AM, outside peak hours) · Sucuri - what is cryptocurrency mining malware (sluggishness as infection symptom; server-side vs browser-side miners).
- "0 of 11": my own audit of the 11 top-ranking "speed up WooCommerce" guides (WooCommerce.com, Kinsta, WP Rocket, WP Engine, WPBeginner, and six others), July 2026 - used as positioning, never as prevalence evidence.
- Cached ~10-100 ms vs uncached 600-900 ms render bands: practitioner consensus, labeled as such in text; no single primary source exists.






Leave a Reply