A visitor taps a menu icon and nothing seems to happen for a beat. Then the menu opens, but the beat was enough to make the site feel sluggish. Interaction to Next Paint (INP) is the Core Web Vitals metric built to capture that beat. In short: INP watches the latency of clicks, taps and key presses during a visit and, for most pages, reports the slowest one. A value of 200 milliseconds or less is good, and anything above 500 milliseconds is poor.
This guide is written for SEOs, front-end developers and site owners who need to move from "INP is failing" to a concrete fix. It starts with what INP counts and what it ignores, then shows how to locate the slow interaction in real-user data. From there it uses the three-phase model of an interaction to work through long tasks, event handlers, rendering cost and third-party scripts, and it ends with a prioritized fix list. Nothing here promises a ranking outcome. The aim is a page that responds quickly to real people, and every change should be confirmed against your own measurements.
What INP Measures and Its Thresholds
Before changing code, be clear about what the number represents. The web.dev INP article (Opens in a new tab) is the primary reference for the definition, the calculation and the thresholds used below.
The definition in plain terms
INP is a stable Core Web Vital that measures responsiveness using the Event Timing API. It records the latency of every click, tap and keyboard interaction during a visit and reduces them to a single value. An interaction is the group of event handlers that fire during one logical gesture, such as pointerdown, pointerup and click for a tap, or keydown, keypress and keyup for a keystroke.
Latency runs from the moment the user acts to the moment the next frame is painted on screen. That detail matters: a fast script that triggers an expensive repaint still produces a slow interaction.
How the single number is chosen
The page's INP is computed when the user leaves it. For most sites the interaction with the worst latency is reported. On pages with many interactions, one of the highest is ignored for every 50 interactions, so a single freak event does not decide the result. The reported figure is then the 75th percentile across page views, split by mobile and desktop.
| Rating | INP at the 75th percentile | What a visitor feels |
|---|---|---|
| Good | 200 ms or less | Controls respond right away |
| Needs improvement | Above 200 ms, up to 500 ms | A noticeable pause after input |
| Poor | Above 500 ms | The page feels stuck |
What is outside the metric
Mouse clicks, taps on a touchscreen and key presses are observed. Scrolling, hovering and zooming are not, although a gesture inside one of those that includes a click, tap or key press can still be measured. A page where people only scroll may report no INP at all, and bots or headless browsers without scripted interaction report none either. An absent value therefore does not prove the page is responsive.
INP replaced First Input Delay. FID looked only at the input delay of the first interaction, which made it mostly a load-time responsiveness check. INP covers all interactions, from input delay through processing and presentation, whenever they happen.
Two edge cases that confuse reports
If a page is restored from the back/forward cache, its INP resets to zero, because the visitor experiences it as a fresh visit. And interactions inside iframes count toward the top-level page experience. The Event Timing API does not hand iframe entries to the parent directly, so sub-frames have to forward them. A payment widget, an embedded map or an ad frame can therefore be the source of a slow interaction even when your own template looks clean.
Field Data First, Lab Second
Responsiveness depends on what people do and when they do it, so a single lab load can miss the problem completely. Start with field data to confirm that a problem exists and where, then reproduce it in the lab to understand why. The general split between the two data types is covered in CrUX field data vs lab data; this section covers only what is specific to INP.
Reading the field signal you already have
PageSpeed Insights shows CrUX data for a URL or origin, and that is a fine way to learn whether INP passes. According to web.dev's optimization guide, though, CrUX usually lacks context: it does not tell you which interaction was slow, whether it happened during or after load, or whether it was a click, a tap or a keypress. For that you need real-user monitoring, either from a provider or built on the web-vitals library.
Attribution: turning a number into a suspect
The web.dev page on finding slow interactions in the field (Opens in a new tab) documents the attribution build of web-vitals. Its onINP callback exposes interactionTarget, a CSS selector for the element involved, and interactionType, the kind of input. It also exposes inputDelay, processingDuration and presentationDelay, the three phase durations, and longAnimationFrameEntries, the Long Animation Frame entries tied to the interaction.
Each Long Animation Frame entry carries script attribution. The invoker names what started the work, the invoker type says whether it was an event listener, a user callback, a promise resolution or a classic or module script, and the source URL and function name point at the code. That is the difference between "the page is slow" and "this listener in this file takes the time."
Reading the phases like a diagnosis
The guidance on the page maps each long phase to a place to look.
- Long processing: sort the scripts in the last Long Animation Frame entry by duration and take the longest.
- Long input delay: look at the first entry. A classic or module script means script evaluation during load, a user callback means timers or requestAnimationFrame work, an event listener means an earlier input was still being handled, and promise types mean asynchronous work that resolved mid-interaction.
- Long presentation delay: compare renderStart with styleAndLayoutStart to estimate requestAnimationFrame work, and use startTime plus duration to estimate style and layout time.
Reproducing it in the lab
The optimization guide suggests following common user flows and testing interactions along the way, including interactions during page load, when the main thread is usually at its busiest. A scripted "load, wait, click" run will often miss the case that real visitors hit, which is tapping something while the page is still booting.
Worked scenario: a search box that stutters
This is an example scenario, not a measured case. Imagine a marketplace page where typing in the search box freezes the keyboard feedback for a moment. Attribution shows the interaction type is a keypress, the target is the search input, and the processing duration dominates. The input delay is small, so reducing script loading would do nothing. The useful move is to look at what the key handler does synchronously, such as filtering a large list and rebuilding it in the DOM, and to defer that work after the input field updates.
Long Tasks and Main-Thread Work
The main thread is a single lane. Script execution, style calculation, layout and event handlers all queue on it, and while a task is running the browser cannot start handling a tap.
What counts as a long task
web.dev's page on optimizing long tasks (Opens in a new tab) defines a long task as any task that takes longer than 50 milliseconds, with the blocking period being the time beyond those 50 ms. JavaScript runs each task to completion regardless of how long it blocks. One click handler that calls several functions in a row can therefore delay visible feedback and drive up INP, even if each function looks harmless alone.
Where input delay comes from
The optimization guide lists the typical causes of input delay: main-thread work while scripts load, parse and compile, fetch handling, timer functions, and interactions that overlap in quick succession. Script evaluation during load can create long tasks. A visitor who taps a cart icon moments after arrival may be waiting behind a script that has not finished booting.
Breaking work apart
Splitting a long job into smaller tasks lets the browser slip input handling in between. The long-task page describes two main tools.
| Technique | How it behaves | Watch out for |
|---|---|---|
| setTimeout(fn, 0) | Runs the callback in a new task so user-visible work can go first | After five nested calls browsers add a minimum 5 ms delay, and the deferred task goes to the back of the queue |
| scheduler.yield() | Pauses with await and resumes in a new task, with the continuation prioritized ahead of similar tasks | Support listed as Chrome 129, Edge 129 and Firefox 142; Safari is not supported, so feature-detect |
The page suggests a progressive-enhancement form, await globalThis.scheduler?.yield?.(), and warns to check both the global scheduler and its yield method. Without support, the browser still yields through the fallback, but the prioritized continuation is lost. A scheduler polyfill is another option.
Freshness note: support for scheduler.yield() and isInputPending() depends on the browser version, so check current browser support before you use them.
Mistakes that undo the benefit
- Forgetting await. Calling scheduler.yield() only schedules a task, and the await is what actually pauses.
- Using forEach and expecting a pause between items. Iterative array methods do not wait for each callback, so use a loop where you can await.
- Yielding after every tiny job. Yielding has overhead, so for long queues the page's pattern is to yield only once a deadline, 50 ms in its example, has passed. That deadline can be tuned to trade responsiveness against total completion time.
The same page no longer recommends isInputPending(). It can return false after a user interaction, input is not the only reason to yield, and scheduler.postTask() and scheduler.yield() now cover those needs. If your codebase still depends on it, plan to move on.
Decision rule for splitting work
Yield before work that the user did not ask to see right now, and after work that gives visible feedback. Do not yield after every function call. If a task is under the long-task line and the interaction is still slow, the cause is probably not scripting length at all, and the presentation phase deserves a look.
Event Handlers and Rendering Cost
Processing duration and presentation delay are the two phases you control most directly through your own templates and scripts.
Handlers should do the minimum
The optimize INP guide (Opens in a new tab) advises doing as little work as possible in event callbacks and splitting the rest into separate tasks. Its recommended order is to update the interface first and defer everything else. The sample code queues non-critical work, such as a word count, spell checking and saving, with requestAnimationFrame and a nested setTimeout after the visual update.
Apply the same idea to a checkout button: show the pressed state and the progress indicator at once, then validate, log and prefetch in later tasks. The shopper sees a response; the heavy lifting still happens.
Layout thrashing
If code changes styles and then reads layout values in the same task, the browser has to recalculate layout synchronously. This is layout thrashing. In the DevTools Performance panel it shows up with a red triangle and the labels Recalculate Style or Layout. Batch all reads first and all writes after, instead of alternating them inside a loop.
DOM size and presentation delay
Presentation delay is the time from the end of callbacks to the next painted frame. The guide notes that rendering work grows with DOM size, not linearly, and that large DOMs hurt both the initial render and rendering after interactions. Its suggestions are to flatten the DOM or add elements during interactions rather than up front, and to use content-visibility so off-screen elements render lazily.
It also warns that client-side HTML rendering with JavaScript can stop the browser from yielding until parsing and rendering finish. That is fine in small amounts and costly in large ones. Expanding an accordion that inserts thousands of nodes at once is a typical trigger; rendering the content in slices or on demand avoids it.
Which phase, which fix
| Dominant phase | Where to look | First fix to try |
|---|---|---|
| Input delay | Invoker type of the first Long Animation Frame entry | Reduce script loaded at start, break up tasks, defer non-essential code |
| Processing duration | Longest script in the last entry | Update the UI first, then yield before the rest |
| Presentation delay | Gap between renderStart and styleAndLayoutStart, style and layout time | Shrink the DOM, use content-visibility, remove forced layouts |
Iframes have their own thread
Each iframe has its own main thread, yet INP is reported at the page level and includes iframes. When an interaction is slow, check which frame it happened in before editing the parent page. Fixing the wrong document is the most common wasted effort in INP work.
Third-Party Load and a Prioritized Fix List
Analytics tags, chat widgets, consent tools and ad scripts all spend main-thread time. Publishers who depend on ad revenue face a real trade-off, which is discussed in ads and Core Web Vitals: the publisher balance.
Loading order for third-party scripts
The web.dev guide to loading third-party JavaScript (Opens in a new tab) says to always use async or defer unless the script is necessary for the critical rendering path. Async downloads in parallel and then pauses parsing to run, while defer runs after parsing. Async suits scripts that should run early, such as some analytics, and defer suits less critical content. Do not use async for essential libraries such as jQuery. In Blink-based browsers both attributes lower request priority, so a tag may load later than you expect.
Resource hints help too: dns-prefetch does the lookup early, and preconnect also sets up TCP and TLS, which the guide says can greatly decrease load time. For embeds that are only needed later, such as an ad low on the page, lazy loading with IntersectionObserver is preferred over scroll listeners, with the caveat that it relies on JavaScript and can be disrupted on unreliable networks.
Measuring before removing
The page gives a method for estimating a third party's cost. Turn on network and CPU throttling, record a baseline, block the suspect URLs with Block Request URL in DevTools, reload, and measure at least three times. In the Performance panel's Bottom-up view, Group by product shows time per vendor. Lighthouse also has audits for JavaScript boot-up time and network payloads, and a PerformanceObserver on longtask entries can attribute long tasks to a frame.
The page does not publish numeric budgets for third parties, so a rule such as "no more than N tags" has no source behind it. Treat the decision as a measured trade-off between value and cost.
A prioritized fix list
- Confirm in field data which page group and device fail INP.
- Pull the offending interaction from real-user attribution: target, type, and whether it happened during load.
- Split the delay into its three phases and name the dominant one.
- If input delay dominates, remove or defer scripts that run during load and add async or defer to third-party tags.
- If processing dominates, update the interface first and yield before the remaining work.
- If presentation dominates, reduce DOM size, use content-visibility and remove forced layouts.
- Ship one change at a time, wait for field data to refresh and compare.
Verifying the Change and Reporting It
A better lab trace is encouraging but it is not the verdict, because the INP assessment comes from the field. Field data accumulates over time, so plan to compare after enough new visits have been recorded. For broader context see the page speed and Core Web Vitals guide, and for reading a score on its own, the PageSpeed Insights score explained.
Pre-release checklist
- The target interaction and affected page group are written down before the change.
- Mobile and desktop are tracked separately.
- Interactions during load were tested, not only after load.
- The change targets one phase rather than several at once.
- Feature detection and a fallback exist wherever scheduler.yield() is used.
- Removing or deferring a third party does not break a business requirement such as consent or payment.
What a useful report contains
Record the affected page group, the dominant phase, the change made and the release date. Field improvements appear with a delay, so a dated log is the only way to connect cause to effect later. When there is no INP value because nobody interacted or there is not enough data, say so plainly instead of presenting an empty report as a pass.
Misreadings to avoid
- "A single lab run showed no slow click, so the page is fine." A lab run cannot know when and what real visitors will tap.
- "The average delay is low." INP is closer to the worst interaction, read at the 75th percentile.
- "The page loads quickly, so responsiveness is fine." Loading speed and responsiveness are separate measurements.
- "One optimization fixes all three phases." Each phase has different causes.
Who owns which fix
Input delay usually involves script and tag governance, processing involves the application logic a developer wrote, and presentation involves template structure and DOM size. The SEO owner picks which page groups matter, the developer reads the attribution records, and whoever manages ads or analytics decides which third parties are truly required. Agreeing on this split turns a vague request to make the site faster into testable tasks. And because field data lags, changing one thing per release makes it clear what worked.
Frequently Asked Questions
What is INP and what counts as a good score?
INP is the Core Web Vitals metric that tracks the latency of clicks, taps and key presses during a visit and, for most pages, reports the slowest interaction. Per web.dev, at the 75th percentile 200 ms or less is good, above 200 ms up to 500 ms needs improvement, and above 500 ms is poor. Mobile and desktop are assessed separately.
How is INP different from First Input Delay?
INP replaced FID. FID measured only the input delay of the first interaction. INP covers every interaction, including input delay, processing and presentation, regardless of when it happens during the visit.
Do scrolling and hovering affect INP?
No. Scrolling, hovering and zooming are not observed. Clicks, taps and key presses are, including those inside such gestures. A page where visitors only scroll may report no INP value at all.
Where should I start when INP fails?
Start with field data to find the failing page group and device, then use real-user attribution to find the interaction. Split its delay into input delay, processing duration and presentation delay, fix only the dominant phase, and compare once field data has refreshed.
Is scheduler.yield() supported everywhere?
According to the web.dev page, it is listed for Chrome 129, Edge 129 and Firefox 142, and Safari is not supported. Feature-detect it and fall back to a setTimeout-based approach; the fallback loses the prioritized continuation.
Should I remove all third-party scripts to improve INP?
Not automatically. Measure first: throttle the network and CPU, record a baseline, block the suspect URL and measure again at least three times. Remove what is not needed, use async or defer for the rest, and note that the documentation gives no numeric budget for third parties.
Conclusion
INP tells you how quickly a page answers real input, and the verdict comes from field data at the 75th percentile. The route to improvement is consistent: find the slow interaction with real-user attribution, divide its latency into input delay, processing duration and presentation delay, then apply the fix that belongs to the dominant phase. Splitting long tasks, updating the interface before the rest of the work, shrinking the DOM and managing third-party scripts by measurement cover most cases. No step guarantees a particular ranking result; the point is a smoother experience for real visitors.
If you sell or buy advertising placements, choose positions that respect page responsiveness. You can review available placements and terms on the Akua Adforce ad spaces page; scope and conditions are listed on the product page.
Post a comment
Please log in to leave a comment. Login