WooCommerce Performance Checklist — Make Your Store Twice as Fast
A no-fluff list of the changes that actually move WooCommerce Core Web Vitals — ranked by impact, not by clickbait.
Most "WooCommerce speed" articles are a mix of cargo-cult advice and "just install WP Rocket". The list below is what we actually do, in the order we do it, when a client tells us their store is slow. Numbers come from real audits across about 40 stores in the past 18 months.
0. Measure first
Run Lighthouse on three pages:
- The homepage
- One product page (your top seller)
- The cart
Record LCP, INP, CLS, and Total Blocking Time. Without these numbers you cannot tell if any of the following actions helped.
1. Switch the cart and checkout to the WooCommerce blocks (≈ 30% LCP improvement)
The old shortcode-based cart and checkout were rewritten as blocks years ago, but a surprising number of stores have not migrated. The block versions skip a lot of jQuery, defer non-critical scripts, and reduce TTFB on the checkout by about 200ms in our benchmarks.
// in your theme's functions.php — block-based by default in new installs
add_filter('woocommerce_use_blocks_cart_checkout', '__return_true');
Then in the admin: Pages → Cart → switch the content from [woocommerce_cart] to the Cart block. Same for Checkout.
2. Optimise product images at upload (≈ 20% LCP improvement on product pages)
Product images are the LCP element on 80% of product pages. If you ship a 4000×4000 PNG, even WP's automatic resize cannot save you because the original is what srcset references for high-DPI.
The combo we use:
- Upload no larger than 2000×2000.
- Force AVIF + WebP at upload (ShortPixel or Imagify, on the
wp_handle_uploadfilter). - Set max image width to 1600 in Settings → Media.
- Lazy-load all but the LCP image. WordPress does this automatically since 5.5 — but the LCP image needs
fetchpriority="high", which most themes do not set. Block themes that follow current WP standards do. Older shortcode themes often don't.
3. Replace ?add-to-cart= with the AJAX endpoint (≈ 1.5s perceived speed)
The old query-param ?add-to-cart=123 triggers a full page reload. The AJAX endpoint added in WC 8 keeps users on the product page and shows a mini-cart slide-in. It is on by default in new stores but disabled in many legacy ones:
WooCommerce → Settings → Products → AJAX add to cart on archives
This is one of the highest-impact, lowest-effort changes you can make.
4. Disable cart fragments on non-cart pages (≈ 200ms TTFB)
The wc-cart-fragments script makes an AJAX call on every page load just to update the mini-cart count. If your mini-cart is only visible on certain pages, you can skip the script everywhere else:
add_action('wp_enqueue_scripts', function () {
if (! is_woocommerce() && ! is_cart()) {
wp_dequeue_script('wc-cart-fragments');
}
}, 11);
5. Use object caching (≈ 40% query reduction)
WooCommerce makes hundreds of database queries per page on busy stores. Redis or Memcached caches them in memory. On managed hosts (Kinsta, WP Engine, Pressable) it is on by default; on a raw VPS you install it yourself:
sudo apt install redis-server php8.4-redis
wp plugin install redis-cache --activate
wp redis enable
Then verify with WooCommerce → Status → Tools → Redis status.
6. Defer non-essential JS (≈ 50% TBT reduction)
WooCommerce stacks: Stripe, Klaviyo, Google Tag Manager, Hotjar, a chat widget, an email-popup, a review plugin. Each adds 50–200ms of TBT. The fix is not to remove them — the marketing team will revolt — but to defer them past LCP:
add_filter('script_loader_tag', function ($tag, $handle) {
$defer = ['klaviyo', 'hotjar', 'gtm-js', 'tawk', 'crisp'];
foreach ($defer as $h) {
if (str_contains($handle, $h)) {
return str_replace(' src=', ' defer src=', $tag);
}
}
return $tag;
}, 10, 2);
For chat widgets specifically, use the requestIdleCallback pattern — load the widget only when the browser is idle.
7. Trim WooCommerce admin AJAX
The WC admin polls admin-ajax.php for stock updates, order counts, and Marketing Hub data. On a store with many concurrent admins, this can spike the database. Disable the Marketing Hub on stores that do not use it:
add_filter('woocommerce_admin_features', function ($features) {
return array_diff($features, ['marketing']);
});
8. Use a CDN — but be careful about the cart
Cloudflare's free tier handles 90% of WooCommerce sites. Set up a page rule to bypass cache on:
/cart/*/checkout/*/my-account/*/wp-admin/*- Any URL with
add-to-cartin the query string
If you skip this, you will get the famous "everyone sees the same cart" bug.
9. Move heavy reports off the main DB
WooCommerce Analytics tables (wc_order_stats, wc_order_product_lookup) bloat fast. After your first holiday season, an analytics query can lock the orders table for seconds. Solutions:
- Easiest: Schedule analytics regeneration during off-hours.
- Better: Move analytics to a read replica.
- Best: Disable WC Analytics and use a dedicated tool like Glew or Polar Analytics that pulls from the API.
10. Audit your themes and templates
The theme is the single biggest variable. A WooCommerce theme that ships every product block on every page even when the page is a blog post will tank your scores. Test in the order: child theme of a fast theme → faster theme → custom child of Storefront → audited custom theme.
Our themes ship under 50KB of CSS by default and lazy-load all WC-specific JS. If you are starting fresh, that is a defensible baseline.
What you should NOT do
- Don't install three caching plugins. They conflict. Pick one (WP Rocket, LiteSpeed Cache, or W3 Total Cache) and tune it carefully.
- Don't disable cart fragments globally on stores that show the cart count in the header. You will lose updates.
- Don't lazy-load the LCP image. That breaks fetchpriority and slows things down.
- Don't bother with "image optimization" plugins that compress to JPG. AVIF/WebP win in every test we have run.
Realistic expectations
Following all ten steps, on a typical WooCommerce store with 500 products and 5k orders per month, we usually see:
- LCP: from 4.2s to 1.9s
- INP: from 380ms to 110ms
- CLS: from 0.18 to 0.04
- Lighthouse mobile: from 38 to 87
You will not hit 100. Anyone who tells you they get 100 on a real WooCommerce store with marketing pixels and a chat widget is either lying or testing with the network throttled to "fast 4G" — Google measures on slow 4G.
87 is enough to pass Core Web Vitals. Pass Core Web Vitals, get your conversion rate back, move on with your business.