How I trace an interaction from tap to next paint

Every Interaction to Next Paint (INP) measurement is the sum of three distinct phases: input delay (waiting for a busy main thread), processing time (running your event handlers), and presentation delay (recalculating styles, layout, and painting pixels). When a merchant tells me their store feels sluggish on mobile, I don’t guess—I open the Chrome DevTools Performance profiler and record real taps on variant swatches, mobile navigation drawers, and collection filters.

By Google’s official Core Web Vitals standard, a good INP is at or below 200 milliseconds, anything between 200 ms and 500 ms needs improvement, and anything above 500 ms is poor. Because field INP is reported at the 75th percentile of worst visit interactions, a single 350 ms stall when switching shirt sizes is enough to push a high-traffic store into the "needs improvement" bucket.

Why I yield to the browser between critical and secondary work

The pattern I see most often in slow Shopify themes is an event listener that tries to do everything synchronously in a single long task: updating the active swatch state, recalculating B2B volume tables, re-rendering 40 DOM nodes, and firing three analytics beacons before letting the browser paint a single frame.

To fix this, I split the handler in two. First, I update the immediate visual state (such as highlighting the selected size button or showing a subtle loading spinner), then I yield back to the browser using `scheduler.yield()` (with a macrotask `setTimeout` fallback) so the browser can paint that frame immediately before my code continues with heavier secondary work.

JAVASCRIPT
export function yieldToBrowser() {
  if (globalThis.scheduler?.yield) {
    return globalThis.scheduler.yield();
  }
  return new Promise(resolve => setTimeout(resolve, 0));
}

export async function respondToSelection(showSelection, doSecondaryWork) {
  showSelection();
  await yieldToBrowser();
  await doSecondaryWork();
}

My main-thread yielding helper that prioritizes immediate visual paint before secondary processing.

My repeatable 5-step INP audit protocol

  1. I reproduce the exact interaction on a mid-tier mobile device or 4x CPU slowdown in DevTools.
  2. I inspect the flame chart for long tasks (>50 ms), forced synchronous layouts, and oversized DOM trees.
  3. I strip redundant listeners or split non-critical work across task boundaries while keeping UI state consistent.
  4. I stress-test rapid repeated taps, keyboard navigation, and network error states.
  5. I monitor 28-day field telemetry after deployment, because a green Lighthouse lab score never measures full-visit INP.
CONCEPT / PERFORMANCE
  1. 01Measure
  2. 02Diagnose
  3. 03Improve
  4. 04Remeasure
Measure a real interaction, diagnose the cause, make a change, then measure again.
INP thresholds
ClassificationDuration
Good≤ 200 ms
Needs improvement> 200 ms to 500 ms
Poor> 500 ms

Sources & review

Maintains the official Web Vitals INP thresholds (≤200 ms good, 200–500 ms needs improvement, >500 ms poor) and avoids unsubstantiated blame percentages. The scheduling helper below is a standalone browser pattern from my performance toolkit.

Content reviewed 2026-10-25. Written in the first person by Mifan Twan Ardana. No production client benchmark is claimed.