Understanding input delay in web interactions
Every interaction on a web page—whether it's a tap, click, or key press—begins with a period of delay before the associated event callbacks actually execute. This is known as input delay, and it's a factor in how responsive your site feels to users.
Part of this delay is inherent to how operating systems and browsers process input. The OS needs time to recognize an event and forward it to the browser. That baseline is typically imperceptible. The more significant component of input delay comes from what's happening on the page itself, and that's the part you can influence.
Why input delay matters for INP
Input delay is one of several phases that make up an interaction's total duration. To meet the Interaction to Next Paint (INP) metric's "good" threshold, you want each phase—including input delay—to be as short as possible. You won't eliminate input delay entirely, but you should aim to keep it low enough that users don't perceive sluggishness when trying to interact with your page.
The key is to avoid excessive main thread work at the moments when users attempt to interact. If the main thread is clear, input delay will typically stay within acceptable bounds.
Common causes of avoidable input delay
While some delay is unavoidable, there are several common patterns that can push input delay into problematic territory. Here are the main culprits to watch for.
Recurring timers that congest the main thread
JavaScript's setTimeout and setInterval functions are two common sources of input delay. Their behavior differs in an important way: setTimeout schedules a single callback to run after a specified delay, while setInterval runs a callback every n milliseconds until stopped with clearInterval.
A single setTimeout call isn't inherently problematic—in fact, it can help break up long tasks. The issue arises when the timeout callback runs at the same moment a user attempts an interaction. A one-off callback might get in the way occasionally, but if you use setTimeout in a loop or recursively, it starts to behave more like setInterval. When that happens, you should ensure the callback isn't doing excessive work.
setInterval is the more frequent offender. Its recurring nature means it's much more likely to overlap with a user interaction, directly increasing input delay. This is particularly true if the interval callback performs substantial work on the main thread.
If these timers come from first-party code, you can evaluate whether they're necessary and reduce the work they perform. Timers in third-party scripts are trickier. You often don't have direct control over what those scripts do. Fixing performance issues there typically requires coordinating with stakeholders to decide whether the script is essential and, if so, working with the vendor to address the performance problems.
Long tasks blocking interactions
Excessive main thread work that manifests as long tasks is a straightforward contributor to input delay. If a long task is running when a user interacts with the page, the interaction's event callbacks won't run until that task completes, adding to the input delay.
The first line of defense is to minimize the amount of work performed in any single task. Beyond that, breaking up long tasks into smaller chunks can meaningfully improve responsiveness to user input.
Overlapping interactions
A more subtle challenge arises when interactions overlap. This happens when a user makes a second interaction before the first one has rendered its next frame. Rapid interactions, such as typing in form fields, frequently produce this pattern. If each key event triggers expensive work—like autocomplete fields that fire network requests to a backend—you have two practical options:
- Debounce inputs to limit how often an event callback executes within a given time window.
- Use
AbortControllerto cancel outgoingfetchrequests, preventing the main thread from becoming congested with their callbacks. Note that anAbortControllerinstance'ssignalproperty can also be used to abort events.
Expensive animations are another potential source of overlap. JavaScript-driven animations often fire many requestAnimationFrame calls, which can compete with user interactions for main thread time. Prefer CSS animations when possible, since they let animations run mainly on the GPU and compositor threads rather than the main thread—just be sure to avoid non-composited animations, which defeat that benefit.
Practical steps to reduce input delay
Input delay is seldom the largest component of an interaction's total time, but it's still a part you can and should reduce. If you're observing long input delays in your page, the opportunities for improvement are typically in three areas:
- Review recurring timer callbacks—especially
setInterval—in both first- and third-party code, and cut or lighten their workloads. - Break up long tasks so the main thread is free to handle interactions when they arrive.
- Watch for interaction overlap, particularly from rapid typing or JavaScript-driven animations, and use debouncing or
AbortControllerto keep the main thread clear.



