What diagnostic approach should you use when INP scores are poor at the 75th percentile but good at the median, indicating a long-tail interaction problem?

A gap between a good median INP and a poor p75 means the problem isn’t universal, it’s concentrated in a specific subset of interactions, users, or device/network conditions rather than affecting every session equally. The diagnostic approach has to move past the single headline p75 number and into segmented, distributional data: which interaction types, which page states, and which user segments are actually driving the slow tail, since the median tells you the “typical” experience is fine and the tail tells you something specific is going wrong for a meaningful minority.

Why a good median INP can still hide a poor p75

INP field data as reported through CrUX is a percentile-based aggregate metric (Google evaluates it at p75 specifically for pass/fail purposes), which necessarily collapses a full distribution of individual interaction latencies into a smaller number of summary points. A good median with a poor p75 is a classic sign of a distribution with a “fat tail,” meaning most interactions are fast, but a substantial enough minority are slow that the 75th-percentile mark falls into the poor range. This pattern is common when a specific subset of causes only affects some interactions or some users, rather than a uniform, universal slowdown that would depress the median too.

Common concrete causes behind this fingerprint: certain interaction types (a complex filter or search interaction, a modal open, a specific button that triggers heavy re-render) are slow while most simple interactions (basic nav clicks, simple toggles) are fast, pulling only part of the distribution into poor territory; certain device tiers (lower-end phones with less CPU headroom) experience the same interaction as much slower than higher-end devices, so the aggregate median (dominated by the more common, often better-performing segment) looks fine while the tail (disproportionately lower-end devices) drags p75 down; or certain page states (a page with more items loaded, more DOM complexity built up during a session, or third-party scripts that load progressively and add cost later in a session) make later interactions slower than early ones in the same session.

It’s also worth ruling out a purely statistical artifact before assuming a genuine performance problem: INP, unlike LCP or CLS, is reported per page load as the single worst (or near-worst, under the current high-percentile-within-session methodology) interaction observed during that session, not an average across all interactions. A page with very few total interactions per session (say, only one or two clicks before navigation) produces a noisier per-session INP value than a page where users interact heavily, since a single unusually slow interaction, caused by something transient like a garbage-collection pause or a background tab losing CPU priority, can dominate that session’s reported value. Low-interaction-volume templates are more prone to this kind of noise inflating the tail, which is a different problem from a genuine, reproducible slow interaction pattern and calls for a different response (more data before acting, rather than immediately optimizing code).

How to diagnose and fix the slow INP tail

Don’t stop at the CrUX headline p75 number. Use CrUX’s full distribution data (histogram bins across “good,” “needs improvement,” and “poor” ranges, available via the CrUX API and BigQuery dataset) rather than only the summary percentile, to understand how fat the tail actually is and get a sense of what share of interactions are affected.

Segment CrUX or your RUM data by device category and effective connection type, since device/network segment concentration is one of the most common drivers of this exact good-median/poor-p75 pattern; if the poor tail correlates heavily with lower-end devices or slower connections, that tells you the fix needs to target main-thread cost reduction that specifically benefits constrained devices (code splitting, reducing JS execution, avoiding heavy work on interaction), not a uniform fix.

Deploy the web-vitals JavaScript library’s attribution build in production RUM, which can report which specific interaction target (element/event type) is associated with each recorded INP value, letting you identify whether specific UI components (a particular filter, a particular modal, a particular data-heavy interaction) are disproportionately represented in the slow tail rather than treating “the page” as a monolithic thing to optimize.

Once you’ve identified the specific interaction type, device segment, or page-state pattern responsible, apply targeted fixes (yielding long tasks specifically around that interaction, reducing DOM complexity for that specific component, deferring non-critical work that accumulates over a session) rather than broad, page-wide performance work that would improve the already-fine median without addressing the actual tail-driving cause.

Reproduce the suspected slow interaction locally using Chrome DevTools’ Performance panel with CPU throttling set to a lower-end profile (a 4x or 6x slowdown, approximating the CPU headroom of a mid-tier or budget Android device rather than the development machine’s own hardware). Record the interaction and look specifically at the breakdown DevTools now provides for INP’s three phases, input delay, processing time, and presentation delay, since each phase points to a different fix. A long input delay usually means the main thread was already busy with something else (a long task from script execution) when the interaction occurred, which points toward reducing or better-scheduling background JS work. A long processing time points at the event handler itself doing too much synchronous work, which points toward breaking that handler into smaller chunks using techniques like scheduler.yield() or setTimeout-based yielding so the browser can paint in between. A long presentation delay, the time between the browser finishing its handler work and the next frame actually painting, often implicates expensive style recalculation or layout work triggered by the interaction, which is a different fix again (simplifying the DOM subtree affected, avoiding layout thrashing).

Check whether the affected interaction correlates with a specific rendering framework’s hydration or re-render behavior, particularly on sites built with client-side-heavy JavaScript frameworks. A common pattern behind an isolated slow-tail interaction is a component that re-renders a disproportionately large subtree on every state change (a full list re-render triggered by selecting one item, for example) when only a small part of the DOM actually needed to update; this shows up cleanly in the DevTools Performance panel as a long “processing” phase tied to a specific component’s render function, and the fix is typically scoped to that component (memoization, narrowing the re-render boundary) rather than anything page-wide.

Avoid assuming a specific percentile threshold beyond Google’s actual published p75 pass/fail standard when interpreting or reporting on this data; the diagnostic value here is in the shape of the distribution, not in inventing additional formal thresholds Google hasn’t defined.

Leave a Reply

Your email address will not be published. Required fields are marked *