While defer JavaScript pushes the script to the bottom of the page load, you can instead delay JavaScript based on user interaction. This can be a great way to significantly speed up the paint of the page for Google Lighthouse when something isn’t needed right away. Especially heavy third-party scripts like Google Adsense, Google Analytics, conversion pixels (FB, Google Ads), etc.
Delaying JavaScript has a big impact on Largest Contentful Paint (LCP) and can help you fix the “Reduce unused JavaScript” warning in Google PageSpeed Insights. It will decrease your Total Blocking Time (TBT) and help fix the “Reduce the impact of third-party code” and “Reduce JavaScript execution time” warnings.
It also works great for things like cart fragments which is a common WooCommerce performance issue due to the fact that the AJAX request can’t be cached. You can also use it with our local analytics feature and Instant Page.
Delay JavaScript
Follow the steps below to delay JavaScript with Perfmatters. This should work with a script tag with either the type='javascript'
or no type.
Step 1
Click into the Perfmatters plugin settings.
Step 2
Click on the “Assets” submenu.
Step 3
Under the “JavaScript” section, toggle on “Delay JavaScript.”
Step 4
Then proceed to choose your Delay behavior.
Delay behavior
There are two different methods you can choose from to delay JavaScript:
1. Only delay specified scripts
Delay specific JavaScript files by adding the source URL (example.js
), or delay an inline script by adding a unique string from that script. Format: one per line. See examples.
2. Delay all scripts
The delay all scripts feature will attempt to delay all JavaScript, including inline. This is by far the most aggressive option. You can then exclude scripts if needed.
Excluded from delay
Exclude specific JavaScript files from delay by adding the source URL (example.js
), or exclude an inline script by adding a unique string from that script. Format: one per line.
You can also use quick exclusions when available or exclude an individual post/page from delay.
Delay timeout
With both delay behavior options, you can toggle on a timeout that will automatically load scripts after 10 seconds if no user interaction has been detected. This is optional and off by default.
Here are a few examples of why you might want to enable a timeout:
- Help improve data accuracy of tracking scripts, especially if you have a goal associated with a pageview, but maybe no user interaction. You want the goal to trigger still.
- You have a Google AdSense blog, and a user is opening up multiple pages in new tabs in the background. You still want the ads to fire off.
If you want to set a different delay timeout value, you can use the perfmatters_delay_js_timeout
filter.
Examples of scripts you can delay
Below are some examples of common scripts we delay on WordPress sites when using the Only Delay Specified Scripts behavior.
Delay Google Analytics
To delay Google Analytics, add the following to the “Delay JavaScript” box.
ga( ' ga(' google-analytics.com/analytics.js
If you’re using our local analytics, you can also delay the scripts.
Local Perfmatters analytics.js
To delay the local Perfmatters analytics.js script, add the following to the “Delay JavaScript” box.
analytics.js
Local Perfmatters gtag.js v4
To delay the local Perfmatters gtag.js v4 script, add the following to the “Delay JavaScript” box.
gtagv4.js
Local Perfmatters Minimal
To delay the local Perfmatters analytics-minimal.js script, add the following to the “Delay JavaScript” box.
analytics-minimal.js
Delay Google Tag Manager
To delay Google Tag Manager, add the following to the “Delay JavaScript” box.
/gtm.js /gtag/js gtag( /gtm- /gtm.
Google Adsense
To delay Google AdSense, add the following to the “Delay JavaScript” box.
adsbygoogle.js
If you’re using a plugin like Ad Inserter, along with HTML insertion blocks, you’ll want to delay both the script and the inline portion.
adsbygoogle.js ai_insert_code
Delay Facebook Pixel
To delay the Facebook Pixel, add the following to the “Delay JavaScript” box.
fbevents.js fbq( /busting/facebook-tracking/
Above are just a few of the many examples of scripts you can disable. If you are having any trouble delaying a certain script, feel free to contact us.
How to exclude delayed scripts
If you’re using the Delay All JavaScript feature, there are three different ways to exclude scripts.
- Option 1: Add scripts to the Excluded from Delay box.
- Option 2: Use Quick Exclusions when available.
- Option 3: Exclude an individual post/page from delay.
Quick exclusions
JavaScript exclusions can sometimes be tricky to track down. When using the Delay All Scripts option, quick exclusions will appear when certain popular plugins and themes are activated. This allows you to more easily apply exclusions based on our predefined list of common exclusions.
We are continuously improving the quick exclusions feature, along with the plugins and themes that are available.
How to exclude a page/post from delay
You can exclude JavaScript delay on an individual post, page, or custom post type. In the editor, on the right-hand side uncheck “Delay JavaScript.” This will exclude the entire page from delay. This can be useful for say a contact us page that might have more issues than the rest of the site. Note: You must be an administrator to see the meta options.
Keep in mind that we automatically exclude specific URLs from optimizations when running WooCommerce (cart, checkout, account) for compatibility reasons. The Perfmatters meta box will not be visible when editing these pages.
Common JS delay exclusions
When using the Delay all scripts option in Perfmatters, you might need to add an exclusion or two. The number is typically based on the complexity of the site. For example, a site using a heavy page builder like Elementor will most likely need more exclusions than a lightweight site using GeneratePress.
Below are some common exclusions we typically see. We’ll make sure to keep adding to this list as we improve the feature.
Astra mobile menu
jquery.min.js
astra
Atarim
/atarim-client-interface/
jQuery_WPF
upgrade_url
jquery.min.js
Avada sticky header
avada-header.js
modernizr.js
jquery.easing.js
avadaHeaderVars
Borlabs Cookie
/wp-content/plugins/borlabs-cookie/
borlabs-cookie
BorlabsCookie
jquery.min.js
Bricks slider
/wp-content/themes/bricks/assets/js/libs/swiper.min.js
/wp-content/themes/bricks/assets/js/bricks.min.js
bricks-scripts-js-extra
Calculated Fields Form
jquery.min.js
/wp-content/plugins/calculated-fields-form/
cp_calculatedfields
Complianz
complianz
Cookiebot
consent.cookiebot.com
CookieYes
/wp-content/plugins/cookie-law-info/legacy/public/js/cookie-law-info-public.js cookie-law-info-js-extra jquery.min.js
Cookie Notice & Compliance for GDPR
/wp-content/plugins/cookie-notice/js/front.min.js
cnArgs
Divi
jquery.min.js
/Divi/js/scripts.min.js
et_pb_custom
elm.style.display
Divi with animations
If you’re using animations with Divi, you might need the following.
jquery.min.js
jquery-migrate.min.js
.dipi_preloader_wrapper_outer
/Divi/js/scripts.min.js
/Divi/js/custom.unified.js
/js/magnific-popup.js
et_pb_custom
et_animation_data
var DIVI
elm.style.display
easypiechart.js
Elementor
This might vary slightly based on the elements and templates you’re using in Elementor. If you’re not using a lot of animations, you might not need any exclusions for Elementor at all.
jquery.min.js
jquery.smartmenus.min.js
jquery.sticky.min.js
webpack.runtime.min.js
webpack-pro.runtime.min.js
/elementor/assets/js/frontend.min.js
/elementor-pro/assets/js/frontend.min.js
frontend-modules.min.js
elements-handlers.min.js
elementorFrontendConfig
ElementorProFrontendConfig
imagesloaded.min.js
Elementor search
webpack-pro.runtime.min.js
webpack.runtime.min.js
elements-handlers.min.js
jquery.smartmenus.min.js
Elementor table of contents widget
Make sure you also enable the main Elementor quick exclusion.
/wp-includes/js/dist/hooks.min.js
/wp-includes/js/dist/i18n.min.js
/wp-content/plugins/elementor/assets/lib/waypoints/waypoints.min.js
Fluent Forms (with Cloudflare Turnstile)
/wp-content/plugins/fluentform/
fluentForm
turnstile
Make sure to also exclude turnstile
from Defer JS.
GeneratePress masonry blog
generateBlog
scripts.min.js
masonry.min.js
imagesloaded.min.js
GeneratePress mobile menu
/generatepress/assets/js/menu.min.js
generatepressMenu
GeneratePress mobile popup menu
/generatepress/assets/js/menu.min.js
generatepressMenu
offside.min.js
offSide
GDPR Cookie Compliance
/wp-content/plugins/gdpr-cookie-compliance/ moove_gdpr jquery.min.js
Gravity Forms
/wp-includes/js/jquery/jquery.min.js
recaptcha
/gravityforms/
gform
/wp-includes/js/plupload/plupload.min.js
/wp-includes/js/plupload/moxie.min.js
/wp-includes/js/jquery/jquery-migrate.min.js
/gravityforms/js/conditional_logic.min.js
jquery-ui-datepicker-js
jquery-ui-datepicker-js-after
JetMenu
jquery.min.js jquery-migrate.min.js /elementor-pro/ /elementor/ /jet-blog/assets/js/lib/slick/slick.min.js /jet-elements/ /jet-menu/ elementorFrontendConfig ElementorProFrontendConfig hasJetBlogPlaylist JetEngineSettings jetMenuPublicSettings
Lightweight Cookie Notice
/wp-content/lightweight-cookie-notice-free/public/assets/js/production/general.js
daextlwcnf-general-js-after
daextlwcnf-general-js-extra
cookieNotice
Lottie animations
jquery.min.js jquery-migrate.min.js window.scopes_array lottie.min.js
Mediavine
mediavine
Motion.page
/motionpage/
MOTIONPAGE
gsap
body{visibility:inherit;}
body.style.visibility
Newspaper
jquery.min.js
jquery-migrate.min.js
tagdiv_theme.min.js
tdBlocksArray
Ninja Forms
/wp-includes/js/underscore.min.js
/wp-includes/js/backbone.min.js
/ninja-forms/assets/js/min/front-end-deps.js
/ninja-forms/assets/js/min/front-end.js
nfForms
nf-
jquery.min.js
OceanWP mobile menu
drop-down-mobile-menu.min.js
oceanwpLocalize
Oxygen Builder
jquery.min.js
aos.js
oxygen-aos-enabled
Presto Player
/presto-player/dist/components/web-components/web-components.esm.js
/presto-player/src/player/player-static.js
var player
/wp-includes/js/dist/vendor/regenerator-runtime.min.js
/wp-includes/js/dist/api-fetch.min.js
/wp-includes/js/dist/hooks.min.js
/wp-includes/js/dist/i18n.min.js
Raptive (previously AdThrive)
adthrive
ads.min.js
adthrive.min.js
Real Cookie Banner
/wp-content/plugins/vendor-banner.pro.js /wp-content/plugins/banner.pro.js realCookieBanner real-cookie-banner-pro-banner-js-before
Revolution Slider
jquery.min.js
jquery-migrate.min.js
revslider
rev_slider
setREVStartSize
window.RS_MODULES
Sahifa
/themes/
tie-scripts
jquery.min.js
Salient
jquery.min.js
jquery-migrate.min.js
/salient/
/salient-nectar-slider/js/nectar-slider.js
ShortPixel Adaptive Images
shortpixel.ai/assets/js/bundles/spai-lib
Slider Pro
/wp-content/plugins/sliderpro/public/assets/js/jquery.sliderPro.min.js
SliderPro
Smart Slider
/smart-slider-3/
_N2
Smart Slider Pro
/nextend-smart-slider3-pro/
_N2
SureCart
jquery.min.js
surecart
hooks.min.js
i18n.min.js
Termageddon + Usercentrics
jquery.min.js
termageddon
usercentrics
UC_UI
WooCommerce single product gallery
jquery.min.js
flexslider
single-product.min.js
slick
functions.min.js
waypoint
wpDiscuz
/wp-content/plugins/wpdiscuz/
wpdiscuzAjaxObj
wpdiscuzEditorOptions
wpdiscuzUCObj
jquery.min.js
WP Grid Builder
wpgb
WS Form
jquery.min.js
jquery/ui
ws-form
wsf-wp-footer
quicktags-js-extra
Delay inline JavaScript
To delay inline JavaScript, enter a partial string that is within the <script type="text/javascript"> </script>
tag.
For example, say we have this inline JavaScript.
<script type="text/javascript">var lazyLoadInstance=new LazyLoad({elements_selector:"[loading=lazy],.perfmatters-lazy",thresholds:"200% 0px"});</script>
We can add lazyLoadInstance
to the “Delay JavaScript” box and it will delay it. You can choose any string within the script tags, just make sure it’s unique.
For some JavaScript, they might have a source file as well as an inline component. In this case, you will need to delay both for it to work properly.
How to filter delayed scripts
You can use the perfmatters_delayed_scripts
filter to manipulate your delayed scripts. For example, you could exclude a script from being delayed on a desktop device.
add_filter('perfmatters_delayed_scripts', function($scripts) {
if(($key = array_search('name_of_your_script', $scripts)) !== false) {
if(!wp_is_mobile()) {
unset($scripts[$key]);
}
}
return $scripts;
});
You can use the perfmatters_delay_js
filter to turn your delayed scripts on or off entirely. For example, you could turn off delay only on pages.
add_filter('perfmatters_delay_js', function($delay) {
if(is_singular('page')) {
return false;
}
return $delay;
});
See additional filters.
Delay versus Defer
Defer will push the JavaScript to the bottom of the page load. This helps resolve render-blocking issues. However, the JavaScript still has to load when the page is rendered. In other words, it will still play an impact on your Core Web Vital scores when it comes to JavaScript execution time, transfer sizes, etc.
Delay removes the JavaScript from the waterfall/page load altogether. If you run a speed test, it will appear as if those scripts don’t exist. They do, but instead of loading on page load, they load on user interaction (moving mouse, scrolling, timer, etc.) This helps improve your Core Web Vital scores and improves the first contentful paint (FCP).
Regarding compatibility, defer is a practice that has been around for a long time. It’s usually safe to defer everything, which is what the Defer JavaScript feature in Perfmatters does. And then we have the exclusions box for cases where a script might need to be excluded due to load order.
Delay is a little trickier, as you can’t just delay every JavaScript file. Due to loading on interaction, it will only work on specific scripts. This can be a little trial and error, but the benefit of delay is that it’s very powerful! It has a massive impact on each script you use it on.
The good news is, you can use both delay and defer simultaneously. If both are applied to the same JavaScript file, delay will always take precedence, and defer is essentially then a fallback. If you delay all of your JavaScript, defer can still be useful as you might have delay exclusions, which would then use defer.
Troubleshooting delay
There are a few things to keep in mind when using delay, especially how it impacts certain scripts.
Turn off combine/compilers
For Delay JavaScript to work properly in Perfmatters, you need to turn off any feature from third-party plugins that combine your JavaScript files. Combining JavaScript is a deprecated optimization technique since HTTP/2 (now HTTP/3) anyways. It’s now faster to load individual files in parallel.
- If you’re using Autoptimize, LiteSpeed, WP Rocket, etc., turn off JavaScript combine.
- If you’re using Avada, turn off the JS Compiler feature.
Google Analytics
For example, with Google Analytics, you might see slightly lower stats if they’re delayed. That’s because the script is now loading on user interaction. However, this isn’t necessarily a bad thing. Google doesn’t filter out all of the bots or spam, so if you delay Google Analytics, along with the delay timeout feature, it might improve your data as it now narrows it down to actual users.
Bounce rate measurements might also fluctuate if you delay Google Analytics.
How to fix double-click on mobile menu
If your mobile menu isn’t working on the first click, you probably need to add an exclusion for the JavaScript that is powering it. See our common exclusions.
How to disable click delay
The click delay might be longer than desired if you have a large and complex site with a lot of JavaScript. Take a mobile menu, for example. Based on how your theme or page builder is coded, it might have to wait for all of the JavaScript to load before it opens. Therefore, disabling the click delay can help speed things up and prevent it from having a negative impact on Interaction to Next Paint (INP).
Note: This assumes you already have the correct JS delay exclusions in place.
Step 1
Toggle on “Show Advanced Options” in Perfmatters.
Step 2
In the JavaScript section of Perfmatters, scroll down and toggle on “Disable Click Delay.”
Step 3
Scroll down and click “Save Changes.”
How to fix double-click in iOS on hyperlinks (FastClick)
There is a known bug on iOS that sometimes occurs when using the Delay JS feature. This bug causes links to not work until they are clicked twice. We hope that iOS will eventually change a few things so that this won’t happen anymore. However, until then, there is a temporary workaround using the FastClick library. Follow the steps below.
Step 1
Toggle on “Show Advanced Options” in Perfmatters.
Step 2
In the JavaScript section of Perfmatters, scroll down and toggle on “Enable FastClick.” This will load the FastClick locally from your site or CDN.
Step 3
Scroll down and click “Save Changes.”
Narrow down exclusions
A quick way to narrow down an issue to a specific script would be to exclude these entire directories temporarily:
/themes/ /plugins/ /wp-includes/
You can then comment them out one by one by adding --
in front, such as in the example below.
--/themes/
/plugins/
/wp-includes/
If you think there might also be inline JS causing an issue, you can exclude all inline JS from delay temporarily using this:
;
{
Make sure to also check out our doc on how to find and fix JavaScript console errors.