Total Blocking Time (TBT) is reported for a page load. How is it computed from the page's long tasks, and why can a page with one 900 ms task score far worse than a page with six 120 ms tasks?
answer
- not total time, total excess
- each task gets a free allowance
- subtract fifty, then sum
- max(0, duration - 50) per task
- shape of the work beats total CPU
basics
~20 sTotal Blocking Time sums, over every long task in the measured load window, the amount by which that task exceeds 50 ms. One 900 ms task contributes 850 ms; six 120 ms tasks contribute 70 ms each, or 420 ms. Anything at or under 50 ms contributes nothing.
solid answer
~50 sTBT is not total main-thread time — it is the total *excess*. For each task inside the measurement window you take `max(0, duration - 50 ms)` and add it up. That first 50 ms is treated as free because a task that short still leaves room to answer input inside the response budget. So one 900 ms task contributes 850 ms, while six 120 ms tasks contribute 70 ms apiece, 420 ms in total — even though the six tasks together consume more CPU. That is the whole point: TBT scores the *shape* of the work, penalising the long uninterruptible blocks that actually strand a user, not raw busyness. In Lighthouse the window runs from First Contentful Paint to Time to Interactive, and TBT carries the heaviest single weight in the performance score, which is why it is often the fastest number to move. It is a lab proxy for real-user responsiveness, measured with nobody actually interacting.
go deeper
Know that Total Blocking Time is about how long the page could not respond during load, and that many short pieces of work are better than one long one.
Be able to do the arithmetic out loud: subtract 50 ms from each task's duration, discard negatives, sum the rest. Say why the 50 ms allowance exists rather than reciting the formula.
Show that you know what the number hides — the lab device profile, the FCP-to-TTI window, and the fact that it names no culprit. Explain how you would go from a bad TBT to the specific code responsible.
Be ready to say what role a lab aggregate should play in how a team is judged: where you would gate a release on it, where field responsiveness must override it, and how you stop a scoring formula from steering engineering effort toward arbitrage.
## What TBT is trying to capture A page load can be busy in two very different ways. It can do its work in many short bursts, leaving frequent gaps where the browser can dispatch a click and paint a frame; or it can do the same amount of work in a few enormous blocks that leave no gaps at all. The elapsed time is identical. The experience is not. **Total Blocking Time** exists to score that difference. ## The arithmetic For every task in the measurement window, the blocking portion is: ```js const blocking = Math.max(0, taskDuration - 50); ``` TBT is the sum of those portions. The first 50 ms of any task is treated as free, for the same reason the long-task threshold sits at 50 ms: a task that short still leaves enough of the roughly 100 ms input-response budget to run a handler and paint. Everything beyond it is time in which the user could have been waiting with no possible response. Work the arithmetic on three profiles: - one 900 ms task → 850 ms of TBT; - six 120 ms tasks → 6 x 70 = 420 ms; - twelve 45 ms tasks → 0 ms, despite 540 ms of CPU time. The six tasks burn 720 ms of CPU against the single task's 900 ms, yet score barely half the TBT. The twelve tasks burn 540 ms and score nothing at all. TBT deliberately rewards interruptibility. ## The window TBT is defined over a window, not the whole session. In Lighthouse that window runs from **First Contentful Paint** — the moment the user first sees content and might plausibly try to interact — to **Time to Interactive**. Tasks before FCP are excluded because there is nothing on screen to interact with yet. This is why moving expensive bootstrap work *earlier* can sometimes reduce TBT without helping the user at all, and it is a fair thing for an interviewer to probe. ## What it is a proxy for TBT is a **lab** metric: measured on a synthetic load, on one device profile, with nobody clicking. Its purpose is to be the lab stand-in for field responsiveness, which is measured with Interaction to Next Paint from real users who really do click. The two correlate because the same long tasks that inflate TBT are the ones that delay a real interaction's handler and paint. They diverge whenever the real problem lives outside the load window — a slow filter handler, an expensive route transition — which TBT never sees. In recent Lighthouse versions TBT carries the largest single weight in the performance score (30% in Lighthouse 10 through 12), which is why it is so often the number a team is asked to fix. ## Moving the number honestly The genuinely useful moves are the ones that also help the user: - **execute less JavaScript in that window** — split what the first view does not need out of the initial payload; - **shrink the work itself** — a smaller serialized state blob to parse, less markup to bootstrap; - **defer non-essential work** past the window, and past the point where the user needs the page; - **move pure computation off the main thread** where the data cost allows it. ## The gaming trap Because each task gets 50 ms for free, mechanically slicing a 300 ms task into seven 45 ms tasks drops its TBT contribution from 250 ms to zero. The CPU work is unchanged and the user still waits roughly 300 ms for a first frame — the browser now merely gets six chances to interleave. Some of that is real (input *can* now be dispatched between chunks), and some of it is pure score arbitrage. A strong answer names both halves rather than pretending chunking is either a cheat or a cure. ## What TBT does not tell you It does not say *which* code was responsible — it is an aggregate with no attribution. It does not cover anything after the load window. And it will happily read zero on a device fast enough to keep every task under 50 ms while the same page produces a wall of long tasks on a mid-range phone, which is why lab runs are CPU-throttled and why field data is still required.
- Two teams report the same TBT but one page feels far worse on real phones. What could explain that?TBT is measured in a lab on one device profile and one network shape. A page whose cost is CPU-bound degrades sharply on a slower phone, turning 60 ms tasks into 200 ms ones and multiplying blocking time in the field while the lab number stays put. It also stops measuring at Time to Interactive, so expensive post-load interactions are invisible to it.
- If a team splits its bootstrap into 45 ms chunks and TBT drops to zero, has anything real improved?Partly. The browser can now dispatch input and paint between chunks, so a click during bootstrap gets answered instead of stranded — that is a genuine responsiveness win. But the total CPU work and the time until the page is fully ready are unchanged, so the score moves further than the experience does. Report both numbers.
- Why does TBT exclude everything before First Contentful Paint?Before FCP there is nothing on screen, so there is no interaction to block — blocking the thread then costs the user waiting, not responsiveness, and other metrics already measure that wait. The side effect is that work shifted earlier can lower TBT without helping anyone, which is a known limitation of the window rather than an optimisation.
saying these in an interview costs you the question
- Says TBT is the total main-thread time during load
- Forgets the first 50 ms of each task is not counted
- Thinks more tasks always means worse TBT
- Treats TBT as a field metric collected from real users
- Assumes zero TBT in the lab means good real-world responsiveness