Skip to main content
Performance

Total Blocking Time (TBT)

Published:

Total Blocking Time (TBT) is a lab performance metric that adds up how long the browser’s main thread was blocked between First Contentful Paint (FCP) and Time to Interactive (TTI). Only the part of each long task that exceeds 50 ms counts towards the total.

TBT is not a Core Web Vital. A lab test has no real clicks, so TBT serves as a proxy for INP, the responsiveness metric measured with real users. A good TBT does not guarantee a good INP in field data.

How TBT is calculated

A long task is any piece of main-thread work that runs for more than 50 ms. During that time the browser cannot handle a click or a keystroke. Only the excess over 50 ms counts as blocking: a 120 ms task adds 70 ms to TBT, while a 45 ms task adds nothing.

In the example below the tasks take 525 ms in total, but TBT is 330 ms. The single 300 ms task weighs the most, because the thread cannot respond to the user for its whole duration.

Calculating TBT (scenario)
Example
Task A: 120 ms → 120 − 50 =  70 ms
Task B:  45 ms → below threshold =   0 ms
Task C: 300 ms → 300 − 50 = 250 ms
Task D:  60 ms →  60 − 50 =  10 ms
───────────────────────────────────
TBT:                          330 ms

Lighthouse TBT thresholds

Since Lighthouse 10, TBT carries 30% of the Performance score, more than any other metric. LCP and CLS carry 25% each, FCP and Speed Index 10% each. That is why JavaScript work on the main thread has a large effect on the score.

web.dev recommends a TBT under 200 ms when tested on average mobile hardware.

DeviceGoodNeeds improvementPoor
Mobile0–200 ms200–600 msover 600 ms
Desktop0–150 ms150–350 msover 350 ms

TBT, INP and Core Web Vitals

The Core Web Vitals are LCP, INP and CLS. TBT is not one of them, but it helps predict INP problems in the lab: the long tasks that inflate TBT also delay responses to clicks.

The two metrics measure different things. TBT covers page load up to TTI in a single controlled test. INP covers interactions throughout the visit, on real users’ devices. web.dev does not recommend measuring TBT in the field, because user interactions skew it. To judge responsiveness in the field, use INP from CrUX or your own RUM.

How to reduce TBT

  • Break up long tasks. Yield to the main thread between chunks of work, for example with scheduler.yield() and a setTimeout() fallback.
  • Ship less JavaScript. Remove unused code and split bundles so only what is needed runs at startup.
  • Limit and defer third-party scripts. Ad tags, chat widgets and embeds often add long tasks of their own.
  • Simplify expensive code, for example by narrowing selectors so a script does not walk thousands of DOM nodes.
  • Do not rely on minification alone. It reduces the bytes transferred but does not remove script work. TBT drops when less code runs on the main thread, or runs in shorter chunks.
Yielding between chunks of work
JavaScript
function yieldToMain() {
  if (globalThis.scheduler?.yield) {
    return scheduler.yield();
  }
  return new Promise((resolve) => setTimeout(resolve, 0));
}

async function processItems(items) {
  for (const item of items) {
    processItem(item);
    // The browser can now handle a pending click
    await yieldToMain();
  }
}

How to measure TBT

Run Lighthouse in Chrome DevTools or PageSpeed Insights and read TBT in the metrics section. Compare several runs on the same device profile, because a single test fluctuates. The DevTools Performance panel shows the individual long tasks, which makes it easy to find the script blocking the thread.

Sources & further reading

See what is blocking your pages

Insight combines lab results with field data when available and ranks performance issues by priority.