Back to Blog
Core Web Vitals4 min readApril 25, 2026

INP: What It Means and Why It Matters

INP is the newest Core Web Vital. It measures how snappy your site feels — and most sites fail it because they have too much JavaScript.

text
Photo by Markus Winkler on Unsplash
Table of contents

INP — Interaction to Next Paint — is the newest Core Web Vital. It replaced First Input Delay (FID) in March 2024 because FID was too easy to pass. INP is a more honest measure of how snappy your site actually feels.

If your INP is bad, your site feels laggy. Period. Here's what it measures and how to fix it.

What INP measures

INP looks at every interaction on your page — taps, clicks, key presses — and measures how long it takes from the moment the user interacts until the next frame is painted.

It then reports the worst interaction (with some allowances for one-off outliers on long sessions). One slow interaction kills your INP score, even if everything else is snappy.

This is a deliberately strict measure. Real users remember the worst slowdowns, not the average.

The thresholds

INPRating
≤ 200ms✅ Good
200–500ms⚠️ Needs improvement
> 500ms❌ Poor

These thresholds are tight. A 500ms delay between tapping a button and seeing a response feels broken.

Why your INP is bad

The number one cause is JavaScript blocking the main thread. When the browser is busy running JavaScript, it can't respond to user input or paint new frames.

Specifically:

1. Heavy event handlers

A click handler that does too much work in a single function:

button.addEventListener("click", () => {
  // Sort 10,000 items, update DOM, send analytics, log to console...
  // All in one synchronous block.
});

2. Third-party scripts

Analytics, ad networks, tag managers, A/B testing tools — many of them install long-running handlers that fire on every interaction.

3. React (or any framework) re-rendering everything

A state change at the root of your tree can trigger thousands of components to re-render. Even with virtual DOM, that's not free.

4. Unoptimized search/filter inputs

A keypress that runs a search across 5000 items synchronously will block the main thread for hundreds of milliseconds.

5. Layout thrashing

JavaScript that reads layout properties (offsetHeight, getBoundingClientRect) and then writes back to the DOM in a loop forces the browser to recalculate layout repeatedly.

How to improve INP

Fix 1: Break up long tasks

The browser can respond to input between tasks, not during them. So splitting a 500ms task into ten 50ms tasks improves INP dramatically.

// ❌ Blocks for 500ms
function processAll(items) {
  items.forEach(processItem);
}

// ✅ Yields between batches
async function processAll(items) {
  for (let i = 0; i < items.length; i += 100) {
    const batch = items.slice(i, i + 100);
    batch.forEach(processItem);
    await new Promise((r) => setTimeout(r, 0));
  }
}

Modern browsers also support scheduler.yield() for explicit yielding to the event loop.

Fix 2: Debounce expensive handlers

Search-as-you-type, autocomplete, live filtering — anything that runs on every keystroke needs debouncing:

function debounce(fn, ms) {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), ms);
  };
}
input.addEventListener("input", debounce(search, 200));

Fix 3: Move work off the main thread

CPU-heavy work (parsing large JSON, image processing, complex calculations) belongs in a Web Worker:

const worker = new Worker("/worker.js");
worker.postMessage({ data });
worker.onmessage = (e) => updateUI(e.data);

The main thread stays free for input.

Fix 4: Reduce React re-renders

  • Use React.memo for components that re-render unnecessarily.
  • Use useMemo and useCallback for expensive computations and stable references.
  • Avoid passing new object/array literals as props on every render.
  • Split context to prevent global re-renders.

Fix 5: Audit and cut third-party scripts

Every third-party script runs on your main thread. Tag managers and analytics platforms are especially bad. See how JavaScript slows down websites for a detailed audit.

Fix 6: Use CSS for animations

transform and opacity are GPU-composited and don't block the main thread. Animating width, height, top, etc. triggers layout and paint, blocking interaction.

How to measure INP locally

INP requires real user interactions to measure properly. In Chrome DevTools:

  1. Open the Performance tab.
  2. Start recording.
  3. Interact with your page (click, scroll, type).
  4. Stop recording.
  5. Look at the "Interactions" lane — DevTools shows the time from input to next paint for every interaction.

You can also use the Web Vitals extension to see live INP as you browse.

For field data, PageSpeed Insights shows you real-user INP from Chrome's CrUX dataset.

A realistic target

Most well-built React apps land at 100–250ms INP. SaaS dashboards often hit 300–600ms because of constant data fetching and re-renders. Heavy editors (Figma, Notion) can be 500ms+ but those users tolerate it because the value is high.

For marketing sites and content pages, you should comfortably stay under 200ms.

The bottom line

INP is brutally honest about how snappy your site feels. The fix is almost always: less JavaScript, broken up into smaller chunks, with fewer third-party scripts and smarter event handlers.

For the broader Core Web Vitals story, see Core Web Vitals Explained for Beginners. For more on cutting JS, see how JavaScript slows down websites.

Frequently Asked Questions

What's a good INP score?+

200ms or less is good. 200–500ms needs improvement. Above 500ms is poor and means your site feels noticeably laggy.

How is INP different from FID?+

FID measured only the first interaction on a page. INP measures all interactions and reports the worst one. INP is harder to pass and more representative of real user experience.

Why is my INP bad even though my LCP is great?+

INP and LCP measure different things. LCP is about loading speed. INP is about responsiveness — usually killed by heavy JavaScript event handlers, third-party scripts, or React re-renders triggered by every interaction.

Rate your website for free

See how your site really performs

Run a full website health check on mobile and desktop in 30 seconds — no signup needed.

Continue reading