Total Blocking Time (TBT)
Also known as: TBT, total blocking time
TBT measures the total time the main thread was blocked by long-running JavaScript tasks (>50ms each) between First Contentful Paint and Time to Interactive. TBT is a Lighthouse-only lab metric — it's not measured in field data (CrUX). It correlates strongly with INP, which IS measured in field data and IS a Core Web Vital. Good TBT is < 200ms; 'Needs Improvement' is 200–600ms; 'Poor' is > 600ms.
TBT in context — lab vs field
There are two complementary metrics that capture JavaScript main-thread blocking:
- TBT (lab) — measured in Lighthouse / PageSpeed Insights synthetic runs. Useful for debugging.
- INP (field) — measured in real-user data via CrUX. This is what affects Google ranking.
A page with high TBT in Lighthouse almost always has high INP in the field. TBT is the early-warning metric; INP is what counts for SEO.
What TBT captures
The main thread is the single execution thread that runs your JavaScript, processes user input, and paints frames. Any synchronous task > 50ms “blocks” the thread.
TBT sums the blocking portion (everything above 50ms) of every long task between FCP and Time to Interactive (TTI).
Example:
- Task 1: 60ms → contributes 10ms to TBT (60 - 50)
- Task 2: 200ms → contributes 150ms to TBT (200 - 50)
- Task 3: 30ms → contributes 0ms (under threshold)
Page TBT: 160ms
Causes of high TBT
The recurring patterns:
- Heavy hydration in React/Vue/Angular — entire app hydrating synchronously at page load
- Third-party scripts — analytics, A/B testing, chat widgets executing in main thread
- Large bundle parsing — multi-MB JS bundles take long time just to parse
- Synchronous expensive work — sorting/filtering large arrays, JSON parsing huge responses
Optimization tactics
The same tactics that fix INP fix TBT:
- Code splitting — load less JS upfront, defer the rest
- Tree shaking — remove unused code from bundles
- Lazy hydration — hydrate components only when they enter viewport
- Move work to Web Workers — heavy computation off the main thread
- Audit third-party scripts — defer or lazy-load non-critical scripts
- Break up long tasks — yield to the browser between chunks of work using
setTimeout(0),requestIdleCallback, or scheduler APIs
TBT vs INP — when they diverge
TBT and INP usually agree, but they can diverge:
- A site with HIGH TBT but LOW INP — long blocking tasks happen during initial load, but users don’t interact until after they finish
- A site with LOW TBT but HIGH INP — load is fast, but interactions later in the session trigger expensive work
For SEO purposes, INP is decisive (it’s what Google measures). TBT is the actionable lab metric for debugging.
Measurement
- PageSpeed Insights — surfaces TBT in lab data
- Lighthouse — primary tool; locally-runnable
- Chrome DevTools Performance panel — shows individual long tasks for debugging
Resocial perspective
We use TBT in our nightly Lighthouse runs as the leading indicator for INP risk. TBT spikes in Lighthouse precede INP regressions in CrUX field data by 4-6 weeks. Catching TBT regressions in CI before they ship saves debugging cycles later.
- Resocial service →
/services/seo/technical-seo/ - Read on the blog →
/blog/technical-seo-complete-guide/