Time to Interactive (TTI) measures the moment a page becomes reliably responsive to user input. The page has finished its visual content, the main thread has quieted down, and clicks, taps, and keystrokes will be handled within the perceptual budget. It's the metric behind every "the page looks done — why isn't my click registering?" experience.
Think of TTI as the green light at a restaurant. The plates are on the table (LCP), the menu is set (FCP), but the staff is still chasing back to the kitchen — and your wave goes unnoticed. TTI is the moment service finally settles and you can actually flag someone down.
TTI is the timestamp of the last long task on the main thread, provided that task is followed by a quiet window. The rules:
Timeline of long tasks (each X is a > 50ms main-thread task):
FCP X X X X X X X | (5 sec quiet)
|__|__|__|____|__|_|_|_________|________________________
0 1 2 3 4 5 6 11
↑
TTI = 6.0s
(last long task before
the 5-second quiet window)The 5-second window is a heuristic that empirically distinguishes "the page is done loading" from "the page is between bursts of work." Anything shorter produces too many false positives where TTI fires during a temporary lull and is then violated by another wave of long tasks. 5 seconds is the sweet spot for stability.
All three metrics measure main-thread blocking, but at different abstractions. Understanding the relationship helps you pick the right one for the job.
| Aspect | TTI | TBT | INP |
|---|---|---|---|
| What it captures | Moment the page becomes reliably responsive | Total blocking duration during load | Worst real-user input response (98th pct) |
| Measurement | Lab | Lab | Field (CrUX) |
| Good threshold | ≤ 3.8 s | ≤ 200 ms | ≤ 200 ms |
| In performance score? | No (since 2023) | Yes (~30%) | No (separate ranking signal) |
| Used for ranking? | No | No | Yes (Core Web Vital) |
Bottom line:Use TBT and INP for scoring and ranking. Use TTI as the single number you set performance budgets against — "our checkout page must be interactive in under 4 seconds on a mid-range mobile."
The dominant cause of slow TTI is too much JavaScript. Every kilobyte must be downloaded, parsed, compiled, and executed — all on the main thread. A 1 MB JS bundle on a mid-range Android phone routinely produces 1,500–3,000 ms of TTI delay.
Fix: Audit your bundle for unused libraries, replace heavy dependencies with lighter ones, and remove polyfills you no longer need.
Don't ship the JavaScript for the cart, the dashboard, and the admin panel on the homepage. Code splitting lets each route load only what it actually needs.
// Dynamic import: code is only fetched when the modal opens
const Modal = await import('./HeavyModal');A blocking <script> in the head pauses parsing and pushes TTI out. defer runs after document parsing; asyncruns whenever it's ready, in any order.
Fix: Default every third-party script to defer or async. Reserve synchronous loading for code that must run before paint.
CPU-bound work (parsing large JSON, image processing, search indexing, encryption) should never run on the main thread. Web Workers run JavaScript on a separate thread, freeing the main thread to become interactive.
Fix:If a task takes > 100 ms and doesn't need DOM access, move it to a Worker.
Single-page apps that render entirely client-side push enormous amounts of work onto the main thread before the page becomes interactive. SSR or static generation hands the browser ready-to-paint HTML; JS only needs to attach event handlers.
Fix: Move to a framework that supports SSR or static export (Next.js, Nuxt, SvelteKit, Astro). Hydration cost is non-zero but typically 5–10× cheaper than client-side rendering from scratch.
Tag managers, A/B testing tools, chat widgets, and ad scripts are TTI's favorite hiding place. Every third-party script runs on your main thread, and the page owner pays the cost.
Fix: Use one tag manager to consolidate scripts, then quarterly-audit every third-party tag. Anything not needed for the first 5 seconds should fire on requestIdleCallback.
If your fonts, scripts, or APIs are served from a different origin, the browser pays a TLS handshake cost before it can fetch them. Preconnecting cuts that out of the critical path.
<link rel="preconnect" href="https://fonts.example.com">
<link rel="preconnect" href="https://api.example.com">The cheapest TTI to fix is the TTI that never regressed. Performance budgets enforce a hard cap on bundle size or main-thread time at build time.
Fix:Add a budget rule to your bundler config (e.g. fail the build if main bundle exceeds 200 KB gzipped). Track TTI in CI and fail PRs that regress it > 500 ms.
What's happening: A server-rendered SPA sends an 800 KB hydration data blob, and the framework parses + reconciles all of it on load.
Fix: Trim hydration data to only what the client actually consumes. Move read-only data into the rendered HTML; only ship interactive state through hydration.
What's happening: Five+ third-party scripts (analytics, A/B test, heatmap, chat, ads) all loading synchronously on first paint.
Fix: Audit and remove duplicate analytics tools. Consolidate the rest behind one tag manager that defers loading. Anything not needed for the first 5 seconds should fire on requestIdleCallback.
useEffect on MountWhat's happening: A React component runs an expensive synchronous calculation in useEffect(() => ..., []), blocking input for hundreds of milliseconds right after the page paints.
Fix: Move the work off the main thread (Web Worker), break it into yielding chunks, or compute it on the server and pass results as props.
What's happening: The page has continuous network or main-thread activity (long-polling, persistent WebSocket, infinite scroll prefetch) that never produces a 5-second quiet window.
Fix: Throttle background activity that runs on first load. Long-polling, prefetch, and analytics flush should all fire after the first quiet window — not before it.
A good TTI is 3.8 seconds or lesson a mid-range mobile device. Between 3.8s and 7.3s "needs improvement," and over 7.3s is poor — the threshold at which most users assume the page is broken.
No. The Core Web Vitals are LCP, INP, and CLS. TTI is a lab-only diagnostic — it's computed during synthetic tests, not from real users, and Google does not use it as a ranking signal.
In 2023, TTI was removed from the standard performance-score formula because Total Blocking Time (TBT) and Interaction to Next Paint (INP) capture the same problem more reliably and with lower variance. TTI is sensitive to small timing changes (a single late long task can shift it by seconds), which made it unstable for scoring. It remains in audits as a diagnostic.
TTI marks the moment the page becomes reliably responsive (one timestamp). TBT measures how much blocking happened during the run-up to TTI (a duration). A page can have a fast TTI of 4 seconds but a poor TBT of 800 ms if there were several long tasks in the load window.
Almost always yes. Both metrics are caused by the same root problem — main-thread blocking. The 8 fixes above (cut JS, defer scripts, Web Workers, SSR, etc.) target both at once.
Mobile CPUs are 4–10× slower than desktop CPUs at JavaScript execution. A 100 ms task on a high-end laptop becomes a 400–1,000 ms task on a mid-range Android phone. Always test TTI under simulated mobile conditions (4× CPU slowdown is the standard).
Indirectly. TTI itself isn't a Google ranking signal, but slow TTI almost always coincides with poor INP — which is a Core Web Vital ranking signal. Lower rankings reduce both organic visibility and AI-citation odds (since AI search systems preferentially cite higher-ranked pages).
TTI is the moment your page goes from "visually loaded" to "actually usable" — the gap between FCP/LCP and TTI is where users misclick, rage-click, and bounce. Even though it no longer feeds the performance score directly, TTI remains the cleanest single number for setting performance budgets and tracking regressions.
The fixes are the same ones that lift TBT and INP: ship less JavaScript, defer what you can, break up what you can't, and move heavy work off the main thread. Run a Greadme deep scan to see your TTI, identify which scripts are pushing it out, and get a prioritized fix list.