Automatic JavaScript optimization for WordPress

WP Core Web Vitals defers the scripts on your page, the inline ones too, and runs them in their original order, so your menus and sliders keep working. Analytics, pixels and chat widgets wait until the page has loaded.

WP Core Web Vitals JavaScript settings: defer scripts, safe mode and optimize analytics, pixels and chat widgets

Why does deferring JavaScript break so many WordPress sites?

Adding defer to the script files is the easy part. The trouble is the inline scripts next to them: jQuery(function($){ ... }) from your theme, your plugins' settings objects. An inline script can't be deferred: it runs right away, before the deferred jQuery exists, and you get "jQuery is not defined" and a slider that never starts. WP Core Web Vitals defers the inline scripts too, so jQuery is there before the code that calls it.

Built on the order your scripts were written in

Every script still runs, in the same order, only later: after the HTML is parsed. By default the plugin also moves them to the end of the page, so the browser finds your LCP image, fonts and CSS first. Scripts that have to run exactly where they are, such as an ad with document.write, stay in place. A visitor who taps the menu before the scripts have run doesn't lose that tap: it's played again once they're ready. gtag() events and dataLayer.push calls from before the analytics have loaded are kept and sent when they arrive.

I don't make scripts wait for the first scroll or tap. It wins a Lighthouse score, because Lighthouse never touches the page. A real visitor taps the menu and waits while the browser downloads and runs all of it, and INP reports the slowest tap of the visit. Only a script you give a Hover / Click or Scroll into view rule waits for the visitor.

The JavaScript settings

WP Core Web Vitals JavaScript settings: defer scripts, safe mode and optimize analytics, pixels and chat widgets

Defer scripts

Your text and LCP image can appear without waiting for your scripts (FCP and LCP). The browser downloads the scripts while it reads the page and runs them afterwards, in their original order. That includes the bits of script your theme and plugins write straight into the HTML, so code that needs jQuery still runs after jQuery and your menus and sliders keep working. If one script breaks, give it a Do not optimize rule under Script rules before you turn this off. On

Safe mode

For a page that still breaks after you gave the failing script a Do not optimize rule. Some scripts expect every script above them to have run already, such as an ad with document.write or a script you marked data-no-optimize. Safe mode leaves those scripts where they are, and every script above them too. It applies to every page and defers fewer scripts, so leave it off until a page needs it. Off

Optimize analytics, pixels and chat widgets

Your analytics, pixels and chat widgets wait until the page has loaded and the browser has a quiet moment. Until then they don't compete with your LCP image for the connection or with your own scripts for the browser's time (LCP). A gtag() or dataLayer.push call from before they arrive is kept and sent then, so only a visitor who leaves in the first seconds isn't counted. The plugin knows Google Analytics, Tag Manager, the Meta pixel, Clarity, Hotjar, Matomo, TikTok, LinkedIn, Pinterest, Intercom, Tidio, Crisp, HubSpot, Zendesk and more; for a tracker that isn't on the list, use Also optimize these scripts. On

Fine-tuning

JavaScript fine-tuning: move scripts to the end of the page, scripts to optimize, back/forward cache and script rules
  • Move scripts to the end of the page (On): the deferred scripts move to the end of the page, in the same order, so the browser finds your LCP image and your CSS first and starts downloading them sooner (LCP). That pays off on pages with many scripts. If your pages load only a few, turn it off: the scripts then start loading earlier and are ready sooner.
  • Also optimize these scripts: for scripts nobody needs in the first seconds, such as a slider further down the page or a tracker the plugin doesn't know. They load after the page has loaded, like the analytics, and stay out of your LCP image's way until then (LCP). Enter part of the script's URL or of its inline code, one per line, for example slider.min.js. Scripts that need one you list wait along with it, but jQuery and the other libraries much of your site builds on never wait, even when you list them.
  • Back/forward cache (On): so the back button can show the previous page at once from the browser's back/forward cache, without loading it again. In some browsers a script that listens for unload keeps a page out of that cache. The plugin switches those listeners to pagehide, which also fires when the visitor leaves, so the scripts still do their job. Other things can keep a page out of the cache as well; this setting only takes care of the unload listeners.
  • Script rules: a rule for one script, on every page of your site. You match the script on part of its URL or of its inline code and pick what happens to it:
    • Do not optimize leaves the script exactly as it is. The first thing to try when one script breaks.
    • Load render blocking makes the page wait for this script before it shows the rest of the page, and loads it with high priority. For a script the page can't be shown without, such as an A/B test that would otherwise show the old version first. It can cost you FCP and LCP.
    • Load Async downloads it with high priority and runs it the moment it arrives, before or after the others. Only for a script that needs no other script and should run early.
    • Load Deferred defers it but doesn't move it to the end of the page. For a script that has to stay where it is in the HTML.
    • Optimized loads it after the page has loaded and the browser has a quiet moment, like the analytics. For a script nobody needs in the first seconds.
    • Scroll into view loads it when an element you name with a CSS selector comes into view. For a script that only serves one part lower on the page, such as a map or a reviews widget.
    • Hover / Click loads it when the visitor hovers over or touches an element you name with a CSS selector. The script only starts downloading at that moment, so keep this for a small script behind one button.
    • Remove this script takes it off every page. For a script nothing on your site uses any more.

When a menu or slider stops working

Turn off Defer scripts and load the page in a private window, to check that deferring is the cause. Then give the script that breaks a rule (Do not optimize or Load render blocking) before you reach for safe mode. In the body, a script with data-no-optimize or data-cfasync="false" is still deferred, because those attributes are usually meant for another optimizer; safe mode respects them.

Turn off "delay JavaScript" in other plugins and at your host. Two tools rewriting the same scripts is asking for a broken page: one optimizer at a time. If your site sends a Content-Security-Policy that would block the rewritten inline scripts, the plugin leaves your scripts alone.

JavaScript

Questions about deferring JavaScript in WordPress

I still get "jQuery is not defined". What now?

Then something else moves jQuery: another plugin or your host delays it until the first interaction, or you gave jQuery itself a script rule. Turn that off first. On its own, the plugin never delays jQuery past the scripts that use it.

Should jQuery be render blocking?

No. jQuery can be deferred like any other script, as long as the scripts that use it run after it.

Does Google Analytics still count every visitor?

Almost every one. It loads within a few seconds after the page has loaded and sends the page view and the earlier events then. A visitor who leaves before that isn't counted.

Is async better than defer for WordPress scripts?

For most scripts, no. Async runs each script the moment it arrives, in any order, and that breaks scripts that need each other. Defer keeps the order. Use a Load Async rule only for a script that stands on its own and should run early.

The background: defer jQuery in WordPress, async vs defer and 16 methods to defer or schedule JavaScript.

Defer JavaScript WordPress Plugin | WP Core Web Vitals Core Web Vitals Defer JavaScript WordPress Plugin | WP Core Web Vitals