On this page
Long Animation Frames (LoAF)
Long Animation Frames (LoAF)
Long Animation Frames (LoAF) is a browser performance API that measures frame-update delays — any frame taking longer than 50 ms from start to paint-start. It is the successor to the Long Tasks API and provides far more actionable attribution for diagnosing slow Interaction to Next Paint (INP) interactions in ecommerce pages.
What it is
LoAF extends the Long Tasks API by capturing not just task execution time but the full frame lifecycle up to paint-start, including rendering work (requestAnimationFrame callbacks, ResizeObservers, scroll observers) that Long Tasks missed entirely. A LoAF entry is generated when the browser cannot paint a new frame within 50 ms. (Chrome for Developers docs)
The API shipped in Chrome 123 (January 2024) after an origin trial from Chrome 116–122. Browser support is limited to Chrome 123+ and Edge 123+; Firefox and Safari do not support LoAF as of 2024. (Chrome for Developers blog, 2024-06-24)
Key differences from Long Tasks API
| Dimension | Long Tasks API | LoAF |
|---|---|---|
| Scope | Task execution only | Full frame: task + render phase + paint-start |
| Script attribution | None | Invoker, sourceURL, sourceCharPosition, functionName |
| Rendering included | ❌ | ✅ (rAF callbacks, ResizeObserver, scroll handlers) |
| Cross-origin attribution | ❌ | ✅ with crossorigin="anonymous" and Timing-Allow-Origin |
| Layout thrash detection | ❌ | ✅ via forcedStyleAndLayoutDuration |
(NitroPack, 2024; DebugBear, 2023/2026)
Entry structure
Each LoAF PerformanceLongAnimationFrameTiming entry exposes: (Chrome for Developers)
startTime— when the frame startedduration— total frame duration (start → paint-start)renderStart— when rendering work beganstyleAndLayoutStart— when style/layout recalculation startedblockingDuration— total time the browser could not respond to user input within this framefirstUIEventTimestamp— non-zero if user input was queued during the frame (links frame to INP)scripts[]— array ofPerformanceScriptTimingentries for scripts >5 ms
Each script entry exposes: invoker, invokerType, sourceURL, sourceCharPosition, sourceFunctionName, forcedStyleAndLayoutDuration, pauseDuration.
invokerType values reveal how a script was triggered: classic-script (eval/initial parse), module-script, user-callback (setTimeout/setInterval), resolve-promise, reject-promise, event-listener. (web.dev, 2024-06-07)
Relationship to INP
LoAF is the primary tool for diagnosing slow INP interactions in the field. When firstUIEventTimestamp is non-zero on a LoAF entry, the frame contributed to an INP interaction. The web-vitals JS library v4 exposes longAnimationFrameEntries on the onINP() callback attribution object, connecting INP measurements directly to their causative frames. (Chrome for Developers blog, 2024-06-24)
Three diagnostic phases using LoAF data: (web.dev, 2024-06-07)
- Input delay —
invokerTypereveals what was running when the user interacted (scheduled tasks, unresolved promises) - Processing duration —
invokernames the element+event (e.g.BUTTON#save.onclick);sourceURL+sourceCharPositionpinpoint the exact code line - Presentation delay —
renderStart,styleAndLayoutStartand frame end time expose rendering costs and layout thrash
Ecommerce relevance
Third-party scripts
LoAF's script attribution is particularly valuable for ecommerce pages, which carry dense third-party script loads (analytics, advertising, consent management, personalisation). Unlike Long Tasks, LoAF can attribute a blocking frame to a specific script domain, URL, and function, enabling surgically precise removal or deferral decisions.
SpeedCurve profiled Selfridges (UK luxury ecommerce) using LoAF at 4× CPU slowdown — a Snapchat tag querying DOM elements was identified as causing slow menu-open interactions. (SpeedCurve, ~2024)
Web Almanac 2024 field data
Web Almanac 2024 analysed LoAF data by script category using RUMvision field data (as-of 2024):
(HTTP Archive Web Almanac 2024)
| Script category | Mobile good INP | Desktop good INP |
|---|---|---|
| Advertising | <50% (poor range majority) | <65% |
| User Behaviour (Hotjar, etc.) | 37% | 60% |
| CDN/Hosting (cdn.shopify.com, etc.) | 50% | 65% |
| Consent Providers | 53% | 76% |
| Analytics | majority good | majority good |
| RUM/Monitoring | among least impactful | among least impactful |
The top 1,000 most-trafficked sites have only 53% good mobile INP — worse than the web average — because high-traffic sites carry more JS, more third-party scripts, and more complex interactions. (as-of 2024)
What practitioners report
RUMvision CEO Karlijn Löwik and Erwin Hofman (We Love Speed 2024) reported from real ecommerce case studies: removing a single third-party script identified via LoAF data delivered a 77% INP improvement on one site; DeOlineDrogist.nl achieved a 53% improvement by fixing a CPU vs GPU animation issue surfaced by LoAF. (YouTube: "We Love LoAF & INP", We Love Speed 2024)
Taboola (third-party content recommendation embedded across 9,000 publisher sites) joined the LoAF origin trial to measure its INP contribution. Using LoAF attribution to identify script entries with durations of 239–997 ms, Taboola built a new rendering engine ("TRECS") using scheduler.postTask() with setTimeout fallback to yield between rendering tasks. A/B test results across 4 publishers (INP at 75th percentile, as-of 2024): (web.dev Taboola case study, 2024-02-01)
| Publisher | Before | After | Change |
|---|---|---|---|
| A | 75 ms | 48 ms | −36% |
| B | 163 ms | 153 ms | −6% |
| C | 135 ms | 92 ms | −33% |
| D | 52 ms | 37 ms | −29% |
TBT dropped from 712 ms → 206 ms (−70%) for Taboola's contribution. Ad click-through rate and RPM were not negatively impacted.
Monitoring and tooling
| Tool | LoAF support |
|---|---|
web-vitals JS library v4 | longAnimationFrameEntries on INP attribution |
| DebugBear RUM | LoAF grouped by script domain/URL |
| RUMvision | LoAF field data by script category |
| SpeedCurve RUM | Native LoAF monitoring + custom Chrome extension |
| Chrome DevTools | No native LoAF panel; requires performance.measure() with devtools detail |
| Lighthouse / PSI | Lab proxy only (TBT); cannot surface LoAF entries |
| CrUX | No LoAF entries; aggregated INP only |
(DebugBear, 2023/2026; SpeedCurve, ~2024; Request Metrics, 2024-10-17)
Optimisation patterns
- Yield to main thread between rendering tasks using
scheduler.postTask()(withsetTimeoutfallback for browser support) — demonstrated by Taboola to reduce INP 29–36%. - Identify layout thrash via
forcedStyleAndLayoutDurationon script entries — DebugBear showed 112 ms of forced layout on the Asana homepage. - Filter to user-interaction frames by querying
firstUIEventTimestamp > 0to focus remediation effort on frames that caused actual INP events. - Monitor by script domain — LoAF data enables separation of first-party vs third-party contribution; first-party code is reported as often as large a contributor as third-party. (SpeedCurve)
- Add
crossorigin="anonymous"to script tags to restoresourceURLattribution that privacy rules otherwise blank out.
Key terms
| Term | Meaning |
|---|---|
| blockingDuration | Time the browser could not respond to user input within a LoAF frame |
| firstUIEventTimestamp | Non-zero if user interaction was queued during the frame — links LoAF to INP |
| forcedStyleAndLayoutDuration | Script-level time spent forcing synchronous style/layout recalculation (layout thrash) |
| PerformanceScriptTiming | Script attribution entry: invoker, sourceURL, charPosition, functionName |
| invokerType | How the script was triggered: event-listener, user-callback, resolve-promise, etc. |
| scheduler.postTask() | Browser API to schedule tasks with priority, enabling yield between rendering chunks |
Benchmarks
- INP mobile good rate: 74% (2024), up from 64% (2023) — Web Almanac 2024 (as-of 2024)
- INP desktop good rate: 97% (2024) — Web Almanac 2024
- Top 1,000 sites mobile INP good rate: 53% (2024) — worse than web average
- Median mobile TBT: 1,209 ms (emulated Moto G Power, slow 4G) — 6× above 200 ms threshold (as-of 2024)
- Median long task: 90 ms desktop / 108 ms mobile; 90th percentile: 331 ms / 377 ms (as-of 2024, RUMvision)