Core Web Vitals

INP (Interaction to Next Paint): The Complete Optimization Guide

INP replaced FID as a Core Web Vital in 2024. Learn what INP measures, why it matters for SEO, and practical optimization techniques to improve your scores.

AI SEO Scanner Team8 min read

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:

  1. Input delay — time between the user's input and the start of event handlers
  2. Processing time — how long the event handlers take to run
  3. 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

ScoreRating
200ms or lessGood
201ms – 500msNeeds Improvement
Over 500msPoor

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 async or defer
  • 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:

  1. The most common interactions — buttons in the main conversion flow (add to cart, sign up, submit)
  2. The slowest interactions — identified from field data with the web-vitals library
  3. 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.

Get Started

Ready to improve your SEO?

Run a full audit, track keywords, and get AI-powered insights — no subscription required.

Try AI SEO Scanner Free

1 credit · 1 page scanned · Credits never expire