At a glance
Total Blocking Time measures how long the main thread was blocked by long tasks (>50ms) during the page load, in milliseconds. The lab approximation of INP: TBT measures synthetic main-thread blocking; INP measures real-user interaction delays. The two correlate strongly because the same code patterns that block the main thread during load are typically the same that delay interactions. Highest-weighted sub-metric in the Performance Score at 30 percent. A site with high TBT will fail INP in the field; bringing TBT down is the most direct lever for improving lab Performance Score and field INP simultaneously.
| What it counts | The cumulative duration of all long tasks (>50ms each) that ran on the main thread between First Contentful Paint and Time to Interactive, minus the 50ms threshold per task. So a 70ms task contributes 20ms to TBT; a 200ms task contributes 150ms. |
| Sample type | Lab data from Lighthouse audit. Field equivalent (closest analog): crux_inp_p75. |
| Why TBT is the INP proxy | Both TBT and INP measure main-thread blocking. TBT is calculated during synthetic page-load; INP measures interaction-driven delays. Brands that reduce lab TBT typically see field INP improve at a 1:1.5 ratio (lab measurements are stricter than field). |
| Lighthouse scoring | TBT feeds the Performance Score with these breakpoints: ≤ 200ms = 100 score, 200-600ms = scaled, > 600ms = 0 score. The 200ms target is much stricter than INP’s 200ms threshold because TBT measures aggregate blocking during load while INP measures single-interaction delay. |
| Common causes of high TBT | (1) Heavy first-party JS bundle parsing and executing during initial load. (2) Third-party script execution on slow CPUs takes 4-10x longer than developer’s machine. (3) Synchronous JS in <head> that blocks the parser. (4) Long-running setup code: GTM tag firing, analytics initialisation, A/B test variant evaluation. (5) Heavy DOM construction: server-rendered HTML with thousands of DOM nodes. |
| Optimisation playbook | Same patterns as INP optimisation: (1) Code-split to reduce per-page JS bundle; (2) Defer third-party scripts that don’t need to run before first paint; (3) Yield to the main thread between heavy work using setTimeout(fn, 0) or scheduler.postTask; (4) Tree-shake unused JS (psi_unused_js) to reduce parse cost; (5) Move expensive JS out of critical-path init and into idle-time execution. |
| Currency | n/a, this is a duration in milliseconds. |
| Time window | T/7D |
| Alert trigger | > 600ms (red, score = 0). Sub-thresholds: amber 200-600ms, red > 600ms. |
| Sentiment key | psi_tbt |
| Roles | owner, operations |
Calculation
Calculated automatically from your Website Performance (PageSpeed + CrUX) data. See the At a glance summary above for what the metric tracks and the worked example below for a typical reading.Worked example
A UK-based BigCommerce fashion store homepage, lab measurement Wednesday 15 May 26.| Long task source | Duration | TBT contribution | Origin |
|---|---|---|---|
| Stencil theme JS parse + execute | 320ms | 270ms | First-party |
| Klaviyo SDK init (popup + tracking) | 280ms | 230ms | Third-party |
| GTM container parse + tag firing | 240ms | 190ms | Third-party |
| Tidio chat widget mount | 220ms | 170ms | Third-party |
| jQuery parse + execute | 180ms | 130ms | First-party |
| Hotjar session-recording init | 140ms | 90ms | Third-party |
| Optimizely variant fetcher | 110ms | 60ms | Third-party |
| 12 short tasks (60-90ms each) | (sum 840ms) | 360ms | Mixed |
| Total Blocking Time | 1,500ms | Poor band |
- TBT at 1,500ms is in the failing band (above 600ms = 0 score). The Performance Score loses 30 percent of its weight to this metric alone. Bringing TBT to under 600ms lifts the Performance Score by 15-25 points just from this sub-metric.
- Third-party tasks contribute 740ms of the 1,500ms total (49 percent). Klaviyo + GTM + Tidio + Hotjar + Optimizely = roughly half the TBT, all from scripts the merchant didn’t write. Deferring or removing the worst offenders delivers most of the available improvement: defer Klaviyo popup (saves 130ms), defer Tidio (saves 170ms), audit GTM tags (saves 80-150ms). Cumulative: 380-450ms reduction with no functional loss.
- First-party tasks contribute 400ms (Stencil theme + jQuery). These are structural to BC Stencil sites and harder to remove. Code-splitting the theme bundle by template type reduces homepage’s JS by 30-40 percent (cuts theme JS contribution from 270ms → 160-190ms). jQuery removal is a multi-month project; defer until structural rewrite.
-
The 12 short tasks (60-90ms each) summing to 360ms are the death-by-a-thousand-cuts pattern. Each task is just over the 50ms threshold so contributes a small portion (10-40ms each), but the cumulative cost is significant. The fix is yielding to the main thread between tasks: split long tasks into smaller chunks via
requestIdleCallbackorscheduler.postTask. - Cumulative impact estimation: Defer third-party (-380ms) + code-split first-party (-110ms) + yield-to-main-thread (-180ms) = roughly 670ms reduction. Post-fix TBT drops from 1,500ms to ~830ms (still amber, but much better). Further work (jQuery replacement, structural framework changes) needed to reach under 600ms; that’s a multi-quarter project.
- Field INP impact: TBT improvement of 670ms typically translates to field INP improvement of 200-400ms (1:1.5-2 ratio). Field INP at 520ms drops to 250-350ms, moving from “needs improvement” toward “good” band.
- Identify the largest single long task. Lighthouse’s audit JSON lists tasks by duration; concentrate on the top 3-5.
- Categorise each task by origin (first-party vs third-party) and criticality.
- Apply the right fix per category:
- Third-party non-critical: defer to post-load.
- Third-party critical: optimise or replace.
- First-party: code-split, tree-shake, yield to main thread.
- Re-audit after each fix. Confirm TBT dropped as expected.
| Time horizon | Action |
|---|---|
| First 1 hour | Identify top 3 long tasks. |
| First 24 hours | Defer dead/non-critical third-party scripts. |
| First 7 days | Code-split first-party bundle by template. |
| First 14 days | Apply yield-to-main-thread pattern to remaining long-running first-party JS. |
| Day 28 | Field INP fully reflects fix. |
Sibling cards merchants should reference together
| Card | Why merchants reach for it |
|---|---|
crux_inp_p75 | Field INP, the real-user equivalent. |
psi_worst_inp_urls | Per-URL INP ranking. |
psi_lab_lcp | Lab LCP; pairs for the lab snapshot. |
psi_lab_cls | Lab CLS. |
psi_speed_index | Speed Index; correlates with TBT for JS-heavy sites. |
psi_performance_score | Performance Score; TBT is 30 percent of weight (highest). |
psi_unused_js | Unused JS bytes contribute to parse time and TBT. |
psi_third_party_cost | Third-party scripts dominate TBT on most ecommerce sites. |
psi_js_execution | Total JS execution time. |
psi_render_blocking | Synchronous JS in <head> adds to TBT. |
psi_perf_score_summary | Composite executive view. |
Reconciling against the vendor’s own dashboard
Where to look:- PageSpeed Insights, “Performance” panel surfaces Total Blocking Time alongside other lab metrics.
- Chrome DevTools → Performance tab, Bottom-Up view shows main-thread time per script; the worst offenders match the long tasks driving TBT.
- Lighthouse CI, TBT can be set as a build budget; failing builds when TBT regresses prevents shipping performance regressions.
| Reason | Direction | What to do |
|---|---|---|
| Run-to-run variance. TBT is more variable than LCP because main-thread scheduling depends on micro-task ordering. ±20-30 percent variance per run. | Either direction | Use 7-day rolling. |
| CPU emulation precision. Different machines may execute Lighthouse’s “mid-tier” emulation slightly differently. | Vortex IQ matches PSI infrastructure | Local Lighthouse runs may produce different TBT than PSI-driven runs. |
| Throttling profile. Mobile profile applies 4x CPU slowdown; desktop applies none. | Mobile higher | Confirm form factor for direct comparison. |
crux_inp_p75, psi_third_party_cost, psi_unused_js).
Quick rule for support tickets: if a merchant says “my TBT improved 400ms but my INP only moved 100ms”, this is the lab-to-field translation ratio. Lab TBT improvements typically translate to field INP improvements at 1:1.5-2 ratio because field measurements are less sensitive to load-time blocking and more sensitive to interaction-time blocking.
Known limitations / merchant FAQs
My TBT is 1,500ms but my INP is only 520ms. Why don’t they match? Different definitions. TBT measures cumulative blocking time during page load; INP measures the worst single-interaction delay. The two metrics correlate but aren’t equivalent. A site with many short long tasks during load can have high TBT without any single interaction being slow; a site with one very heavy interaction handler can have low TBT but high INP. Why does Lighthouse weight TBT at 30 percent? Main-thread blocking is the most universally damaging performance issue. A blocked main thread means the page can’t respond to user input, can’t animate smoothly, can’t process incoming network responses. Almost every other performance issue traces back to main-thread contention; TBT measures it directly. Should I optimise for TBT or for INP? Both, but TBT is the engineering iteration target. TBT is deterministic (runnable repeatedly during development); INP is the field truth source (the thing Google ranks on). Engineering teams iterate on TBT; product/SEO teams track INP for outcome confirmation. My TBT is 200ms but my Performance Score is still 60. Why? Other sub-metrics dragging the score. The Performance Score is a weighted composite: TBT (30%), LCP (25%), CLS (25%), FCP (10%), Speed Index (10%). A 100-score TBT alone produces 30 score points; the other 70 percent comes from the other sub-metrics. Check thepsi_perf_score_summary decomposition.
Can I have low TBT and high INP?
Possible but unusual. Would happen if your site loads fast (no main-thread blocking during initial parse + execute) but a specific interaction handler is heavy (e.g. a complex filter widget that triggers a 1-second JS computation). The Vortex IQ field-data INP would catch this; lab TBT would not. The fix in this case requires the interaction-specific work documented in the per-URL INP card.
Should I focus on first-party or third-party TBT first?
Third-party first. Third-party scripts often contribute 50+ percent of TBT and the fixes are simpler (defer or remove). Tackling third-party first delivers most of the available TBT improvement quickly; first-party code-splitting and refactoring is more invasive.