Total Blocking Time (TBT): The Silent Killer of Conversion Rates
TBT measures how long the main thread is blocked during page load. Learn why high TBT destroys conversions and how to reduce it on any site.
Your page loads, the hero image appears, but when a user tries to click the "Buy Now" button — nothing happens. They click again. Still nothing. Three seconds later, the page finally responds. By then, they've already left.
The metric that captures this exact scenario is Total Blocking Time (TBT).
What TBT Measures
TBT measures the total amount of time between First Contentful Paint (FCP) and Time to Interactive (TTI) where the main thread was blocked long enough to prevent input responsiveness.
Specifically, it sums up the "blocking portion" of all long tasks (tasks over 50ms). If a task takes 200ms, its blocking portion is 150ms (200 - 50).
TBT Thresholds
| TBT | Rating |
|---|---|
| ≤ 200ms | Good |
| 200–600ms | Needs Improvement |
| > 600ms | Poor |
Why TBT Matters for Conversions
TBT directly correlates with how "frozen" a page feels during load. High TBT means:
- Buttons don't respond to clicks
- Forms can't be filled out
- Scroll feels janky and unresponsive
- Users assume the page is broken
A Deloitte study found that a 0.1-second improvement in site speed led to 8% more conversions for retail sites and 10% more for travel sites. Much of that improvement came from reducing main thread blocking.
The Anatomy of a Long Task
The browser's main thread handles everything: JavaScript execution, DOM parsing, style calculations, layout, painting, and handling user input. It can only do one thing at a time.
When a JavaScript function runs for 300ms straight, the browser literally cannot process a click event until it finishes. The user's click sits in a queue, waiting.
Common long tasks include:
- Framework initialization (React hydration, Angular bootstrap)
- Third-party script execution (analytics, chat widgets, ad scripts)
- Large JSON parsing (API responses with thousands of items)
- Complex DOM manipulation (rendering large tables, charts)
- Polyfill execution on older browsers
How to Find Your Long Tasks
Chrome DevTools
- Open DevTools → Performance tab
- Click Record, then load your page
- Look for red triangles in the "Main" track — these are long tasks
- Click each to see what JavaScript is running
Lighthouse
Run a Lighthouse audit. The "Avoid long main-thread tasks" diagnostic lists each long task with its duration and source.
Performance Observer API
Track long tasks programmatically:
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log('Long task:', entry.duration, 'ms');
}
});
observer.observe({ type: 'longtask', buffered: true });
How to Reduce TBT
1. Defer Non-Critical JavaScript
Move scripts that aren't needed for the initial render to load after the page is interactive:
<script src="/analytics.js" defer></script>
<script src="/chat-widget.js" async></script>
2. Code Split Aggressively
Don't ship your entire application in a single bundle. Use dynamic imports:
// Instead of importing everything upfront
import { HeavyChart } from './charts';
// Load on demand
const HeavyChart = lazy(() => import('./charts'));
3. Remove Unused JavaScript
Audit your bundles with tools like webpack-bundle-analyzer or source-map-explorer. Common waste:
- Moment.js (use date-fns instead)
- Lodash full build (use lodash-es with tree shaking)
- Polyfills for features your target browsers already support
4. Optimize Third-Party Scripts
Third-party scripts are often the biggest TBT contributors. Strategies:
- Load them after page interactive (
requestIdleCallback) - Use facades (show a static image until user interacts)
- Audit with Google's third-party web tool
5. Break Up Long Tasks with Yielding
function yieldToMain() {
return new Promise(resolve => {
setTimeout(resolve, 0);
});
}
async function processLargeDataset(data) {
for (let i = 0; i < data.length; i++) {
processItem(data[i]);
if (i % 100 === 0) {
await yieldToMain(); // Let the browser handle pending input
}
}
}
6. Use Web Workers for Heavy Computation
Move CPU-intensive work off the main thread entirely:
const worker = new Worker('/heavy-computation.js');
worker.postMessage(largeDataset);
worker.onmessage = (e) => {
updateUI(e.data);
};
TBT vs. INP: What's the Difference?
| Aspect | TBT | INP |
|---|---|---|
| Type | Lab metric | Field metric |
| Measures | Blocking during load | Interaction latency throughout visit |
| When | FCP to TTI | Entire page lifecycle |
| Tool | Lighthouse | CrUX, Real User Monitoring |
TBT is a strong predictor of INP. If your TBT is high, your INP will almost certainly be poor too.
The ROI of Reducing TBT
| TBT Reduction | Typical Conversion Lift |
|---|---|
| 600ms → 200ms | 15–25% |
| 200ms → 100ms | 5–10% |
| 1000ms+ → 200ms | 30–50% |
These numbers vary by industry, but the pattern is consistent: reducing TBT is one of the highest-ROI performance optimizations you can make.
Start Measuring TBT Today
BadPageSpeed runs Lighthouse audits on your pages and tracks TBT over time. Set alerts so you know the moment a deployment increases blocking time.
Ready to stop wasting ad spend?
Track your landing page performance, monitor Core Web Vitals, and calculate exactly how much slow pages cost you.
Start Free — No Credit Card