To reduce Total Blocking Time in WordPress, find the long JavaScript tasks with Chrome DevTools or Lighthouse, remove scripts you do not need, load the rest only on pages that use them, defer or delay non-critical scripts, and replace heavy third-party widgets with lighter options. TBT is a lab metric; the real-user measure it predicts is INP.
This is part of my speed series; start with the Core Web Vitals guide for context.
What is Total Blocking Time?
Total Blocking Time measures how long the browser’s main thread was too busy to respond during page load. Any task longer than 50 ms is a “long task,” and the time beyond 50 ms counts as blocking. TBT adds up those blocking portions between First Contentful Paint and Time to Interactive. A 250 ms task contributes 200 ms.
TBT and INP: how they relate
Interaction to Next Paint, a Core Web Vital, measures how fast the page responds to real taps and clicks during the whole visit. Lab tools cannot tap your page like users do, so Lighthouse reports TBT instead. A high TBT means the main thread is busy, so interactions during load are likely to feel slow. Fix TBT in the lab, then confirm with INP field data.
Step 1: find what blocks the main thread
- Lighthouse → “Avoid long main-thread tasks” and “Reduce JavaScript execution time” list the worst scripts.
- “Reduce the impact of third-party code” groups costs by provider.
- DevTools Performance panel: record a page load with CPU throttling, find the red-flagged long tasks, and expand them to see which script and function caused them.
- Coverage tab: shows how much of each JS file is actually used on the page.
Write down each script, its source (plugin, theme, third party), its cost, and whether this page needs it.
Step 2: remove what is not needed
The cheapest JavaScript is the one never loaded. Typical candidates:
- Plugins no longer used (see my plugin audit).
- Duplicate libraries (two versions of a slider library, several icon fonts).
- jQuery Migrate, if nothing depends on it.
- Emoji scripts, if you do not need them.
- Old tracking tags from past campaigns in your tag manager.
Step 3: load scripts only where needed
Contact form scripts on every page, slider scripts on pages without sliders, map scripts site-wide: all common. Dequeue them conditionally:
add_action( 'wp_enqueue_scripts', function () {
if ( ! is_page( 'contact' ) ) {
wp_dequeue_script( 'contact-form-7' );
wp_dequeue_style( 'contact-form-7' );
}
}, 100 );
Handles differ per plugin; find them in the page source or with Query Monitor. Some optimisation plugins offer per-page script managers that do the same without code.
Step 4: defer and delay
- Defer (
deferattribute) downloads in parallel and runs after HTML parsing. Since WordPress 6.3,wp_enqueue_script()accepts a loading strategy:
wp_enqueue_script( 'mx-ui', get_stylesheet_directory_uri() . '/assets/ui.js', array(), '1.0', array(
'strategy' => 'defer',
'in_footer' => true,
) );
- Delay until interaction waits until the user scrolls, moves the mouse or taps before loading a script. Very effective for chat widgets, review widgets, heat maps and some analytics. Not suitable for anything needed immediately: navigation menus, above-the-fold sliders, cookie consent required before tracking.
Always test after enabling delay: open the mobile menu, submit forms, add to cart, check analytics still records.
Step 5: tame third-party scripts
Third parties are often the biggest share. Options:
- Chat widgets: load on click with a lightweight placeholder button; or load after a delay.
- YouTube and map embeds: use a facade (a thumbnail that loads the real embed on click).
- Tag managers: audit tags; each one runs on your users’ devices.
- A/B testing tools: these often block rendering by design; use them deliberately and remove when tests end.
- Social feeds: replace with static content or links.
Step 6: reduce DOM and page builder weight
Large DOMs make every script and style recalculation slower, which affects both TBT and INP. With page builders:
- Avoid deeply nested sections and columns.
- Turn off unused widgets and modules in the builder settings.
- Use the builder’s performance options (for example, loading only used assets).
- For key templates, a lean custom template in the child theme may outperform the builder.
Step 7: write lighter JavaScript
If you control the code:
- Break long work into smaller chunks and yield to the main thread between them.
- Use event delegation instead of thousands of listeners.
- Avoid layout thrashing: batch DOM reads, then writes.
- Use CSS for animation where possible, and
IntersectionObserverinstead of scroll handlers.
Measuring correctly
Lab TBT varies between runs and between machines. Run Lighthouse several times and compare medians, always with the same device settings. After deploying, purge caches (page cache, optimisation plugin cache, CDN) so you test the new version.
Checklist
- Long tasks identified and attributed to scripts
- Unused plugins and tags removed
- Page-specific scripts loaded only on those pages
- Non-critical scripts deferred; widgets delayed until interaction
- Embeds replaced with facades
- DOM size reduced on key templates
- Key interactions tested after changes
- INP field data monitored
Common mistakes
- Enabling “delay all JavaScript” and not noticing the mobile menu is broken.
- Measuring with a cached old version.
- Blaming WordPress core when one chat widget causes most of the blocking time.
- Combining all JS into one large file, which can create one huge long task.
How TBT is calculated
A long task is any piece of work on the main thread that runs for more than 50 milliseconds. TBT adds up only the part of each long task above 50 ms, between First Contentful Paint and Time to Interactive. So a 70 ms task contributes 20 ms, and a 300 ms task contributes 250 ms (web.dev: Total Blocking Time). This is why one heavy script can hurt more than many small ones: the cost grows with the length of each task.
TBT is a lab metric. It appears in Lighthouse and PageSpeed Insights but is not one of the Core Web Vitals. It is useful because it correlates with INP, which is measured in the field. If your TBT is high in the lab, your real users are likely to see slow responses when they tap menus, filters or “Add to cart” buttons.
Breaking up long tasks
When the blocking work comes from your own theme or custom code, the goal is to split it into smaller pieces so the browser can handle user input between them. Google’s guidance describes yielding to the main thread, for example with setTimeout or, in supporting browsers, scheduler.yield() (web.dev: Optimize long tasks). Typical candidates on WordPress sites include:
- scripts that initialise every slider, tab and accordion on the page at once, even those far below the fold;
- large JSON objects passed with
wp_localize_scriptand parsed on every page; - analytics or tracking code that runs heavy work on page load instead of after it.
Initialising components only when they come near the viewport, using IntersectionObserver, is often enough to remove a long task.
WooCommerce-specific sources of blocking time
Stores tend to collect more scripts than brochure sites. Watch for these:
- Cart fragments: the AJAX request that updates the mini-cart can run on every page. If your theme does not show a live mini-cart, it may be safe to disable it on non-shop pages; test the cart count afterwards.
- Payment and BNPL widgets: some payment providers load scripts on product pages to show instalment messages. Load them only on product and checkout templates.
- Product filters: filter plugins can attach many event listeners and re-render large lists. Server-side filtering with simple links is lighter.
- Marketing pixels: Meta, TikTok, Snap and Google tags together can create noticeable blocking time. Consolidate through one tag manager and remove tags nobody uses.
Testing like your visitors
Lighthouse mobile simulates a slower CPU, but it is still an approximation. Many visitors in Egypt and the Gulf use mid-range Android phones, where JavaScript runs noticeably slower than on a laptop. Two simple habits help:
- In Chrome DevTools, use the Performance panel with CPU throttling enabled and record a real interaction, such as opening the menu.
- Test on an actual mid-range phone on mobile data at least once before and after changes.
If something feels slow on the phone but Lighthouse looks fine, trust the phone and investigate further.
Prioritising fixes
Sort the scripts in the Lighthouse “Reduce JavaScript execution time” and “Minimize third-party usage” audits by time. Start with the top one or two. In most audits I run, a small number of scripts cause most of the blocking time, so fixing them gives more benefit than micro-optimising everything.
Frequently asked questions
Is a “delay JavaScript” plugin setting safe?
It can be very effective, but exclude scripts needed for above-the-fold interaction, such as the menu, and test every template after enabling it.
Does TBT affect rankings directly?
No. Google uses field metrics such as INP. TBT is a diagnostic that helps you find the work that causes poor INP.
If your site feels sluggish on phones, contact me and I will trace where the time goes. Related: improving LCP.
Frequently asked questions
What is Total Blocking Time?
TBT is the total time, between First Contentful Paint and Time to Interactive, that the main thread was blocked long enough to prevent input responsiveness. Each task over 50 ms contributes its time beyond 50 ms.
What is a good TBT score?
Lighthouse treats around 200 ms or less on mobile as good. Because it is a lab metric, use it to compare changes, and judge users' experience with INP field data.
Is delaying JavaScript safe?
Often, but not always. Delaying scripts until user interaction can break menus, sliders, forms or analytics. Exclude critical scripts and test key pages after enabling it.
Why did TBT get worse after an update?
New plugin versions, added tracking tags, or a theme adding scripts site-wide are common causes. Compare the scripts loaded before and after in DevTools.


