Why INP Is the Most Difficult Metric
FID was comparatively easy to optimize since only the first interaction counted. A fast page build without long tasks was often sufficient. INP is fundamentally different: it measures every interaction throughout the entire page visit. A click on a filter, a tap in a search field, scrolling through a dropdown: every one of these actions is evaluated.
The reported INP value is not an average but typically the worst interaction (for few interactions) or a high percentile (for many interactions). This means a single slow interaction can ruin the page's entire INP score. This strictness makes INP the most commonly failed Core Web Vital metric.
The Three Phases of Every Interaction
Every user interaction passes through three phases whose total duration determines the INP value. The diagram above shows the typical flow. To optimize INP, you need to understand which phase consumes the most time.
Phase 1: Input Delay
Input Delay is the time between the user action (click, keypress, tap) and the start of processing by the associated event handler. Long input delay occurs when the main thread is blocked by other tasks at the time of interaction. The browser cannot start the event handler until the current task completes.
Typical causes of input delay are long tasks (JavaScript tasks over 50 ms), third-party scripts occupying the main thread, garbage collection, and style recalculations and layout calculations triggered by previous JavaScript operations.
Phase 2: Processing Time
Processing Time is the duration of event handler execution itself. When a click handler performs complex calculations, traverses DOM trees, triggers extensive state updates, or makes synchronous API calls, this phase lengthens. In modern single-page applications, processing time can be substantial, especially for actions that trigger extensive UI updates.
Phase 3: Presentation Delay
Presentation Delay is the time from the end of event handler processing to the next visible frame update in the browser. This phase encompasses style recalculations, layout calculations, paint operations, and compositing. Layout thrashing, the alternation between reading and writing DOM properties, is the most common cause of high presentation delays.
Use the Chrome DevTools Performance tab to analyze the three phases. Record a typical interaction and check which phase has the largest share. That is where the greatest optimization potential lies.
Eliminating Long Tasks: The Most Important Lever
Long tasks are JavaScript tasks that block the main thread for more than 50 milliseconds. During a long task, the browser cannot process user interactions. The sum of all long tasks is measured as Total Blocking Time (TBT) and correlates directly with the INP value.
Identifying Long Tasks
Chrome DevTools marks long tasks in the Performance tab as red bars. The PerformanceObserver API can also measure long tasks in production. XICTRAQ uses this data to identify long-task patterns and quantify their impact on INP.
Breaking Up Long Tasks with Yielding
The principle of yielding is to split long JavaScript tasks into smaller units and give the browser the opportunity to respond to user interactions between subtasks.
async function processLargeList(items) {
for (let i = 0; i < items.length; i++) {
processItem(items[i]);
// Give the browser a break every 5 items
if (i % 5 === 0) {
await scheduler.yield();
}
}
}scheduler.yield() is the most modern yielding method and has been supported by Chrome since version 115. As a fallback, you can use setTimeout(resolve, 0) in a Promise or requestIdleCallback() for low-priority tasks.
Optimizing Event Handlers
Writing Lean Handlers
An event handler should do as little work on the main thread as possible. Compute-intensive operations belong in Web Workers, network requests should be asynchronous, and visual updates should be batched via requestAnimationFrame().
- Use Web Workers: Move sorting, filtering, and calculations to a Web Worker. The main thread stays free for user interactions.
- Debouncing and throttling: Limit the execution frequency of scroll, resize, and input handlers. Not every scroll event needs an immediate response.
- Asynchronous operations: Use
fetchwithasync/awaitinstead of synchronous XMLHttpRequests. Synchronous network requests completely block the main thread. - Minimize DOM operations: Batch DOM changes and execute them in a single reflow. Document Fragments help with efficient DOM manipulation.
requestAnimationFrame for Visual Updates
When an event handler makes visual changes, it should schedule them via requestAnimationFrame() (rAF). rAF synchronizes changes with the browser's next frame update and prevents unnecessary intermediate calculations. This reduces presentation delay and ensures smooth animations.
Avoiding Layout Thrashing
Layout thrashing is one of the most common and hardest-to-diagnose INP killers. It occurs when JavaScript alternately modifies DOM elements (writes) and reads layout properties (reads). Every read operation after a write forces an immediate layout recalculation that blocks the main thread.
// BAD: Alternating reads and writes
elements.forEach(el => {
const height = el.offsetHeight; // Read -> forces layout
el.style.height = height + 10 + 'px'; // Write
});
// GOOD: Read all first, then write all
const heights = elements.map(el => el.offsetHeight); // Read all
elements.forEach((el, i) => {
el.style.height = heights[i] + 10 + 'px'; // Write all
});Layout properties that force recalculation include offsetHeight, offsetWidth, scrollTop, clientHeight, getBoundingClientRect(), and getComputedStyle(). Avoid reading these properties within loops that also make DOM changes.
Third-Party Scripts and INP
External scripts are one of the main causes of poor INP values. Analytics scripts, advertising scripts, chat widgets, and social media embeds register their own event listeners and execute their own tasks on the main thread. Each of these scripts potentially extends the input delay for user interactions.
- Load scripts with defer or async: So they do not block initial parsing and rendering
- Prioritize by importance: Business-critical scripts first, marketing pixels later
- Remove unneeded scripts: Every script that has not supported a campaign in months unnecessarily burdens the main thread. More in the article about third-party scripts.
- Use Intersection Observer: Load chat widgets and social media buttons only when the user scrolls to them
XICTRAQ detects all third-party scripts on your website and quantifies their impact on main thread utilization. This helps you identify scripts that burden the INP value most and optimize or remove them specifically.
Progressive Enhancement and Native HTML Elements
Many JavaScript implementations can be replaced by native HTML elements that respond instantly without main thread burden. This is not only beneficial for INP but also improves accessibility and reduces code complexity.
<details>/<summary>instead of JavaScript accordion: Responds instantly, no main thread load<dialog>instead of custom modal: Native modals have built-in focus management- Native form validation instead of client-side validation libraries
- CSS animations instead of JavaScript animations: CSS animations run on the compositor thread
<input type="color/date/range">instead of custom pickers: Native pickers are immediately responsive
Code Splitting and Lazy Loading JavaScript
The less JavaScript a page needs to load and execute, the better the INP. Code splitting divides your application into chunks loaded only on demand. Route-based splitting loads only the code for the current page. Component-based splitting loads complex UI components only upon interaction.
// Instead of static import
// import { HeavyChart } from './HeavyChart';
// Lazy import on demand
button.addEventListener('click', async () => {
const { HeavyChart } = await import('./HeavyChart');
HeavyChart.render(container);
});Frameworks like SvelteKit offer code splitting by default. Each route automatically receives its own bundle, and shared dependencies are extracted into shared chunks. The result: minimal JavaScript payload per page, which directly improves INP.
Measuring INP: Field and Lab Data
INP can only be reliably evaluated through field data, as lab tests cannot capture the diversity of real user interactions. Lighthouse measures TBT (Total Blocking Time) as a proxy for INP, but TBT and INP are not identical.
Chrome UX Report, PageSpeed Insights, XICTRAQ. Shows the actual INP experience of real users over 28 days.
Chrome DevTools, Lighthouse (TBT). Useful for diagnosis but not identical to real INP values.
For diagnosis, use Chrome DevTools: open the Performance tab, enable Web Vitals, and record typical interactions. The panel shows Input Delay, Processing Time, and Presentation Delay for each interaction separately.
INP Optimization for Different Website Types
Forms and Checkout Pages
Forms are interaction-intensive. Every keystroke, every field validation, and every checkout step is captured by INP. Use native form validation instead of JavaScript libraries. Validate fields asynchronously on blur, not on every keystroke. Keep checkout steps lean and load only the code for the current step.
Filters and Product Configurators
Filter functions in online shops and product configurators often trigger complex UI updates: product lists are re-sorted, prices recalculated, images swapped. Use virtual scrolling for long lists, calculate filter results in a Web Worker, and immediately show a loading indicator to give the user visual feedback while the update runs.
Content-Rich Pages with Many Interactions
News portals, social media feeds, and dashboards have many interactive elements: accordions, tabs, share buttons, comment fields. Each element registers event listeners that burden the main thread. Use event delegation (one listener on the parent element instead of each child) and implement lazy loading for interaction code needed only when visible.
INP in Interplay with LCP and CLS
INP does not exist in isolation. An optimization that improves INP could theoretically worsen LCP or CLS if not carefully implemented. Aggressive code splitting can improve responsiveness but lead to additional network requests that worsen LCP. Removing preload hints for third-party scripts improves INP but could worsen CLS if a script is needed for layout stability.
XICTRAQ monitors all three Core Web Vitals simultaneously and shows how changes affect the overall picture. The reporting function creates reports that correlate changes across all three metrics so you can identify and avoid trade-offs.
Prioritized Action Checklist
- Identify long tasks with Chrome DevTools and break them up with yielding
- Evaluate third-party scripts and remove unnecessary ones
- Keep event handlers lean and move compute-intensive logic to Web Workers
- Avoid layout thrashing by batching DOM read and write operations
- Use native HTML elements instead of JavaScript widgets
- Implement code splitting and lazy loading for interactive components
- Apply debouncing and throttling for scroll and input handlers
- Use requestAnimationFrame for visual updates
- Set up continuous INP monitoring with XICTRAQ
Setting Up Continuous INP Monitoring
Since INP measures responsiveness across all user interactions, the value can deteriorate with every deployment, code change, and new plugin. XICTRAQ monitors your Core Web Vitals including INP continuously and alerts you to deterioration.
The combination of performance monitoring, third-party script detection, regular Lighthouse audits, and SEO monitoring gives you the tools to not only detect INP problems but quickly identify their cause. Start now with a free demo or register for continuous monitoring of your website.
What exactly does INP measure?
Why do so many websites fail the INP threshold?
What is the difference between INP and TBT?
How do I find out which phase is worsening my INP?
Does a CDN help with INP optimization?
Which frameworks offer the best INP performance?
This article is based on data from: Core Web Vitals (Google).