Back to blog
Core Web Vitals Monitor8 min readApril 18, 2026

How to Improve INP: Causes and Solutions for Interactivity

INP measures the latency of all user interactions on your page. Since March 2024 it replaced FID as the official Core Web Vital. Learn how to diagnose it and reduce it with concrete techniques.


INP (Interaction to Next Paint) is the newest and most challenging Core Web Vital to optimize. Since March 2024 it replaced FID as the official interactivity metric. While FID only measured the delay before the first click, INP measures the response latency of all user interactions throughout the entire visit: clicks, keyboard presses, and taps. Poor INP makes the page feel sluggish and unresponsive even if it loads quickly.

How is INP calculated exactly?

For each user interaction, the browser measures the time between the input event (click, key, tap) and the next painted frame on screen. The reported INP is the 98th percentile of all interactions in the session — meaning it discards the worst 2% to prevent a one-off outlier from ruining the metric, but it does penalize consistently slow interactions.

INP thresholdRatingExperience
≤ 200 ms✅ GoodResponse feels instantaneous
200 – 500 ms⚠️ Needs improvementPerceptible lag, degraded experience
> 500 ms❌ PoorPage feels blocked or broken

INP is measured with real field data (CrUX), not just in the lab. This means PageSpeed Insights may show an estimated INP that differs from what Google uses for ranking, which comes from real Chrome user data. If your page has low traffic, there may not be enough field data and Google uses only the lab value.

The root cause of high INP: the blocked main thread

High INP almost always has the same root cause: the browser's main thread is busy processing JavaScript when the user interacts. The browser is single-threaded — it cannot process user events and execute JavaScript simultaneously. If a long task (> 50ms) is running when the user clicks, the response is delayed until that task finishes.

Cause 1: Long JavaScript tasks

A long task is any task that blocks the main thread for more than 50ms. The user feels the lag when a long task is running exactly when they try to interact. The longer the task, the worse the INP.

  • Identify long tasks with Chrome DevTools → Performance → record while interacting. Long tasks appear as red blocks in the timeline.
  • Break up long tasks using scheduler.yield() or setTimeout(fn, 0) to yield control to the browser between work chunks.
  • Prioritize what JavaScript runs on the main thread — move non-urgent work to Web Workers.
javascript
// Technique: break up a long task with scheduler.yield()
async function processLargeList(items) {
  for (let i = 0; i < items.length; i++) {
    processItem(items[i])

    // Yield control to the browser every 50 items
    // so it can process user interactions
    if (i % 50 === 0) {
      await scheduler.yield()
      // or: await new Promise(resolve => setTimeout(resolve, 0))
    }
  }
}

Cause 2: Costly event handlers

The work executed by the event handler (the function responding to the click or key press) consumes part of the INP time budget. If the handler performs expensive operations — complex DOM queries, heavy calculations, large re-renders — INP increases.

  • Move non-urgent work outside the event handler using requestAnimationFrame or setTimeout — execute the visible part first, defer the rest.
  • Avoid interleaving DOM reads and writes in the same handler (layout thrashing).
  • Use debounce or throttle on handlers that respond to frequent events (scroll, resize, input).
javascript
// Incorrect: all work in the handler blocks the response
button.addEventListener('click', () => {
  const data = calculateComplexData()  // expensive task
  updateUI(data)
  sendAnalytics(data)  // not urgent
})

// Correct: defer non-urgent work
button.addEventListener('click', () => {
  // Urgent work: update UI immediately
  updateUIQuick()

  // Non-urgent work: defer to next frame
  requestAnimationFrame(() => {
    const data = calculateComplexData()
    updateUIFull(data)
    setTimeout(() => sendAnalytics(data), 0)
  })
})

Cause 3: Costly renders in SPA frameworks (React, Vue, Angular)

In React, Vue, or Angular applications, an interaction can trigger a re-render of a large component tree. If the render is expensive, INP rises. This is the most common issue in SPAs with a lot of shared state.

  • In React: use React.memo, useMemo, and useCallback to prevent unnecessary re-renders of unchanged components.
  • Defer non-urgent re-renders with useTransition or startTransition — React processes the update without blocking user interactions.
  • Split large components into smaller pieces so re-renders are more granular.
  • In Vue: use computed properties carefully and avoid watchers that trigger cascading effects.
javascript
// React: use startTransition to defer non-urgent renders
import { startTransition, useState } from 'react'

function ProductSearch() {
  const [query, setQuery] = useState('')
  const [results, setResults] = useState([])

  const handleInput = (e) => {
    // Urgent update: show what the user is typing
    setQuery(e.target.value)

    // Non-urgent update: search and render results
    startTransition(() => {
      setResults(searchProducts(e.target.value))
    })
  }

  return <input value={query} onChange={handleInput} />
}

Cause 4: Third-party scripts blocking the main thread

Third-party scripts (analytics, chat widgets, A/B testing, maps, social buttons) compete with your code for the main thread. A third-party script that runs heavy code can increase the INP of pages that would otherwise be fully interactive.

  • Load third-party scripts with defer or async so they do not block the initial render.
  • Use the loading="lazy" attribute or the Intersection Observer API to load third-party scripts only when the user needs them (for example, load the chat widget only when the user scrolls to the footer).
  • Audit which third-party scripts are active using Chrome DevTools Coverage panel and remove those that are not essential.
  • Consider loading Google Tag Manager conditionally — many GTM tags can be loaded after the user's first interaction.

How to diagnose your site's INP

iRankly's Core Web Vitals Monitor shows you the current INP for each URL using PageSpeed Insights data. Identify which pages have INP in the "Needs improvement" or "Poor" range to prioritize optimization.

Try the tool for free

Core Web Vitals MonitorAnalyze your URLs with {tool} by iRankly. No sign-up, no credit card.

Use tool for free

For a deeper diagnosis, install the Chrome Web Vitals extension and browse your site while interacting with elements — click things, open menus, use forms. The extension shows INP in real time and identifies which specific interaction is causing the highest latency.

High INP is usually concentrated on specific pages or interactions, not across the entire site. Before optimizing globally, identify the 3–5 interactions with the highest latency and focus on those — the impact will be much greater with less effort.


Try the tool for free

Analyze your URLs with Core Web Vitals Monitor by iRankly. No sign-up, no credit card.

Use tool for free