Interaction to Next Paint (INP): The Complete
Optimize Interaction to Next Paint (INP) to improve responsiveness. Practical strategies for reducing input delay and processing time.
Auditite Team
Table of Contents
What Is Interaction to Next Paint (INP)?
Interaction to Next Paint (INP) replaced First Input Delay (FID) as a Core Web Vital in March 2024. While FID only measured the delay before the browser began processing the first interaction, INP measures the full responsiveness of all interactions throughout a page’s lifecycle — from the user’s click or tap to the moment the browser paints the visual update.
Google’s thresholds:
- Good: INP under 200 milliseconds
- Needs Improvement: 200 to 500 milliseconds
- Poor: Over 500 milliseconds
INP is a more demanding metric than FID because it captures every interaction, not just the first one, and measures the complete cycle — input delay, processing time, and presentation delay.
The Three Phases of INP
Every user interaction goes through three phases:
1. Input Delay
The time between when the user interacts (clicks, taps, or presses a key) and when the browser starts executing the event handler. Input delay occurs when the main thread is busy with other tasks (parsing JavaScript, running timers, processing other events).
2. Processing Time
The time spent executing the event handler code. Long event handlers that perform complex calculations, DOM manipulation, or synchronous API calls extend processing time.
3. Presentation Delay
The time between when the event handler finishes and when the browser paints the visual update. This includes style recalculation, layout, and paint operations.
INP is the sum of all three phases for the worst interaction (specifically, the interaction at the 98th percentile).
Reducing Input Delay
Break Up Long Tasks
The main thread can only do one thing at a time. If a long JavaScript task is running when the user clicks, their interaction must wait until that task finishes. Long tasks (over 50ms) are the primary cause of input delay.
Solutions:
- Use
requestIdleCallbackfor non-urgent work - Break tasks into smaller chunks using
setTimeout(fn, 0)orscheduler.postTask() - Use web workers for computation-heavy operations
- Defer non-critical JavaScript so it does not compete with user interactions
Minimize Third-Party Script Impact
Analytics, chat widgets, and advertising scripts often run heavy operations on the main thread. Audit your third-party scripts and:
- Load them after initial page interaction
- Use the
asyncordeferattribute - Consider using a tag manager with trigger-based loading
- Remove scripts that provide minimal value
Optimize Event Listeners
Avoid adding event listeners to high-frequency events (scroll, mousemove, resize) without throttling or debouncing. These can saturate the main thread and block other interactions.
Reducing Processing Time
Optimize Event Handler Code
Review your click handlers, form submissions, and other interactive code for:
- Unnecessary DOM queries — Cache DOM references instead of querying on every interaction
- Expensive DOM mutations — Batch DOM changes and use
requestAnimationFramefor visual updates - Synchronous operations — Move file reads, storage operations, and calculations to async patterns
- Redundant computation — Memoize results that do not change between interactions
Use Efficient Data Structures
If your event handlers process large data sets (filtering, sorting, searching), use appropriate data structures and algorithms. A linear search through thousands of items on every keystroke creates terrible INP.
Avoid Layout Thrashing
Reading layout properties (offsetHeight, getBoundingClientRect) followed by writing to the DOM forces the browser to recalculate layout synchronously. This pattern, called layout thrashing, dramatically increases processing time.
Fix: Batch all DOM reads together, then all DOM writes together. Or use requestAnimationFrame to separate read and write cycles.
Reducing Presentation Delay
Simplify CSS Selectors
Complex CSS selectors (deeply nested, universal, attribute selectors) slow down style recalculation after DOM changes. Keep selectors simple and specific.
Reduce DOM Size
Pages with massive DOM trees (over 1,500 elements) take longer to recalculate styles and layout after interactions. Simplify your markup and avoid deeply nested structures.
Use CSS Containment
The contain CSS property tells the browser that changes within an element do not affect elements outside it, allowing the browser to optimize layout and paint operations:
.component {
contain: layout style;
}
Avoid Forced Synchronous Layouts
Similar to layout thrashing, any code that forces the browser to complete layout before continuing (reading layout properties after DOM changes) increases presentation delay.
Measuring INP
Lab Testing
INP is difficult to measure in lab environments because it depends on real user interactions. However, you can:
- Use Chrome DevTools Performance panel — Record interactions and measure total event processing time
- Use Lighthouse user flows — Script interactions and measure responsiveness
- Manual testing — Click through your site while monitoring the Performance panel
Field Data
Field data is essential for INP because it captures real user behavior:
- Chrome User Experience Report (CrUX) — Aggregated real-user INP data
- Google Search Console — Core Web Vitals report includes INP
- Web Vitals JavaScript library — Measure INP from your own users
Identifying the Worst Interactions
Use the Web Vitals library with attribution to identify exactly which interactions have the worst INP scores:
- Which element was interacted with
- What type of interaction (click, keypress, etc.)
- How long each phase (input delay, processing, presentation) took
This data tells you precisely where to focus optimization efforts.
Framework-Specific INP Optimization
React
- Use
useMemoanduseCallbackto prevent unnecessary re-renders - Implement virtualization for long lists (react-window, react-virtuoso)
- Use
useTransitionto mark non-urgent state updates - Use concurrent features (startTransition) to keep the UI responsive during heavy updates
Vue
- Use computed properties instead of methods for derived data
- Implement virtual scrolling for large lists
- Use
v-oncefor content that never changes - Lazy load components with
defineAsyncComponent
Vanilla JavaScript
- Use event delegation instead of individual listeners on many elements
- Implement debouncing for input-driven updates
- Use
requestAnimationFramefor visual updates - Break expensive operations into chunks with
scheduler.yield()
INP Optimization Checklist
- No long tasks over 50ms on the main thread during interactions
- Third-party scripts are loaded after critical content
- Event handlers complete in under 100ms
- No layout thrashing (mixed reads and writes)
- DOM size is under 1,500 elements
- CSS containment applied to independent components
- Field INP measured and monitored with real user data
- Worst interactions identified and optimized
Key Takeaways
INP is the most technically challenging Core Web Vital to optimize because it touches every aspect of your site’s interactivity:
- Reduce input delay by breaking up long tasks and deferring non-critical JavaScript
- Optimize processing time by writing efficient event handlers and avoiding layout thrashing
- Minimize presentation delay through CSS containment, simplified selectors, and smaller DOM trees
- Measure with real users — lab data alone cannot capture the full INP picture
- Focus on the worst interactions — your 98th percentile interaction determines your INP score
Combined with strong LCP and CLS scores, optimized INP ensures your site feels fast and responsive to every user interaction.
Stay in the loop
Get insights, strategies, and product updates delivered to your inbox.
No spam. Unsubscribe anytime.
Ready to see Auditite in action?
Get started and see how Auditite can transform your SEO auditing workflow.
Get started