Skip to main content

Minify, Defer, Delay

This page is a practical strategy for controlling JavaScript on WordPress sites: reduce unnecessary bytes, move non-critical execution out of the critical rendering path, and keep the main thread calm for good INP. The hard part is avoiding conflicts (double-optimization) and keeping checkout/forms functional.

What Each Technique Does

TechniqueWhat It DoesTypical BenefitTypical Risk
MinifyShrinks JS transfer sizeSmall LCP improvementConflicts when multiple tools minify
DeferRuns scripts after HTML parsingBetter LCP/INP, fewer long tasks earlyBreakage if a script must run before paint
DelayPrevents execution until interaction/timeoutBig INP wins for third-party scriptsBreakage if critical scripts are delayed

Avoid Conflicts (One Tool Owns JS)

Choose one tool to handle JS optimization. If Perfmatters is your primary JS tool:

  • LSCache: disable JS minify/defer/delay features.
  • Cloudflare: disable Rocket Loader and JS Auto Minify.
  • Autoptimize/other optimizers: disable JS optimization features.
caution

Conflicts are the fastest way to ship broken pages. If something breaks after enabling minify/defer/delay, the first step is to disable overlapping JS optimization in other tools.

The exact labels vary by version, but the strategy is consistent:

  • Minify JS: ON
  • Defer JS: ON
  • Delay JS: ON
  • Delay timeout: set a fallback (so delayed scripts still run eventually)

Static vs Dynamic Starting Points

Use these as initial defaults and refine based on real templates.

Static sites (blogs/docs/marketing) - starter exclusions

Static sites can often delay most third-party scripts.

perfmatters-delay-exclusions-static.txt
jquery
recaptcha
grecaptcha
Dynamic sites (WooCommerce/LMS/memberships) - starter exclusions

Dynamic sites need tighter exclusions for cart/checkout/forms/payment flows.

perfmatters-delay-exclusions-dynamic.txt
jquery
wc-add-to-cart
wc-cart
wc-checkout
wc-cart-fragments

recaptcha
grecaptcha

stripe
elements.js
paypal
braintree
klarna

How to Build a Good Exclusion List

  1. Start minimal.
  2. Test one template at a time (home, post, product, cart, checkout).
  3. When something breaks, exclude the script handle/keyword responsible.
  4. Keep notes (why an exclusion exists) so you can revisit it later.

Common categories that often need exclusions:

  • Payments (Stripe/PayPal)
  • Forms + captcha
  • Cart/checkout fragments
  • Theme navigation scripts
  • Video players you expect to work immediately

Testing Workflow

  1. Test logged-out in an incognito window.
  2. Use DevTools Console: errors like $ is not defined usually indicate a dependency was delayed.
  3. Perform real interactions: open mobile menu, add to cart, submit form, checkout.
  4. Re-run Lighthouse/PSI and compare:
    • INP and long tasks
    • total JS bytes
    • main thread time

Common Breakages and Fixes

SymptomLikely CauseFix
Menu/accordion is deadA theme script was delayedExclude that script from Delay
Add-to-cart failsWoo scripts delayedExclude wc-add-to-cart and related handles
Checkout validation failsGateway SDK delayedExclude gateway keywords (stripe/paypal/etc.)
Forms don't submitForm/captcha scripts delayedExclude form plugin + recaptcha/grecaptcha
Analytics misses first pageviewAnalytics delayed too longUse a shorter timeout or do not delay analytics

Optional: Code-Based Defer (Fallback)

If you cannot use Perfmatters in a specific environment, you can add defer to many enqueued scripts.

warning

This is a blunt tool. It can break themes/plugins. Prefer a dedicated optimization plugin and test on staging.

wp-add-defer-to-scripts.php
add_filter('script_loader_tag', function($tag, $handle, $src) {
$exclude = [
'jquery-core',
'jquery-migrate',
'wc-add-to-cart',
];

if (in_array($handle, $exclude, true)) {
return $tag;
}

if (str_contains($tag, ' defer')) {
return $tag;
}

return str_replace(' src', ' defer src', $tag);
}, 10, 3);

What's Next