Diagnosing TBT and CLS: Find Main-Thread and Layout Bottlenecks
Total Blocking Time (TBT) is not a Core Web Vital. It is a lab metric that can expose main-thread work likely to hurt responsiveness, while Cumulative Layout Shift (CLS) is a Core Web Vital that measures visual stability. The useful question is not simply “which score is bad?” but “what work caused the bad experience, under which conditions, and did the fix improve real users without creating a regression?”
Start with the evidence: field first, lab second
The current Core Web Vitals are Largest Contentful Paint (LCP), Interaction to Next Paint (INP), and Cumulative Layout Shift (CLS). TBT sits outside that set: it is a laboratory metric used by tools such as Lighthouse to quantify how much the main thread is blocked during page load. Because a blocked main thread can delay interactions, TBT can be a useful diagnostic for INP, but it is not a substitute for measuring INP from real users. web.dev's Core Web Vitals guidance makes that distinction explicit.
That distinction changes how you troubleshoot. Field data tells you whether real users are experiencing a problem; lab data gives you a controlled environment in which to reproduce and dissect it. When both are available, use the field result to decide what deserves attention, then use Chrome DevTools or Lighthouse to isolate the cause. Lab and field values can legitimately disagree because real users have different devices, networks and behaviours, and because lab tests do not reproduce every click, scroll, route change, advertisement or personalised component. web.dev explains why lab and field data diverge.
- Poor field INP plus high lab TBT: load-time main-thread blocking is a strong lead. Trace the long tasks and find out whether first-party or third-party work is responsible.
- Poor field INP plus low lab TBT: do not assume responsiveness is fixed. The slow interaction may happen after page load, inside an event handler, or during expensive style, layout or paint work.
- Good field INP plus high lab TBT: the lab run has found performance headroom, but it has not proved that users are currently failing INP. Treat the result as diagnostic evidence, not a ranking emergency.
- Poor field CLS plus good lab CLS: reproduce the page beyond the initial load. Scroll, open menus, trigger consent UI, load lazy content and exercise any route or state changes that real visitors use.
TBT and CLS describe different failure modes
A useful investigation starts by being precise about what each metric can and cannot tell you. The Core Web Vitals targets below are evaluated at the 75th percentile of page visits, separated by mobile and desktop. TBT's commonly used threshold is a Lighthouse lab target rather than a field Core Web Vitals threshold. web.dev's TBT documentation describes TBT as the blocking portion of long tasks after First Contentful Paint and notes that it often correlates with INP.
| Metric | What it measures | Where it is most useful | Current “good” target | Do not conclude |
|---|---|---|---|---|
| TBT | The total blocking portion of long main-thread tasks during the measured load window. | Lab diagnosis of load-time responsiveness and main-thread pressure. | Under 200 ms in the standard Lighthouse-style lab guidance. | That TBT is a Core Web Vital, or that a good TBT proves real-user INP is good. |
| INP | Real-user responsiveness across qualifying interactions, including input delay, processing and presentation delay. | Field evidence of whether interactions actually feel slow. | 200 ms or less at the 75th percentile. | That load-time JavaScript is necessarily the cause; slow handlers or rendering after interaction can dominate. |
| CLS | Unexpected visual movement of visible content across the page lifecycle. | Field evidence of visual instability, with lab traces used to find specific shift clusters and causes. | 0.1 or less at the 75th percentile. | That the element which moved caused the shift; it may simply have been pushed by something inserted or resized elsewhere. |
Google says Core Web Vitals are used by its ranking systems, but also says good Core Web Vitals do not guarantee high rankings and that page experience should not be reduced to chasing a perfect score. That is a useful guardrail for prioritisation: fix performance because users are encountering a measurable problem, not because a single tool changed colour. Google Search Central's page experience guidance provides the current wording.
Use a dependency-isolation workflow
For difficult performance problems, use a repeatable sequence rather than jumping from a score to a generic optimisation:
- Observe: establish whether the problem exists in field data, lab data or both, and identify the affected device class and page or template.
- Hypothesise: state a specific suspected cause, such as “the consent platform creates long tasks during initial load” or “the advert slot expands after the article has rendered.”
- Isolate: reproduce the problem in a trace and attribute the expensive work or layout shift to a script, component, request, DOM change, font, image, iframe or animation.
- Change one cause: remove, reschedule, resize or refactor the responsible work. Avoid changing several unrelated systems at once if you still need to prove causality.
- Verify: repeat the same lab flow, test important interactions and page states, then watch field data for the real-user result.
This Observe → Hypothesise → Isolate → Fix → Verify loop matters because the visible symptom is often downstream of the true cause. A layout shift may be blamed on the text that moved even though an advert above it expanded. A high TBT score may be blamed on a third-party domain even though first-party code repeatedly forces style and layout recalculation.
Diagnosing TBT: trace the work that blocks the main thread
TBT is built from long tasks: tasks that run on the main thread for more than 50 milliseconds. Only the portion beyond the first 50 milliseconds contributes blocking time. This makes TBT more useful when you inspect the trace behind the number rather than treating the number itself as the diagnosis.
- Record a representative load in Chrome DevTools. Open the Performance panel, use a realistic device/CPU profile where appropriate, reload the page, and include the early interactions a user is likely to make.
- Find the long tasks. In the Main track, Chrome marks long tasks with a red triangle and shades the blocking portion beyond 50 ms. Select a task and inspect the Summary, Bottom-up or Call tree views to see what consumed the time.
- Separate first-party from third-party cost. DevTools can dim third parties and provides first/third-party attribution in the Summary view. This is more reliable than guessing from the page's list of tags. Chrome's Performance panel reference documents the current workflow.
- Classify the expensive work. A long task can be dominated by script evaluation, event handlers, style recalculation, layout, rendering or a mixture. The remedy should match that category.
- Confirm the business owner of the dependency. Analytics, consent, advertising, chat, testing and personalisation scripts often exist for valid reasons. Before removing or delaying them, confirm what they do and which team depends on them.
Match the TBT fix to the cause
- Unused or duplicate JavaScript: remove it. Eliminating work is generally more reliable than trying to schedule unnecessary work more cleverly.
- Large first-party bundles: reduce the shipped code, split code by route or feature, and avoid executing work before it is needed.
- Non-critical classic scripts: consider
deferwhen execution should wait until HTML parsing is complete, orasyncfor independent scripts that may execute as soon as they are available. Neither attribute makes expensive execution free; an asynchronous script can still occupy the main thread when it runs. MDN's<script>reference explains the execution behaviour. - Long application tasks: break work into smaller tasks and yield so input and rendering can run between chunks. For suitable computation, a Web Worker may move work off the main thread.
- Third-party features that are not needed immediately: load them later, behind user intent, or after critical content where the product requirement allows it. If third-party cost is the recurring problem, see ScanMySEO's guide to managing third-party scripts.
- Style/layout-heavy tasks: look for forced reflow, repeated DOM reads and writes, very large DOM updates or expensive selector work rather than assuming “JavaScript size” is the only problem.
A useful test for third-party code is temporary isolation: block the provider in DevTools or disable the tag in a safe environment, repeat the same trace, and compare the main-thread work. If TBT improves but the page also loses required functionality, you have proved the cost without yet proving the correct production remedy.
Diagnosing CLS: find the shift cluster, then the cause
CLS is a Core Web Vital, but a single page-load trace can understate it because real users may trigger shifts later by scrolling, opening UI, receiving personalised content or loading delayed embeds. If field CLS is poor and Lighthouse looks clean, treat that mismatch as evidence to reproduce more of the page lifecycle rather than as a contradiction.
- Start with the worst shift cluster. In Chrome's Performance panel, the Layout Shifts track groups related shifts. Select the largest cluster first rather than fixing tiny movements that contribute little to the overall result.
- Inspect the shifted elements and potential culprits. Chrome can show the affected elements and, in the current performance insights, likely causes such as unsized media, injected iframes, fonts or animations.
- Trace what changed before the movement. The element that visibly moved may be the victim. Check whether something above it was inserted, resized, restyled or replaced.
- Reproduce post-load behaviour. Scroll through lazy-loaded regions, open accordions and menus, trigger consent or promotion banners, wait for adverts and embeds, and test client-side route changes if the site uses them.
- Fix the mechanism, not the score. Reserve predictable space, stabilise dimensions, improve font fallback behaviour or change the animation/layout strategy as appropriate.
web.dev's CLS optimisation guidance identifies common causes including images without dimensions, adverts and iframes without reserved space, dynamically injected content and web fonts.
Common CLS causes and targeted remedies
- Images and video without a stable aspect ratio: provide intrinsic
widthandheightattributes where possible, or reserve the correct ratio in CSS so the browser can allocate space before the resource arrives. - Ads, embeds and iframes: reserve a realistic slot before the content loads. If the provider can return different sizes, choose a container strategy that minimises unexpected growth and test each breakpoint.
- Consent, promotion or notification UI inserted into document flow: either reserve its space from the start or use an overlay pattern when that is appropriate for the user experience. Do not simply inject a banner above existing content after first paint and accept the movement.
- Web-font swaps: use a sensible fallback font and, where suitable, font metric overrides or a font-loading strategy that reduces re-layout. Verify the visual result as well as the metric.
- Layout-inducing animations: prefer compositor-friendly properties such as
transformandopacitywhen the design allows it, rather than repeatedly changing layout properties such as position or dimensions. - Client-side content replacement: maintain a stable container size during loading and state changes. Skeletons and placeholders only help if their dimensions reasonably match the content that replaces them.
Remediation matrix: diagnose before you optimise
The table below is deliberately symptom-to-evidence rather than score-to-fix. The same metric can have several causes, and a plausible remedy is not a confirmed remedy until the trace supports it.
| Observed symptom | Likely mechanism | How to confirm | Targeted action | Verification |
|---|---|---|---|---|
| High TBT; one third party dominates main-thread time | Large script evaluation or repeated third-party callbacks during load | Use first/third-party attribution, Bottom-up view, and a controlled run with that dependency blocked or disabled | Remove unused tags, reduce scope, delay non-critical loading, or change provider/integration where business requirements permit | Repeat the same trace and confirm the specific main-thread cost falls without breaking consent, analytics or required functionality |
| High TBT; first-party scripting dominates | Large bundle, synchronous startup work, or a long task that does too much at once | Inspect the long task stack and Bottom-up view; identify the functions with the largest self/total time | Remove unused code, code-split, reduce startup work, and break long work into smaller tasks | Compare repeated lab runs and then confirm field INP rather than treating TBT alone as success |
| Poor INP but low TBT | Slow post-load interaction, event handler or rendering work not captured by the page-load proxy | Record the actual slow interaction and inspect the Interactions track for input, processing and presentation delay | Optimise the phase that is actually slow: competing main-thread work, handler code, or rendering/layout | Repeat the interaction under comparable conditions and monitor field INP |
| High CLS from an image, ad or iframe | No stable dimensions are known before the resource loads | Select the largest shift cluster and inspect affected elements/potential culprits | Reserve space with intrinsic dimensions, an aspect ratio, or an appropriate slot/container | Replay the same load and scroll path and confirm that the cluster disappears or materially shrinks |
| Field CLS is poor but lab CLS is good | Post-load, personalised or interaction-dependent content shifts | Reproduce real flows beyond initial load or collect field attribution from real-user monitoring | Fix the recurring post-load component responsible for the largest field shifts | Confirm the flow in lab immediately, then watch the rolling field data as new visits replace old samples |
What should you fix first?
When several bottlenecks appear at once, prioritise by evidence and reach rather than by whichever warning looks most dramatic:
- Real-user failure first: a poor field INP or CLS affecting a meaningful page/template set usually deserves more attention than a lab-only warning on an otherwise healthy page.
- Shared root causes next: a consent manager, site-wide tag, shared component or common layout pattern can affect many URLs, so one fix may remove the same failure across a whole template family.
- Largest attributable cost: within a trace, start with the longest task, largest shift cluster or most expensive repeated work that you can tie to a specific cause.
- High-value journeys: give extra weight to problems on navigation, forms, checkout, lead generation and other interactions where delay or movement can prevent task completion.
- Lab headroom last: once field problems are controlled, use lab diagnostics to prevent regressions and improve resilience on slower devices rather than chasing an arbitrary perfect score.
Verification loop: prove the fix without creating another problem
Performance changes are easy to misread because lab runs vary and one improvement can move work somewhere else. Verify in layers:
- Repeat the same lab scenario more than once. Keep the page state, device profile, throttling and interaction sequence comparable. Look for a consistent directional change, not one unusually good run.
- Verify the exact culprit. For TBT, confirm the targeted task or function is shorter, split or absent. For CLS, confirm the largest shift cluster and its source have been removed or reduced.
- Check neighbouring metrics. A deferred script may improve TBT but delay a required interaction. Reserving a large ad slot may stabilise CLS while harming usable above-the-fold space. Optimise the user experience, not one number in isolation.
- Check product behaviour. Confirm analytics, consent, advertising, forms, personalisation, navigation and other business-critical features still work as intended.
- Watch field data. PageSpeed Insights field values use CrUX real-user data from a rolling 28-day collection period, so they do not update immediately after deployment. Google's PageSpeed Insights documentation explains the field-data window. Use lab testing for immediate regression checks and field data for the eventual real-user verdict.
The practical finish line is not “TBT is green” or “CLS is zero.” It is that the root cause you identified is measurably reduced, the relevant real-user Core Web Vital improves or remains healthy, and the change does not introduce a more important regression elsewhere.