
What Is Total Blocking Time (TBT)? The Heaviest Metric in the Lighthouse Score
- vuetelemetry
- Guides
- 7 min read
TBT carries 30 percent of the Lighthouse performance score, more than any other metric, and it is not a Core Web Vital. What it counts, why only the part of a task above 50 ms is measured, and why splitting your JavaScript beats shrinking it.
Total Blocking Time is the metric with the largest share of the Lighthouse performance score, 30 percent, ahead of LCP and CLS at 25 each. It is also not a Core Web Vital, which is an odd pair of facts to hold at once and the reason it is worth understanding properly.
What it measures is not how long your page takes to load. It measures how long the browser was too busy to answer you.
What TBT actually counts

During loading, the browser runs your JavaScript on the main thread, the same thread that handles clicks and key presses. While a piece of work is running there, nothing else can happen. A task that occupies the main thread for more than 50 milliseconds is called a long task, and it is the unit TBT is built from.
Here is the part that surprises people. TBT does not count the whole task, only the portion above the 50 ms threshold. A task lasting 70 ms contributes 20 ms. A task lasting 45 ms contributes nothing at all. TBT is the sum of those blocking portions for every long task between First Contentful Paint and the moment the page becomes interactive.
The 50 ms line is not arbitrary. It is roughly the point at which a person notices that the interface did not respond immediately, so the metric is counting the time the page spent being noticeably unresponsive rather than the time it spent working.
Why it weighs 30 percent and still is not a Core Web Vital
Lighthouse scores TBT in three bands, measured on its simulated mobile device: good at 200 ms or less, needs improvement between 200 and 600 ms, and poor above 600 ms. Those numbers assume a mid-range phone, which is deliberately slower than the machine you are testing from.
- Good - 200 ms or less
- Needs improvement - between 200 and 600 ms
- Poor - above 600 ms
TBT is a lab metric. It is measured in a controlled run, with a fixed device profile and no real user, which is exactly why it is not a Core Web Vital: the Core Web Vitals are field metrics collected from real visits. Its field counterpart is Interaction to Next Paint, and the two are related without being the same thing.
TBT looks at the main thread being blocked during load. INP looks at what actually happened when a real person interacted, at any moment of the visit. A page can have a respectable TBT and a poor INP because the expensive work happens later, when a menu opens or a filter is applied.
What makes it bad
The causes are almost always JavaScript, and usually in one of a few shapes. A large bundle has to be parsed, compiled and executed before anything else can run, and that work lands on the main thread in one go.
Framework hydration is the second common source. Server-rendered HTML arrives quickly, then the framework walks the component tree to attach behaviour, and on a large page that walk is a single long task at exactly the moment the user is most likely to try clicking something.
Third-party scripts are the third, and the least controlled. Tag managers, analytics, chat widgets and consent banners each execute their own work on your main thread, on a schedule you do not set, and their cost rarely appears in anyone's bundle budget.
Splitting beats shrinking
The instinct is to make the bundle smaller. That helps, but it is not the same lever, and this is the most useful thing to know about TBT. The metric counts time above 50 ms per task, so the same total amount of work split into many short tasks scores far better than one long one, even though the bytes are identical.
That is why yielding matters. Breaking a heavy loop so the browser can service input between chunks, moving computation into a Web Worker where it does not touch the main thread at all, and deferring third parties until after the page is usable all reduce TBT without removing a single line of logic.
The lab and the field do not measure the same thing
One honest caveat before you optimise for the number. A lab run uses one device profile and never clicks anything, so TBT can look fine while real users on cheaper hardware still wait. Treat it as a diagnostic that tells you where the main thread is busy, and check the field data for what people actually experienced.
Read together, the two answer different questions. TBT tells you the page was blocked during load and roughly how much. INP tells you whether that mattered to somebody.
FAQ
What is a good Total Blocking Time?
200 ms or less in a Lighthouse run, which uses a simulated mid-range mobile device. Between 200 and 600 ms is needs improvement, and above 600 ms is poor. Because the run is throttled, a figure measured on your own laptop without throttling is not comparable and will usually look far better than reality.
Is Total Blocking Time a Core Web Vital?
No. The Core Web Vitals are Largest Contentful Paint, Interaction to Next Paint and Cumulative Layout Shift, and they are collected from real visits. TBT is a lab metric measured in a controlled run, which is why it can carry 30 percent of the Lighthouse performance score and still sit outside the ranking-facing set.
What is the difference between TBT and INP?
TBT measures the main thread being blocked during page load, in a lab run, with no user interacting. INP measures how long real interactions took to produce a visible response, at any point in the visit. They correlate, because a busy main thread hurts both, but a page can score well on TBT and badly on INP when the expensive work happens after load.
Why does a 45 ms task count for nothing?
Because TBT only counts the portion of a task above 50 ms. A task of 45 ms is not a long task and contributes zero; a task of 70 ms contributes 20 ms. The threshold is roughly where a person starts to notice that the interface did not respond, so the metric is measuring noticeable unresponsiveness rather than total work.
How do I reduce Total Blocking Time?
Split the work before you try to remove it. The same amount of JavaScript broken into short tasks scores far better than one long task, so yield to the browser between chunks, move computation into a Web Worker, and defer third-party scripts until the page is usable. Then reduce what you ship: code splitting, dropping unused dependencies, and cutting hydration cost on large pages.



That is why yielding matters. Breaking a heavy loop so the browser can service input between chunks, moving computation into a Web Worker where it does not touch the main thread at all, and deferring third parties until after the page is usable all reduce TBT without removing a single line of logic.