Introduction
How to Improve INP starts with finding the work that prevents a page from responding quickly when someone clicks, taps, or types. Heavy JavaScript, expensive event handlers, long tasks, and excessive main-thread activity can delay the next visual update after an interaction. By measuring interaction latency, reducing unnecessary processing, splitting long tasks into smaller units, and updating the interface efficiently, developers can improve responsiveness and create a smoother user experience. A page can load quickly and still feel frustratingly slow when someone tries to use it.
A menu takes a moment to open. A filter responds late. A button appears to ignore the first click. A search field freezes while suggestions are generated.
These are responsiveness problems, and JavaScript is often involved.
But saying “JavaScript is slow” is too broad to be useful.
The delay can come from an event handler doing too much work, a long task occupying the main thread, expensive DOM changes, forced layout calculations, rendering work, or third-party code competing for CPU time.
Improving Interaction to Next Paint (INP) therefore requires more than minifying JavaScript or making a bundle smaller.
The practical objective is simple:
When a user interacts with the page, the browser should have enough time to respond instead of being buried under unrelated work.
This guide explains how to find that work and reduce it.

Quick Answer
To improve INP:
- Identify the interactions contributing to poor INP.
- Find long tasks and expensive JavaScript on the main thread.
- Keep event handlers small and focused.
- Break large pieces of work into smaller tasks.
- Avoid unnecessary DOM updates.
- Reduce forced synchronous layout and style calculations.
- Move suitable non-UI work away from the main thread.
- Delay non-essential JavaScript.
- Reduce third-party scripts and their execution cost.
- Avoid doing expensive work synchronously during user interactions.
- Test real interactions rather than optimizing JavaScript only by file size.
- Verify improvements in both lab tools and field data.
The goal is not simply to reduce JavaScript kilobytes.
The goal is to reduce the amount of work the browser has to perform before it can present the next visual update after an interaction.
What Actually Makes INP Poor?
An interaction can be thought of as having three broad stages:
Input delay → Processing time → Presentation delay
The browser first needs an opportunity to respond to the interaction.
Then the relevant event handlers execute.
Finally, the browser needs to perform the work required to update the page and present the result.
A delay in any of these stages can contribute to a slow interaction.
JavaScript commonly affects the processing stage, but it can also contribute to input delay when other JavaScript is occupying the main thread.
Rendering and layout work can contribute to the final stage.
This is why simply looking for a single “slow function” is not always enough.
Why JavaScript Often Causes INP Problems
JavaScript runs on the browser’s main thread in many common web applications.
The same thread is responsible for important browser work such as:
- Processing JavaScript
- Handling user input
- Calculating styles
- Performing layout
- Updating the page
- Painting
When too much work is scheduled at once, interaction can wait.
Imagine a visitor clicks a menu button at exactly the moment a large JavaScript task is running.
The click has happened.
But the browser cannot immediately execute the menu’s event handler because the main thread is occupied.
The user experiences that as a delayed response.
This is why reducing unnecessary main-thread work can be more important for INP than simply reducing the number of JavaScript files.
Long Tasks: A Major Warning Sign
A long task is a task that occupies the main thread for more than 50 milliseconds.
That does not mean every long task automatically creates a poor INP.
But long tasks are important because they can prevent the browser from responding promptly to user input.
For example:
JavaScript task
████████████████████████████████████
↑
User clicks
If the click occurs while the main thread is busy, the interaction may have to wait.
A page containing many long tasks has fewer opportunities to respond quickly.
What Creates Long Tasks?
Common sources include:
- Large JavaScript execution
- Complex calculations
- Parsing large data sets
- Processing large arrays
- Expensive framework updates
- Rendering large DOM trees
- Third-party scripts
- Hydration work
- Client-side application startup
- Large libraries doing unnecessary work
The solution is not always “remove JavaScript.”
Often the better solution is to break expensive work into smaller pieces or move non-critical work away from the interaction path.
Don’t Confuse Total JavaScript With Interaction Cost
A page may download 500 KB of JavaScript and have excellent responsiveness.
Another page might download only 150 KB and still have poor INP because one interaction triggers an expensive operation.
File size matters, but it is not the same thing as execution cost.
For INP, investigate:
- What happens when the user interacts?
- How much JavaScript executes?
- How much DOM work follows?
- How much layout and rendering occurs?
- What else is occupying the main thread?
A smaller bundle can help, but it is not the finish line.
Optimize Event Handlers
An event handler is code that responds to an event such as:
- Click
- Pointer interaction
- Keyboard input
- Touch interaction
- Form input
- Selection changes
A handler should generally do only the work required to respond to that interaction.
Consider a search box.
A poorly designed input handler might:
- Read the entire product catalog.
- Filter thousands of records.
- Sort the results.
- Rebuild a large section of the DOM.
- Measure several elements.
- Trigger additional layout calculations.
- Update multiple components.
All of that can happen because the user typed one character.
That is a poor interaction architecture.
A better implementation might:
- Debounce appropriate searches
- Keep the immediate UI update small
- Avoid rebuilding unrelated DOM
- Process expensive data separately
- Cache repeated calculations
- Update only the necessary elements
The user should not have to wait for work that has nothing to do with the immediate response.
Keep the First Response Small
An interaction often has a visible first step.
For example:
User clicks menu → menu opens
The menu opening should not have to wait for unrelated work such as:
- Analytics processing
- Large data transformation
- Recommendation calculations
- Non-critical component initialization
- Background DOM updates
Separate the immediate visual response from secondary work whenever the architecture allows it.
This is one of the most useful principles for improving perceived responsiveness.
Break Up Long Tasks
Suppose a function performs a large amount of work:
processEverything();
If processEverything() occupies the main thread for hundreds of milliseconds, user interactions can become unresponsive.
One approach is to divide the work into smaller chunks.
Conceptually:
Large task
████████████████████████████████
becomes
Task Task Task Task Task
███ ███ ███ ███ ███
Between smaller tasks, the browser gets opportunities to process pending input and rendering work.
Modern browser scheduling APIs can help with this kind of cooperative scheduling.
For example, appropriate work can sometimes be scheduled using APIs such as scheduler.postTask() where browser support and application requirements make it suitable.
The exact implementation depends on the application.
The principle is more important:
Do not monopolize the main thread when the browser needs to respond to the user.
Use requestAnimationFrame() for Visual Updates
When JavaScript needs to update visual state in response to animation or interaction, requestAnimationFrame() can help coordinate updates with the browser’s rendering cycle.
For example:
requestAnimationFrame(() => {
element.classList.add(“active”);
});
This does not magically make expensive code fast.
It is useful when you need to schedule visual updates in a way that aligns with rendering.
Do not use it as a general replacement for every asynchronous operation.
Avoid Forced Synchronous Layout
One subtle source of performance problems occurs when JavaScript changes the DOM and then immediately asks the browser for layout information.
For example:
element.style.width = “500px”;
const width = element.offsetWidth;
The browser may need to calculate layout before returning the requested value.
If code repeatedly alternates between:
write → read → write → read
it can create expensive layout work.
This pattern is sometimes described as layout thrashing.
A better approach is often to group reads and writes rather than constantly switching between them.
For example:
Read required measurements
↓
Perform updates
↓
Allow browser to render
The exact optimization depends on the code, but the underlying principle is consistent:
Avoid forcing the browser to repeatedly recalculate layout when it could do the work more efficiently.
Reduce Unnecessary DOM Work
A large DOM does not automatically mean poor INP.
The problem occurs when interactions trigger expensive operations across that DOM.
Examples include:
- Rebuilding large lists
- Changing hundreds of nodes
- Updating unnecessary components
- Recalculating styles across large sections
- Rendering hidden content unnecessarily
- Replacing entire containers when only one element changed
If a button changes one label, there may be no reason to rebuild an entire page section.
Keep updates as targeted as possible.
Be Careful With Framework Rendering
React, Vue, Angular, and other frameworks can simplify application development, but they do not remove browser performance constraints.
An interaction can still trigger:
- Component rendering
- State propagation
- DOM reconciliation
- Layout
- Painting
- JavaScript execution
When a framework application has poor INP, investigate what happens during the actual interaction.
Look for:
- Excessive component updates
- Large render trees
- Unnecessary state changes
- Expensive computations during render
- Large lists
- Repeated calculations
Framework-specific optimizations can help, but the diagnosis should begin with the work actually appearing in the performance trace.
Large Lists Can Hurt Interaction Performance
Consider a page displaying 5,000 records.
A filter interaction that causes all 5,000 items to be processed and rendered may become expensive.
Possible solutions include:
- Pagination
- Virtualization
- Incremental rendering
- More efficient filtering
- Cached calculations
- Server-side filtering
- Smaller DOM representations
The best solution depends on the application.
The key is to avoid doing substantially more work than the user needs for the current interaction.
Move Suitable Work Off the Main Thread
Some calculations do not need direct access to the DOM.
Examples might include:
- Large data transformations
- Complex calculations
- Parsing substantial data
- Image or file processing
- Computational operations
For suitable workloads, Web Workers can move JavaScript processing away from the main thread.
A simplified example:
const worker = new Worker(“/worker.js”);
worker.postMessage(data);
worker.onmessage = (event) => {
updateUI(event.data);
};
The worker does not directly manipulate the page’s DOM.
Instead, it performs the calculation and sends the result back.
This can help keep the main thread available for user interactions.
Workers are not a solution for every problem. Sending large amounts of data between the main thread and a worker also has costs.
Use them when the work is sufficiently expensive and independent from direct DOM access.
Third-Party JavaScript Can Affect INP
Your own code may not be responsible for every long task.
Third-party scripts can perform substantial work on the page.
Examples include:
- Analytics
- Advertising
- Chat widgets
- Social embeds
- A/B testing
- Heatmaps
- Marketing platforms
- Customer-support tools
A third-party script can run while a visitor is trying to interact with your page.
That creates competition for the same main-thread resources.
Review third-party scripts with the same questions you apply to first-party code:
- Is it necessary?
- Is it loaded on every page?
- Does it need to initialize immediately?
- Can it be delayed?
- Can it load only after interaction?
- Is its functionality duplicated elsewhere?
Reducing unnecessary third-party execution can improve responsiveness without changing your application’s core code.
Event Delegation Can Reduce Unnecessary Handlers
Pages with large numbers of interactive elements sometimes attach individual event handlers to every element.
For example, a list containing hundreds of items may create hundreds of listeners.
Event delegation can allow a parent element to handle events from its children.
Conceptually:
list.addEventListener(“click”, (event) => {
const item = event.target.closest(“.item”);
if (!item) return;
// Handle interaction
});
This can simplify event management and reduce some overhead.
However, event delegation is not a magic INP fix.
If the delegated handler performs expensive work, the interaction can still be slow.
Focus on the work performed in response to the event.
Debouncing and Throttling: Useful, but Not Interchangeable
High-frequency events such as input, scrolling, and pointer movement can trigger large amounts of work.
Two common techniques are debouncing and throttling.
Debouncing
Debouncing waits until events stop occurring for a period before running the expensive operation.
This can be useful for:
- Search suggestions
- Validation
- Filtering
For example, instead of running an expensive search for every keystroke, the application can wait briefly until the user pauses.
Throttling
Throttling limits how frequently a function can run.
This can be useful when updates need to happen periodically during continuous activity.
For example:
100 events
↓
only process a controlled number of updates
Neither technique should be used blindly.
If a visible interaction needs an immediate response, excessive debouncing can make the interface feel slower rather than faster.
Avoid Unnecessary Work During Clicks
A common architecture problem looks like this:
Click
↓
Update UI
↓
Save analytics
↓
Recalculate data
↓
Render recommendations
↓
Update unrelated components
↓
Send network request
The user may only care about the first step.
Separate the immediate response from secondary work whenever possible.
For example:
Click
↓
Immediate UI update
↓
Return control to browser
↓
Secondary work
The details depend on the application, but this separation can make interactions feel dramatically more responsive.
How to Find the Interaction Causing Poor INP
If field data reports poor INP, do not guess which button is responsible.
Use interaction data where available to identify the relevant element and page state.
Then reproduce the interaction in a controlled environment.
For example:
- Open the affected page.
- Start a performance recording.
- Perform the same interaction.
- Stop the recording.
- Locate the interaction in the timeline.
- Inspect the JavaScript tasks around it.
- Look for long tasks.
- Inspect style, layout, and rendering work.
- Identify the expensive operation.
- Change one thing.
- Record the interaction again.
This turns INP optimization into a debugging exercise rather than a collection of guesses.
What to Look for in a Performance Trace
When investigating an interaction, pay attention to:
Long JavaScript tasks
Was the main thread occupied for a long period?
Event handler execution
How much work happened directly because of the interaction?
Forced layout
Did JavaScript trigger expensive style or layout calculations?
DOM updates
How many elements changed?
Rendering
Did the interaction trigger substantial paint or compositing work?
Other simultaneous work
Was unrelated JavaScript executing at the same time?
This broader view matters because the code responsible for an interaction may not be the only thing delaying its visual response.
A Practical INP Optimization Workflow
Step 1: Measure
Start with field data when available.
Find out whether the problem is widespread or limited to a particular page, template, device group, or interaction.
Step 2: Identify the interaction
Determine which interaction is contributing to the poor experience.
Step 3: Reproduce it
Use browser developer tools to record the interaction.
Step 4: Find long tasks
Look for main-thread tasks that overlap the interaction.
Step 5: Inspect the handler
Determine what the event handler actually does.
Step 6: Reduce immediate work
Remove unnecessary calculations, DOM updates, and secondary processing from the interaction path.
Step 7: Break up expensive work
Split large tasks into smaller chunks when appropriate.
Step 8: Move suitable computation
Consider Web Workers for expensive calculations that do not need direct DOM access.
Step 9: Review third parties
Check whether external scripts are competing for main-thread time.
Step 10: Measure again
Compare the interaction before and after the change.
Step 11: Validate in the field
Lab improvements are useful, but real-user data is what ultimately tells you whether the experience improved for your audience.
WordPress: Improving INP
On WordPress, poor INP can come from a combination of:
- Theme JavaScript
- Page-builder code
- Plugins
- Third-party scripts
- Large DOM structures
- Interactive widgets
- Sliders
- Popups
- Filters
- Search functionality
Start with the actual interaction rather than disabling plugins randomly.
For example, if opening a mobile navigation menu takes 500 milliseconds, investigate what happens when the menu button is pressed.
Perhaps the handler:
- Recalculates a large layout
- Triggers several components
- Loads additional JavaScript
- Runs tracking code
- Changes many DOM nodes
The right fix depends on the trace.
Removing an unrelated plugin simply because it is present may not address the real problem.
Common INP Optimization Mistakes
Minifying JavaScript and expecting INP to disappear
Minification reduces source size but does not automatically eliminate expensive execution.
Focusing only on bundle size
A small script can still perform expensive work.
Breaking every task into tiny tasks
Excessive scheduling can introduce overhead and make code more complicated.
Break up genuinely expensive work where it improves responsiveness.
Debouncing everything
Too much delay can make an interface feel unresponsive even if the performance trace looks cleaner.
Moving every script to a Web Worker
Workers cannot directly manipulate the DOM and are not suitable for every workload.
Optimizing only lab data
A synthetic interaction may not represent the interactions real users experience.
Ignoring third-party code
External JavaScript can consume the same main-thread time as your own code.
Rebuilding large sections of the DOM
Small UI changes should not require unnecessary large-scale updates.
Chasing a perfect INP number
The objective is a responsive experience, not a benchmark score at any cost.
INP Targets
The current INP thresholds are:
| INP | Rating |
| 200 ms or less | Good |
| More than 200 ms to 500 ms | Needs improvement |
| More than 500 ms | Poor |
INP is evaluated using real interaction behavior and reported at the 75th percentile when assessing Core Web Vitals.
A page does not need every interaction to occur in under 200 milliseconds to provide a good overall field result.
The useful objective is to eliminate the interactions that create meaningful delays for users.
Does Reducing JavaScript Always Improve INP?
No.
Reducing unnecessary JavaScript is often helpful, but INP is about the complete interaction-to-next-paint experience.
A page can have relatively little JavaScript and still experience poor responsiveness because of:
- Expensive layout
- Large DOM updates
- Rendering work
- Main-thread contention
- Third-party scripts
Likewise, a page with substantial JavaScript can remain responsive if that work is well scheduled and does not interfere with user interactions.
The question is not:
“How much JavaScript does the page have?”
It is:
“How much work does the browser have to perform when the user interacts?”
INP Optimization Checklist
JavaScript
- Identify expensive scripts
- Remove unused JavaScript
- Reduce unnecessary execution
- Split large bundles where appropriate
- Delay non-critical code
- Review framework rendering
Event handlers
- Identify slow handlers
- Keep immediate interaction work small
- Avoid unnecessary calculations
- Avoid unnecessary DOM updates
- Use debouncing where appropriate
- Use throttling where appropriate
- Consider event delegation for suitable interfaces
Long tasks
- Find tasks longer than 50 ms
- Identify what creates them
- Break up expensive work where appropriate
- Yield to the browser between chunks
- Move suitable computation to Web Workers
DOM and rendering
- Reduce unnecessary DOM changes
- Avoid layout thrashing
- Batch DOM reads and writes
- Avoid rendering unnecessary content
- Review expensive style and layout work
Third parties
- Audit external scripts
- Remove unnecessary services
- Delay non-critical third-party code
- Load functionality only where needed
Testing
- Check field data
- Identify problematic interactions
- Record interactions in DevTools
- Compare before and after
- Validate real-user performance
Final Verdict
Improving INP is fundamentally about giving the browser room to respond.
JavaScript is frequently part of the problem, but the deeper issue is usually excessive main-thread work.
An event handler may perform too many calculations. A long task may occupy the browser when a user clicks. A large DOM update may trigger expensive layout and rendering. A third-party script may compete for CPU time at exactly the wrong moment.
The most effective approach is therefore to diagnose the interaction itself.
Find the slow interaction.
Find what occupies the main thread.
Find the work that does not need to happen immediately.
Then remove it, reduce it, split it, delay it, or move suitable computation away from the main thread.
Fast INP is not about making JavaScript disappear. It is about making the browser responsive when users need it most.
Related Guides
- What Is INP? Interaction to Next Paint Explained
- Website Speed Optimization Checklist
- How to Eliminate Render-Blocking Resources
- What Is LCP? Largest Contentful Paint Explained
- What Is CLS? Cumulative Layout Shift Explained
- Lighthouse vs CrUX: Lab Data vs Real-World Data
- How to Fix Poor LCP: A Practical Troubleshooting Guide
Recommended Resources
- web.dev: Optimize INP: Learn how to diagnose and improve Interaction to Next Paint with practical techniques.
- Google Search Central: Core Web Vitals: Review Google’s guidance on INP and the other Core Web Vitals.
- web.dev: Optimize Long Tasks: Understand how long tasks block the main thread and how to reduce their impact.
- Chrome for Developers: Performance Overview: Learn how to inspect browser performance and identify expensive JavaScript work.
- Google PageSpeed Insights: Test page performance and review available diagnostics and field data.
Leave a Reply