Measure a slow WooCommerce store before you buy a plugin
A caching plugin speeds up the home page and leaves the cart and checkout as slow as before. What to measure, and the five causes that come up most.

The cart page cannot be cached. Neither can the checkout, the account page, or any page for a customer with something in their cart. Those are the pages where a slow store loses orders, and they are the pages a caching plugin does nothing for.
So a store that installs a caching plugin, sees the home page score jump, and calls the problem solved has fixed the page that was not losing money and left the ones that were. Measuring first avoids that.
TLDR
Measure the product page, the cart and the checkout, not the home page, with field data from real visitors where you can get it. Then find the cause with Query Monitor before installing anything. The five causes that come up most: a plugin loading its assets on every page, cart fragments, a slow query from a plugin, oversized images, and hosting with a slow time to first byte.
Measure the right pages
PageSpeed Insights shows two things: field data from Chrome users who visited your store in the last 28 days, and a lab test run on the spot. The field data is the truth. The lab test is a hint. If your store has enough traffic to show field data, look at that first, and look at it for a product URL, not the home page.
The three numbers that matter are the Core Web Vitals: Largest Contentful Paint under 2.5 seconds, Interaction to Next Paint under 200 milliseconds, and Cumulative Layout Shift under 0.1. A store failing LCP on product pages is losing customers who left before the image loaded. A store failing INP is losing the ones who tapped “Add to cart” and nothing happened for a second.
Then the pages the tools cannot see. Log in as a customer, put something in the cart, and time the cart and checkout pages in the browser’s network panel. Time to first byte on those pages is the server doing real work, and no front-end plugin changes it.
Find the cause before you fix it
Install Query Monitor on staging. It shows, for the page you are on, every database query with its time and the plugin that ran it, every script and stylesheet with where it came from, and every hook that took real time. Ten minutes with it answers the question that three speed plugins were guessing at.
Load the product page and read the three panels in order: queries sorted by time, scripts and styles sorted by source, and the PHP time by component. The cause is usually at the top of one of them.
The five causes that keep coming back
A plugin loading everything everywhere. A form plugin, a slider, an icon pack or a page builder add-on that enqueues its CSS and JavaScript on every page, including product pages that never use it. Query Monitor’s scripts panel shows it. The fix is a small snippet that dequeues the assets where they are not needed, or replacing the plugin.
Cart fragments. WooCommerce refreshes the mini cart with an AJAX call to wc-ajax=get_refreshed_fragments after every page load, so the header shows the right count. On a store with a heavy theme, that call takes a full second of server time on every page. If the header has no mini cart, disable the fragments script. If it does, make sure the call is cheap.
A slow query from one plugin. A related-products plugin running an unindexed query, a stock-sync plugin checking every product on page load, an analytics plugin writing to the database on every request. Query Monitor puts the plugin name next to the query. Some of these are a setting. Some are a replacement. Some are a rewrite, and the rewrite is a feature sprint.
Images. A product gallery with 4,000 pixel originals served to a 400 pixel slot is the most common LCP failure and the cheapest to fix. WordPress generates sizes; the theme has to ask for them with srcset, and the images need to be compressed on upload. A block theme does this. Many older themes do not.
Hosting. Time to first byte over 600 milliseconds on a plain page with caching off, measured from a server near your customers, is the host, not the store. Cheap shared hosting for a store doing real volume is a false economy. A managed WordPress host with PHP 8.3 and an object cache fixes it, and nothing you do in the plugin list will.
A worked pass with Query Monitor
Take a store with a product page scoring 38 on mobile in PageSpeed Insights and a cart page that takes two seconds to open. Log in to staging with Query Monitor active and open a product page. The admin bar shows the page took 1.9 seconds of PHP and ran 212 database queries.
Queries by time. The top entry is a single query taking 640 milliseconds, from a related-products plugin, selecting every product with a matching tag and sorting by a meta value. No index on the meta key, so MySQL scans the table. That one plugin is a third of the page time, on every product page. The fix is either its own setting to limit candidates, or replacing it with the WooCommerce related products block, which uses a cached query.
Scripts and styles by source. Nine stylesheets and eleven scripts, and four of each come from a form plugin the store uses on one contact page. They load on every page. That is 140 kilobytes of CSS and JavaScript the product page downloads and never uses.
PHP by component. The theme is 400 milliseconds, which is high for a theme, and the breakdown shows a mega menu rendering every category with its product count on each page load, uncached.
Three findings, none of which a caching plugin would have shown, and none of which a caching plugin would have fixed on the cart page.
Fixes in order of cost
| Finding | Fix | Effort |
|---|---|---|
| A plugin loading assets everywhere | Dequeue where unused | An hour, one snippet |
| A slow query from one plugin | Plugin setting, replacement, or a rewrite | An hour to a sprint |
| Oversized images | Compress on upload, serve responsive sizes, lazy load below the fold | A day with an image plugin, or free with a block theme |
| Cart fragments on a store without a mini cart | Disable the fragments script | Ten minutes |
| Uncached theme work on every load | Cache the fragment with a transient or an object cache | A few hours |
| Slow time to first byte | Move hosting, add PHP 8.3 and an object cache | A day, and a monthly cost |
The dequeue snippet for the form plugin, in a small plugin of its own rather than the theme:
add_action( 'wp_enqueue_scripts', function () {
if ( is_page( 'contact' ) ) {
return;
}
wp_dequeue_style( 'forms-plugin-css' );
wp_dequeue_script( 'forms-plugin-js' );
}, 100 );
The handle names come from Query Monitor’s scripts panel, which lists them. Priority 100 runs the dequeue after the plugin’s own enqueue, which is the detail that makes it work.
Cart fragments deserve their own note because the advice online is wrong half the time. The wc-cart-fragments script calls wc-ajax=get_refreshed_fragments so that a cached page can still show a correct mini cart count. On a store whose header has no mini cart, the call does nothing useful and can be dequeued the same way. On a store with a mini cart, dequeueing it makes the count wrong on cached pages, and the right fix is to make the call cheap, which usually means fixing the theme work above rather than the fragments themselves.
Testing the checkout, not the home page
Interaction to Next Paint is the metric that catches a slow checkout, and it needs real interactions to measure. On staging, open the checkout with the browser’s performance panel recording, change the shipping country, apply a coupon, and change the payment method. Each of those triggers a server call and a re-render. Anything over 200 milliseconds from click to visible update is a failing interaction, and the panel shows whether the time went to the server or to JavaScript on the page.
The common server cause is a shipping or tax plugin recalculating on every keystroke in the address fields. The common JavaScript cause is a payment gateway loading its whole SDK at page load rather than when its method is selected. Both are fixes in the plugin’s settings or a support ticket to the plugin’s developer, and both are invisible to any home page score.
Then, and only then, cache
With the causes fixed, a page cache makes anonymous product and category pages fast for free, and an object cache such as Redis makes the pages that cannot be cached faster by keeping repeated queries in memory. That order matters. Caching a slow store hides the problem for logged-out visitors and leaves every customer with a cart exactly where they were.
If the numbers on your product page are red and Query Monitor is unfamiliar, the store and code audit does this measurement for you and hands back a list ordered by what it will cost against what it will gain.
Questions
Which speed plugin do you recommend?
None until the cause is known. Most stores that come to us with three speed plugins installed have a slow database query or a plugin loading on every page. The speed plugins are hiding it on cached pages and doing nothing on the rest.
Is it the hosting?
Sometimes. A server time to first byte over 600 milliseconds on a plain page with caching off usually is. Under 300 milliseconds and the hosting is fine; look at the plugins and the theme.
Read these next
Same kind of problem, different corner of the store.

Block theme or page builder for a new WooCommerce store
Page builders are how most WooCommerce stores got slow. A block theme keeps the layout in the editor WordPress already has. Where each one wins.
WooCommerce
Check old plugins for HPOS before an update breaks the store
HPOS moved orders out of the posts table. Old plugins that read orders as posts fail without an error. How to find them and what a fix involves.
WooCommerce
Add custom fields to the WooCommerce block checkout
The old checkout field filters do nothing on the block checkout. The Additional Checkout Fields API does. Code, limits, and when to go further.
WooCommerce