Home›Journal›This post

Long Animation Frames API: Find UI Jank

Capture a privacy-bounded long-animation-frame receipt, preserve missing attribution, correlate it with one action, and validate one predicted repair.

JP
JP Casabianca
AI Engineer and Product Designer · full-stack delivery · Bogotá

A slow interaction score says the page felt late; it does not name the work that delayed a frame. The Long Animation Frames API can turn a supported local frame into a bounded diagnostic receipt, provided missing attribution and experimental support remain explicit.

What the Long Animation Frames API measures

A browser aims to produce visual updates on a cadence, but the main thread can spend too long running script, recalculating style, laying out, and preparing paint. A long animation frame is a frame whose rendering update lasts beyond the API's 50-millisecond exposure threshold. The entry describes a frame-sized episode of work; it is not simply another name for a long task.

That difference is useful. Long Tasks identifies main-thread tasks over its threshold and provides coarse attribution. Interaction to Next Paint measures the latency of user interactions in the field or a page session. The Long Animation Frames API places script and rendering-related timestamps in a frame-oriented record. These tools can overlap, but their entries do not have a one-to-one identity.

The practical question is not “Did the page ever exceed 50 ms?” It is “For the product action I can reproduce, which available frame evidence tells me what to inspect next?” A frame can contain several script entries, rendering work, and missing fields. It may begin before the action mark or end after the interaction's event processing.

Treat the 50 ms rule as an observation filter, not a universal responsiveness budget. A shorter frame may still matter on a high-refresh display, and a long frame outside a user action may not explain poor interaction latency. The LoAF API is an attribution bridge between a symptom and a focused profile, not a complete UI jank attribution system.

Long animation frame autopsy timelineA synthetic 76 millisecond frame is divided into script, rendering before style and layout, style and layout, and remaining frame time. A hatched threshold band marks blocking beyond 50 milliseconds.SYNTHETIC 76 MS FRAME · RAW BOUNDARIESSCRIPTRENDERSTYLE +LAYOUTREMAINDER50 ms exposure thresholdThe final span is not automatically ‘paint’; preserve the API’s limits.
A frame timeline narrows inspection while refusing to name phases the entry did not expose.
Synthetic frame anatomy
BoundaryValueSafe interpretation
Start1000 msFrame entry begins.
Render start1034 ms34 ms before rendering starts.
Style/layout start1047 ms13 ms from render start.
End1076 ms29 ms remain; not automatically paint.
Blocking duration26 msAPI-derived blocking amount for this fixture.

Detect Long Animation Frames API support first

The Long Animation Frames API is experimental and not available in every browser. Before constructing an observer, check that PerformanceObserver exists and that its supportedEntryTypes list contains “long-animation-frame.” Keep the unsupported state visible in the interface and export. Absence is not a zero-frame result; it means this diagnostic channel is unavailable.

When supported, create a PerformanceObserver with the long-animation-frame type and buffered delivery if the browser accepts it. Wrap construction and observation in error handling because a partially implemented browser or policy can still reject options. Process existing buffered entries, then future entries, until the local storage cap is reached. After 50 records, refuse additional payloads but count every refused record until the user stops capture; that preserves an explicit loss signal without retaining an unbounded buffer. This PerformanceObserver frame timing path stays optional.

Feature detection should govern only the LoAF path. The product must remain usable without it, and the lab provides deterministic replay fixtures in every browser. An unsupported browser can still use DevTools, Event Timing where available, Long Tasks, manual performance marks, or a recorded trace. It just cannot claim a LoAF observation.

Do not polyfill synthetic PerformanceLongAnimationFrameTiming objects and label them browser evidence. A replay fixture is valuable for teaching and tests, but its provenance must say fixture. Frontend observability for product UI offers a broader measurement envelope; this tutorial keeps the experimental capability local and optional.

Read a long animation frame as a timeline

Start with raw timestamps from the Long Animation Frames API. A frame entry has a start time and duration. Its rendering start, style-and-layout start, first UI event timestamp, and blocking duration may add phase clues depending on browser support and the entry. In the 28 April 2026 W3C First Public Working Draft, a script attribution record can expose execution timing, source location, invoker, and invokerType. Preserve those versioned fields before deriving spans; accept older entryPoint data only through an explicitly labeled compatibility path.

Derive only what the available fields support. If renderStart is a positive finite timestamp not before frame start, the pre-render span can be renderStart minus startTime. If styleAndLayoutStart is positive and not before renderStart, the render-before-style span can be derived. The remainder to frame end is not automatically paint time: other rendering and bookkeeping may be included. Name it “remaining frame span,” not a phase the API did not measure directly.

Zero often means unavailable in performance timelines. A renderStart of zero must remain unavailable; subtracting the frame start would produce a negative fiction. Reject non-finite values, negative duration, or phase timestamps outside the frame. The lab caps timestamps at 10^15 ms and durations at 86,400,000 ms, checking addition before export. Keep malformed entries in a rejected-count receipt with reasons rather than forcing them onto the timeline.

The first figure uses a synthetic frame to teach the anatomy. Its semantic table exposes each value so color is not required. In a real capture, display unavailable cells explicitly and let the raw entry accompany any derived view. The timeline should narrow a profiling question, not upgrade partial timestamps into complete rendering truth.

Use script attribution carefully

Long Animation Frames API script records can expose an invoker, invoker type, source URL, function name, or character position, but availability varies with the evolving browser surface. Cross-origin code, browser internals, workers, extensions, privacy constraints, and implementation limits can leave attribution empty. Empty attribution means unknown, not “rendering was the cause.” Preserve no-script, unavailable-script, cross-origin-unattributed, and attributed states separately.

An entry point is also not necessarily the hottest function. A click handler may call a framework update that triggers many downstream functions and forced layout. The exposed URL and function identify a place to begin a profile. Validate the hypothesis with a CPU trace, source map, or a small controlled change rather than assigning blame from one label.

Treat source detail as privacy-sensitive. The local lab converts source URLs to an originless path label, removes query strings and fragments, caps length, and never reads DOM text, input values, user identifiers, or page content. For cross-origin sources it uses a bounded marker instead of copying a full URL. Exporting an exact application path can still reveal product structure, so a production pipeline may need a route allowlist or stable code-bundle identifier.

The Chrome LoAF guide gives field examples, while the W3C draft defines the evolving model. Read both against the browser version under test. Attribution is evidence with gaps, not a complete flame chart.

LoAF, Long Task, and INP comparisonThree aligned horizontal lanes show different entry boundaries for a long animation frame, a long task, and an interaction. Their overlaps are connected with dotted guides rather than equality signs.RELATED SIGNALS · DIFFERENT QUESTIONSLoAF frameLong TaskINP interactionOverlap supports correlation; it does not prove equivalence or cause.
Use INP for interaction latency, Long Tasks for task episodes, and LoAF for supported frame attribution.
Comparison matrix
SurfaceUnitDoes not prove
LoAFLong rendering updateInteraction latency or root cause
Long TaskMain-thread task episodeComplete frame anatomy
INP / Event TimingUser interaction latencyWhich script or rendering phase caused it
Correlation
Entries overlap in time around the same user action.
Causation
A separate profile or controlled experiment establishes the responsible work.

Correlate LoAF with product action and INP

A useful Long Animation Frames API capture begins with a named action: open the filters panel, drag a timeline handle, submit a form, or switch a dense tab. Place a performance mark immediately before the application initiates that action and another after its expected visual state is committed. Store a coarse route label and action identifier, not user text. Then select overlapping long-animation-frame entries by timestamp.

Event Timing and INP answer a different question. Interaction latency includes input delay, processing duration, and presentation delay for eligible interactions. A LoAF entry can overlap part of that interval and reveal frame work, but overlap is correlation. The interaction can span more than one frame, background work can share the same frame, and presentation timing is not fully described by LoAF.

Debugging INP with PerformanceObserver can identify the interaction and its timing. Use Long Animation Frames API entries after that step to ask whether the overlapping frame exposes script or rendering clues. Keep both timestamps and their clock basis in the receipt. Do not equate blockingDuration with INP or subtract one from the other as if they were nested measurements.

The same caution applies to Long Tasks. Align the three lanes visually, but label the entry boundaries separately. The comparison figure lists what each surface measures, where attribution can appear, and what claim it cannot support. That prevents a dashboard from turning three related signals into three copies of one metric.

Capture a privacy-bounded UI jank receipt

Use local Long Animation Frames API capture for one deliberate named action. Cap the observer at 50 entries and the two-space-indented download, including its final newline, at 65,536 UTF-8 bytes. Store a schema version, capture mode, support state, timestamps relative to navigation, coarse route/action labels, raw frame timing, permitted derived spans, redacted scripts, rejected-entry counts, and the cap state.

If field telemetry is later justified, sample sparingly and document the data path. Timing plus route, code path, device class, and account context can become identifying. Avoid DOM text, selectors assembled from user content, raw URLs, stack traces with secrets, or network payloads. Apply allowlists before collection rather than trying to scrub an unrestricted record afterward.

Keep these states distinct: unsupported API, supported but no entries, frame with no scripts, frame with scripts whose source is unavailable, cross-origin unattributed work, malformed entry, and buffer capped. A single empty array cannot explain why no attribution is present. The lab exports state alongside entries so downstream readers do not infer “fast” from “unknown.”

The replay fixtures cover each state and remain labeled synthetic. They make the interface, redaction, and export code testable on a browser without support. They do not prove that the browser would emit identical fields. That distinction is the core privacy and truth contract of the artifact.

Evidence-to-repair decision treeA frame receipt branches by script evidence, layout evidence, and unavailable attribution. Rectangle, diamond, and dashed capsule shapes identify evidence, decision, and unknown states.LET EVIDENCE CHOOSE THE NEXT INSPECTIONbounded frame receiptSCRIPT CLUELAYOUT CLUEUNAVAILABLEprofile / sliceinspect invalidationprofile, do not guess
Every branch predicts one check, then reruns the same product action and protects accessibility.
  1. Script clue: profile the entry path; reduce or slice measured work.
  2. Layout clue: inspect invalidation, forced measurement, structure, and containment.
  3. Unavailable attribution: use a profiler or controlled feature isolation; do not assign cause.
  4. For every repair: replay the same action, compare repeated runs, and verify focus, keyboard, announcements, and reduced motion.

Choose and verify one repair

Read the Long Animation Frames API evidence tree as a hypothesis generator. If script execution dominates and a named entry point is available, profile that path. Remove redundant work, reduce algorithmic cost, or slice cooperative work across turns. scheduler.yield for responsive long tasks can preserve continuation priority when support and semantics fit; postTask versus requestIdleCallback compares other scheduling choices. Yielding everywhere can add overhead and does not repair expensive layout.

If style-and-layout time is large, inspect invalidation scope, forced synchronous measurement, DOM size, and read/write ordering. Containment or simpler structure may help, but only after confirming the affected component. If attribution is unavailable, do not guess. Reproduce the action in a profiler, disable one feature at a time, or add safe application marks.

Change one meaningful factor, then replay the same fixture, device profile, content, and action. Predict what should move before running: fewer script milliseconds, later render work avoided, or no long frame at all. Compare multiple runs because one trace is noisy. Protect keyboard order, focus, announcements, reduced motion, and visual completion while optimizing; a faster interaction that loses accessibility fails the product gate.

The MDN long animation frame timing reference is useful for availability and fields, but the experiment still needs an application-specific acceptance rule. Success is a verified repair to one action, not an impressive screenshot.

Ship progressive diagnostics, not a dependency

Keep the observer out of the critical product path. Load the diagnostic only for an explicit debugging session or a carefully sampled telemetry path, and let unsupported browsers continue normally. Disconnect it after the requested action. When the storage cap is full, refuse later payloads while incrementing a dropped count until stop rather than retaining unbounded entries. A tool intended to explain jank should not create continuous work or transmit data by default.

Version the receipt with the draft and browser surface it expects. Recheck support and field semantics on 2026-12-23 or when the W3C draft, browser implementation, or privacy guidance changes. The API can evolve; treating the exported schema as permanent would turn an experimental diagnostic into hidden technical debt.

Use the result alongside field INP, focused profiles, product marks, and accessibility checks. Long Animation Frames API evidence can narrow the next question to script, rendering, or unknown. It cannot prove causality, describe every frame, replace a profiler, certify presentation timing, or stand in for real-user experience.

That modest role is still powerful. A bounded receipt makes “the UI felt janky” inspectable without pretending to see more than the browser exposed. When the data is absent, say unavailable. When a repair is predicted, rerun the same action. The discipline around uncertainty is what turns an experimental API into useful engineering evidence.

Runnable local artifact — LoAF is experimental and not universal; a frame entry is diagnostic correlation, not proof of a root cause or a replacement for INP.

Plain text1 line
Feature-detect supportedEntryTypes, cap the buffer, derive spans only from present timestamps, redact source URLs, and preserve unsupported and unattributed states.