In March 2024, Google retired First Input Delay (FID) and officially replaced it with Interaction to Next Paint (INP) as a Core Web Vital. For many websites, this was a wake-up call. FID was relatively easy to pass — it measured only the delay before the browser started processing an interaction, not how long that processing took. INP is far more demanding: it measures the complete response time from the moment a user interacts with your page to the moment the browser paints the resulting visual update.
If your site had a comfortable FID score, your INP may tell a very different story. And since Core Web Vitals directly influence Google's ranking signals, understanding and optimizing INP is now a genuine SEO priority.
What INP Actually Measures
INP captures the time from when a user makes an interaction (click, tap, or keyboard press) to the next frame the browser paints after that interaction is processed. Unlike FID, which only measured the input delay portion, INP captures the full loop:
- Input delay — time between the user's input and the start of event handlers
- Processing time — how long the event handlers take to run
- Presentation delay — time for the browser to commit the frame to screen
INP reports the worst single interaction across the entire page visit (with some outlier filtering), making it a stringent measure of real-world responsiveness.
INP Thresholds
| Score | Rating |
|---|---|
| 200ms or less | Good |
| 201ms – 500ms | Needs Improvement |
| Over 500ms | Poor |
A "good" INP means that for the vast majority of interactions on your page, users never wait more than 200 milliseconds to see a visual response. That's a tight target for JavaScript-heavy applications.
Why Google Replaced FID with INP
FID's core weakness was that it only measured the first user interaction on a page and only the input delay — not the processing or rendering time. This meant a page could score well on FID while making users wait 800ms for a button click to visually confirm. INP fixes this by:
- Measuring all interactions throughout the page session, not just the first
- Capturing the full round-trip from input to paint
- Providing a more accurate picture of perceived responsiveness
In Google's field data, INP correlates far more strongly with user satisfaction and abandonment rates than FID ever did.
Common Causes of Poor INP
Long JavaScript Tasks
The main thread in a browser is single-threaded. When JavaScript runs a long task (anything over 50ms is considered "long"), it blocks all other work including responding to user input. A click handler that runs for 300ms before the browser can repaint will produce an INP of at least 300ms.
Common culprits:
- Large data processing in event handlers
- Synchronous DOM queries inside click handlers
- Unoptimized React renders triggered by state changes
- Third-party scripts executing during interactions
Forced Layout / Layout Thrashing
When JavaScript reads layout properties (like offsetWidth, getBoundingClientRect(), scrollTop) immediately after writing to the DOM, the browser is forced to recalculate layout synchronously. Interleaving reads and writes in a loop is called "layout thrashing" and can add hundreds of milliseconds to interaction time.
// Bad — causes layout thrashing
elements.forEach(el => {
const height = el.offsetHeight; // forces layout
el.style.height = height + 10 + 'px'; // invalidates layout
});
// Good — batch reads, then writes
const heights = elements.map(el => el.offsetHeight); // read all first
elements.forEach((el, i) => {
el.style.height = heights[i] + 10 + 'px'; // then write all
});
Rendering Bottlenecks
React and other virtual DOM frameworks can trigger expensive reconciliation on every state update. If a small interaction causes a large component tree to re-render, INP suffers.
Optimization Strategies
1. Break Up Long Tasks with Yielding
The most impactful technique is yielding back to the browser during long operations. This allows the browser to handle input events, repaint, and keep the page responsive.
// Without yielding — blocks the main thread
function processLargeList(items) {
items.forEach(item => heavyComputation(item));
}
// With yielding — browser stays responsive
async function processLargeList(items) {
for (let i = 0; i < items.length; i++) {
heavyComputation(items[i]);
if (i % 50 === 0) {
// Yield to browser every 50 items
await new Promise(resolve => setTimeout(resolve, 0));
}
}
}
2. Use scheduler.postTask() for Prioritized Work
The modern Scheduler API lets you assign priority levels to work, ensuring user-visible updates run before background tasks:
// Run non-critical work at low priority
scheduler.postTask(() => {
analyticsTrack('button_clicked');
prefetchNextPage();
}, { priority: 'background' });
// This runs immediately — user sees feedback fast
updateButtonState('loading');
3. Debounce Expensive Event Handlers
For events that fire repeatedly (scroll, resize, input), debouncing prevents handlers from executing on every event:
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
const handleSearch = debounce(async (query) => {
const results = await fetchSearchResults(query);
updateUI(results);
}, 150);
searchInput.addEventListener('input', handleSearch);
4. Move Heavy Work to Web Workers
Computationally intensive tasks — data parsing, encryption, image manipulation — can be offloaded to a Web Worker, keeping the main thread free to respond to interactions:
// main.js
const worker = new Worker('heavy-task-worker.js');
button.addEventListener('click', () => {
updateButtonState('processing'); // immediate visual feedback
worker.postMessage({ data: largeDataset });
});
worker.onmessage = ({ data }) => {
updateUI(data.result);
updateButtonState('done');
};
5. Optimize React and Framework Renders
In React applications, unnecessary re-renders are a common source of INP problems:
- Use
React.memo()to prevent child components from re-rendering when props haven't changed - Move state as close to where it's used as possible to limit render scope
- Use
useDeferredValue()for non-urgent state updates - Implement virtualization (e.g., react-window) for long lists
// Defer non-critical state updates
const deferredSearchTerm = useDeferredValue(searchTerm);
// Expensive filtering runs deferred — doesn't block input response
const filteredResults = useMemo(
() => filterItems(deferredSearchTerm),
[deferredSearchTerm]
);
6. Audit and Defer Third-Party Scripts
Third-party scripts executing during interactions are a frequent source of INP degradation. Use Chrome DevTools' Performance tab to identify which scripts fire during interactions and cause long tasks.
Strategies:
- Load analytics and tag managers with
asyncordefer - Use Partytown to move third-party scripts to a web worker
- Remove scripts that aren't contributing measurable value
Measuring and Monitoring INP
Tools for INP Analysis
Chrome DevTools — Performance panel: Record an interaction and look for long tasks (red bars in the timeline). The "Interactions" track shows INP candidates.
Web Vitals Chrome Extension: Shows real-time INP scores as you interact with pages.
Field data via CrUX: Google's Chrome User Experience Report contains real-user INP data for pages with sufficient traffic. Access it via PageSpeed Insights or the CrUX API.
web-vitals JavaScript library: Instrument your own field data collection:
import { onINP } from 'web-vitals';
onINP(({ value, rating, entries }) => {
sendToAnalytics({
metric: 'INP',
value,
rating, // 'good', 'needs-improvement', or 'poor'
element: entries[0]?.target // which element was interacted with
});
});
The SEO Connection
INP is a direct ranking signal as part of the Core Web Vitals assessment, which feeds into Google's Page Experience ranking factor. Pages that score "Good" across all Core Web Vitals are eligible for a ranking boost, while pages with "Poor" scores may see suppression in competitive SERPs.
Beyond rankings, poor INP directly damages conversion rates and user satisfaction. A 500ms interaction delay feels broken to users — they click again, assume the page didn't register their input, and often leave. Use AI SEO Scanner to track your Core Web Vitals scores and identify which pages need INP attention first.
Prioritizing INP Fixes
Not every interaction on your site is equally important. Start with:
- The most common interactions — buttons in the main conversion flow (add to cart, sign up, submit)
- The slowest interactions — identified from field data with the
web-vitalslibrary - Pages with the most traffic — where improvements have the greatest impact
Run a full site audit to get a comprehensive view of performance issues across your site alongside INP data.
Struggling with poor Core Web Vitals scores? AI SEO Scanner gives you page-level performance data, INP insights, and actionable recommendations to help you pass Google's performance thresholds and protect your rankings.