[{"data":1,"prerenderedAt":1139},["ShallowReactive",2],{"content:\u002Fcore-web-vitals-measurement\u002Flong-animation-frames-api\u002Floaf-vs-long-tasks-api":3,"surroundings:\u002Fcore-web-vitals-measurement\u002Flong-animation-frames-api\u002Floaf-vs-long-tasks-api":1130},{"id":4,"title":5,"body":6,"description":1108,"extension":1109,"meta":1110,"navigation":1123,"path":1124,"seo":1125,"stem":1128,"__hash__":1129},"content\u002Fcore-web-vitals-measurement\u002Flong-animation-frames-api\u002Floaf-vs-long-tasks-api\u002Findex.md","LoAF vs the Long Tasks API",{"type":7,"value":8,"toc":1092},"minimark",[9,14,42,45,158,163,214,218,327,331,340,351,361,494,498,503,506,693,699,705,711,806,809,813,819,849,853,856,860,866,996,1000,1003,1013,1019,1022,1026,1041,1050,1054,1077,1082,1085,1088],[10,11,13],"h1",{"id":12},"loaf-vs-the-long-tasks-api-which-observer-should-feed-your-inp-debugging","LoAF vs the Long Tasks API: Which Observer Should Feed Your INP Debugging?",[15,16,17,18,23,24,28,29,33,34,37,38,41],"p",{},"This comparison belongs to the ",[19,20,22],"a",{"href":21},"\u002Fcore-web-vitals-measurement\u002Flong-animation-frames-api\u002F","Long Animation Frames topic"," in ",[19,25,27],{"href":26},"\u002Fcore-web-vitals-measurement\u002F","Core Web Vitals & Measurement",". Both APIs report main-thread congestion above the ",[30,31,32],"code",{},"50ms"," threshold, and many RUM setups still collect ",[30,35,36],{},"longtask"," entries out of habit. The question is whether that data can still earn its beacon bytes now that ",[30,39,40],{},"long-animation-frame"," exists.",[15,43,44],{},"The short answer: for diagnosing Interaction to Next Paint, LoAF supersedes Long Tasks in Chromium. The longer answer depends on what else you use task data for — Total Blocking Time approximations, cross-browser coverage plans, or historical dashboards you do not want to break.",[15,46,47],{},[48,49,55,56,55,63,55,67,55,70,55,79,55,85,55,94,55,100,55,105,55,110,55,113,55,116,55,119,55,122,55,125,55,128,55,133,55,137,55,139,55,143,55,145,55,148,55,150,55,153,55,155,55],"svg",{"viewBox":50,"width":51,"role":52,"ariaLabel":53,"style":54},"0 0 760 228","100%","img","Side-by-side comparison of what a long task entry and a long animation frame entry report for the same slow interaction.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[57,58],"rect",{"className":59,"x":61,"y":61,"width":51,"height":51,"fill":62},[60],"svg-canvas","0","#ffffff",[64,65,66],"title",{},"What each observer actually tells you",[68,69,53],"desc",{},[57,71],{"x":72,"y":72,"width":73,"height":74,"rx":75,"fill":76,"stroke":77,"style":78},"1","758","226","10","none","currentColor","stroke-opacity:0.18",[80,81,66],"text",{"x":82,"y":83,"fill":77,"style":84},"28.0","34.0","font-size:16px;font-weight:700",[57,86],{"x":82,"y":87,"width":88,"height":89,"rx":90,"fill":91,"stroke":92,"style":93},"56.0","340.0","150.0","6","#ffc300","#b8860b","fill-opacity:0.24;stroke-opacity:0.9",[80,95,99],{"x":96,"y":97,"fill":77,"style":98},"42.0","82.0","font-size:14px;font-weight:700","longtask entry",[80,101,104],{"x":96,"y":102,"fill":77,"style":103},"108.0","font-size:12.5px;font-weight:700","•",[80,106,109],{"x":87,"y":102,"fill":77,"style":107,"textAnchor":108},"font-size:12.5px","start","One task over 50ms, start and duration",[80,111,104],{"x":96,"y":112,"fill":77,"style":103},"132.0",[80,114,115],{"x":87,"y":112,"fill":77,"style":107,"textAnchor":108},"attribution usually reads unknown or window",[80,117,104],{"x":96,"y":118,"fill":77,"style":103},"156.0",[80,120,121],{"x":87,"y":118,"fill":77,"style":107,"textAnchor":108},"Rendering work after the task is invisible",[80,123,104],{"x":96,"y":124,"fill":77,"style":103},"180.0",[80,126,127],{"x":87,"y":124,"fill":77,"style":107,"textAnchor":108},"Several 40ms tasks in one frame are never reported",[57,129],{"x":130,"y":87,"width":88,"height":89,"rx":90,"fill":131,"stroke":131,"style":132},"392.0","#0466c8","fill-opacity:0.14;stroke-opacity:0.9",[80,134,136],{"x":135,"y":97,"fill":77,"style":98},"406.0","long-animation-frame entry",[80,138,104],{"x":135,"y":102,"fill":77,"style":103},[80,140,142],{"x":141,"y":102,"fill":77,"style":107,"textAnchor":108},"420.0","Whole frame from first task to paint",[80,144,104],{"x":135,"y":112,"fill":77,"style":103},[80,146,147],{"x":141,"y":112,"fill":77,"style":107,"textAnchor":108},"Each script with URL, function and invoker",[80,149,104],{"x":135,"y":118,"fill":77,"style":103},[80,151,152],{"x":141,"y":118,"fill":77,"style":107,"textAnchor":108},"renderStart and styleAndLayoutStart for the tail",[80,154,104],{"x":135,"y":124,"fill":77,"style":103},[80,156,157],{"x":141,"y":124,"fill":77,"style":107,"textAnchor":108},"Forced layout time per script",[159,160,162],"h2",{"id":161},"rapid-diagnosis-is-your-current-data-actionable","Rapid Diagnosis: Is Your Current Data Actionable?",[164,165,166,185,202,208],"ul",{},[167,168,169,176,177,180,181,184],"li",{},[170,171,172,173,175],"strong",{},"Inspect a week of ",[30,174,36],{}," attribution."," If more than 90% of entries carry ",[30,178,179],{},"name: \"self\""," and a container of ",[30,182,183],{},"window",", your long-task data identifies that the thread was busy and nothing more.",[167,186,187,190,191,194,195,198,199,201],{},[170,188,189],{},"Look for slow interactions without long tasks."," An INP of ",[30,192,193],{},"260ms"," composed of five ",[30,196,197],{},"40ms"," tasks produces no ",[30,200,36],{}," entries at all — but one LoAF entry.",[167,203,204,207],{},[170,205,206],{},"Check whether presentation delay is ever attributed."," Long Tasks cannot see style, layout and paint after your script returns; if your INP breakdown shows presentation delay dominating, you have been blind to its cause.",[167,209,210,213],{},[170,211,212],{},"Count browsers."," If a large share of your RUM comes from Safari and Firefox, neither API covers it; the choice between them is a Chromium-only decision.",[159,215,217],{"id":216},"the-comparison","The Comparison",[219,220,221,237],"table",{},[222,223,224],"thead",{},[225,226,227,231,234],"tr",{},[228,229,230],"th",{},"Axis",[228,232,233],{},"Long Tasks API",[228,235,236],{},"Long Animation Frames API",[238,239,240,252,263,280,291,302,316],"tbody",{},[225,241,242,246,249],{},[243,244,245],"td",{},"Unit",[243,247,248],{},"One task over 50ms",[243,250,251],{},"One frame over 50ms",[225,253,254,257,260],{},[243,255,256],{},"Script attribution",[243,258,259],{},"Container only, usually unhelpful",[243,261,262],{},"URL, function, char position, invoker",[225,264,265,268,271],{},[243,266,267],{},"Rendering visibility",[243,269,270],{},"None",[243,272,273,276,277],{},[30,274,275],{},"renderStart",", ",[30,278,279],{},"styleAndLayoutStart",[225,281,282,285,288],{},[243,283,284],{},"Forced layout",[243,286,287],{},"Not reported",[243,289,290],{},"Per script",[225,292,293,296,299],{},[243,294,295],{},"Many short tasks",[243,297,298],{},"Missed entirely",[243,300,301],{},"Captured as one long frame",[225,303,304,307,310],{},[243,305,306],{},"Blocking metric",[243,308,309],{},"Duration over 50ms per task",[243,311,312,315],{},[30,313,314],{},"blockingDuration"," per frame",[225,317,318,321,324],{},[243,319,320],{},"Support",[243,322,323],{},"Chromium",[243,325,326],{},"Chromium 123+",[159,328,330],{"id":329},"root-cause-analysis-why-long-tasks-misled-teams","Root Cause Analysis: Why Long Tasks Misled Teams",[15,332,333,336,337,339],{},[170,334,335],{},"1. The task is the wrong unit for an interaction."," A user experiences the delay between input and the next paint. That span can include several tasks and a rendering step. A metric that only fires when one task exceeds ",[30,338,32],{}," systematically misses the \"death by several cuts\" pattern common in framework apps, where each microtask batch is modest.",[15,341,342,345,346,350],{},[170,343,344],{},"2. Attribution was structurally limited."," Long Tasks attribute to a ",[347,348,349],"em",{},"container"," — the frame or iframe — not to a script. For first-party work in the top frame, that is always \"the page\". Teams built elaborate timestamp-correlation heuristics to compensate; LoAF makes them unnecessary.",[15,352,353,356,357,360],{},[170,354,355],{},"3. Rendering was invisible."," A handler that returns in ",[30,358,359],{},"20ms"," but invalidates layout for 10,000 nodes produces no long task; the expensive work happens in the browser's rendering step. LoAF reports it as the render tail of the frame.",[15,362,363],{},[48,364,55,367,55,370,55,373,55,375,55,378,55,380,55,389,55,393,55,400,55,406,55,409,55,412,55,416,55,420,55,424,55,428,55,431,55,434,55,437,55,441,55,445,55,450,55,455,55,460,55,466,55,469,55,473,55,477,55,480,55,484,55,490,55],{"viewBox":365,"width":51,"role":52,"ariaLabel":366,"style":54},"0 0 760 226","A timeline in which five tasks each under 50 milliseconds plus rendering add up to a 230 millisecond frame that only LoAF reports.",[57,368],{"className":369,"x":61,"y":61,"width":51,"height":51,"fill":62},[60],[64,371,372],{},"Five short tasks, no long task, one long frame",[68,374,366],{},[57,376],{"x":72,"y":72,"width":73,"height":377,"rx":75,"fill":76,"stroke":77,"style":78},"224",[80,379,372],{"x":82,"y":83,"fill":77,"style":84},[381,382],"line",{"x1":383,"y1":384,"x2":383,"y2":118,"stroke":92,"strokeWidth":385,"strokeDashArray":386,"style":388},"599.9","72.0","1.5",[387,387],"4","stroke-opacity:0.9",[80,390,392],{"x":82,"y":391,"fill":77,"style":103},"96.0","Tasks",[57,394],{"x":395,"y":396,"width":397,"height":398,"rx":399,"fill":131,"stroke":131,"style":132},"96.5","78.0","99.3","26.0","3",[80,401,197],{"x":402,"y":403,"fill":77,"style":404,"textAnchor":405},"146.1","95.5","font-size:11.5px","middle",[57,407],{"x":408,"y":396,"width":397,"height":398,"rx":399,"fill":131,"stroke":131,"style":132},"197.3",[80,410,197],{"x":411,"y":403,"fill":77,"style":404,"textAnchor":405},"247.0",[57,413],{"x":414,"y":396,"width":415,"height":398,"rx":399,"fill":131,"stroke":131,"style":132},"298.2","112.0",[80,417,419],{"x":418,"y":403,"fill":77,"style":404,"textAnchor":405},"354.1","45ms",[57,421],{"x":422,"y":396,"width":423,"height":398,"rx":399,"fill":131,"stroke":131,"style":132},"411.6","86.7",[80,425,427],{"x":426,"y":403,"fill":77,"style":404,"textAnchor":405},"455.0","35ms",[57,429],{"x":430,"y":396,"width":423,"height":398,"rx":399,"fill":131,"stroke":131,"style":132},"499.8",[80,432,427],{"x":433,"y":403,"fill":77,"style":404,"textAnchor":405},"543.2",[57,435],{"x":436,"y":396,"width":423,"height":398,"rx":399,"fill":91,"stroke":92,"style":93},"588.1",[80,438,440],{"x":439,"y":403,"fill":77,"style":404,"textAnchor":405},"631.5","render",[80,442,444],{"x":82,"y":443,"fill":77,"style":103},"134.0","Reported",[57,446],{"x":395,"y":447,"width":448,"height":398,"rx":399,"fill":77,"stroke":77,"style":449},"116.0","578.4","fill-opacity:0.06;stroke-opacity:0.4",[80,451,454],{"x":452,"y":453,"fill":77,"style":404,"textAnchor":405},"385.6","133.5","one long-animation-frame entry (230ms)",[381,456],{"x1":457,"y1":118,"x2":458,"y2":118,"stroke":77,"style":459},"95.7","726.0","stroke-opacity:0.4",[80,461,465],{"x":462,"y":463,"fill":464,"style":404,"textAnchor":405},"106.4","173.0","#51617a","0ms",[80,467,32],{"x":468,"y":463,"fill":464,"style":404,"textAnchor":405},"221.8",[80,470,472],{"x":471,"y":463,"fill":464,"style":404,"textAnchor":405},"347.8","100ms",[80,474,476],{"x":475,"y":463,"fill":464,"style":404,"textAnchor":405},"473.9","150ms",[80,478,479],{"x":383,"y":463,"fill":464,"style":404,"textAnchor":405},"200ms",[80,481,483],{"x":482,"y":463,"fill":464,"style":404,"textAnchor":405},"715.3","250ms",[80,485,489],{"x":383,"y":486,"fill":487,"style":488,"textAnchor":405},"68.0","#8a6608","font-size:12px;font-weight:700","INP 200ms",[80,491,493],{"x":82,"y":492,"fill":464,"style":107},"204.0","The Long Tasks API reports nothing here because no single task crosses 50ms.",[159,495,497],{"id":496},"step-by-step-migration","Step-by-Step Migration",[499,500,502],"h3",{"id":501},"_1-add-a-loaf-observer-next-to-the-existing-one","1. Add a LoAF observer next to the existing one",[15,504,505],{},"Run both for a release so you can compare coverage before deleting anything.",[507,508,513],"pre",{"className":509,"code":510,"language":511,"meta":512,"style":512},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","const supportsLoAF = PerformanceObserver.supportedEntryTypes?.includes('long-animation-frame');\nif (supportsLoAF) {\n  new PerformanceObserver((l) => queueLoAF(l.getEntries()))\n    .observe({ type: 'long-animation-frame', buffered: true });\n} else {\n  new PerformanceObserver((l) => queueLongTasks(l.getEntries()))\n    .observe({ type: 'longtask', buffered: true });\n}\n\u002F\u002F trade-off: falling back to longtask on non-LoAF engines gains nothing today —\n\u002F\u002F the engines without LoAF also lack longtask. The branch only helps older\n\u002F\u002F Chromium builds; drop it once their share of your traffic is negligible.\n","javascript","",[30,514,515,548,557,591,614,626,650,668,674,681,687],{"__ignoreMap":512},[516,517,519,523,527,530,534,538,541,545],"span",{"class":381,"line":518},1,[516,520,522],{"class":521},"sPARh","const",[516,524,526],{"class":525},"sPXB4"," supportsLoAF",[516,528,529],{"class":521}," =",[516,531,533],{"class":532},"saISM"," PerformanceObserver.supportedEntryTypes?.",[516,535,537],{"class":536},"smZ65","includes",[516,539,540],{"class":532},"(",[516,542,544],{"class":543},"sZ8jY","'long-animation-frame'",[516,546,547],{"class":532},");\n",[516,549,551,554],{"class":381,"line":550},2,[516,552,553],{"class":521},"if",[516,555,556],{"class":532}," (supportsLoAF) {\n",[516,558,560,563,566,569,573,576,579,582,585,588],{"class":381,"line":559},3,[516,561,562],{"class":521},"  new",[516,564,565],{"class":536}," PerformanceObserver",[516,567,568],{"class":532},"((",[516,570,572],{"class":571},"sQw3B","l",[516,574,575],{"class":532},") ",[516,577,578],{"class":521},"=>",[516,580,581],{"class":536}," queueLoAF",[516,583,584],{"class":532},"(l.",[516,586,587],{"class":536},"getEntries",[516,589,590],{"class":532},"()))\n",[516,592,594,597,600,603,605,608,611],{"class":381,"line":593},4,[516,595,596],{"class":532},"    .",[516,598,599],{"class":536},"observe",[516,601,602],{"class":532},"({ type: ",[516,604,544],{"class":543},[516,606,607],{"class":532},", buffered: ",[516,609,610],{"class":525},"true",[516,612,613],{"class":532}," });\n",[516,615,617,620,623],{"class":381,"line":616},5,[516,618,619],{"class":532},"} ",[516,621,622],{"class":521},"else",[516,624,625],{"class":532}," {\n",[516,627,629,631,633,635,637,639,641,644,646,648],{"class":381,"line":628},6,[516,630,562],{"class":521},[516,632,565],{"class":536},[516,634,568],{"class":532},[516,636,572],{"class":571},[516,638,575],{"class":532},[516,640,578],{"class":521},[516,642,643],{"class":536}," queueLongTasks",[516,645,584],{"class":532},[516,647,587],{"class":536},[516,649,590],{"class":532},[516,651,653,655,657,659,662,664,666],{"class":381,"line":652},7,[516,654,596],{"class":532},[516,656,599],{"class":536},[516,658,602],{"class":532},[516,660,661],{"class":543},"'longtask'",[516,663,607],{"class":532},[516,665,610],{"class":525},[516,667,613],{"class":532},[516,669,671],{"class":381,"line":670},8,[516,672,673],{"class":532},"}\n",[516,675,677],{"class":381,"line":676},9,[516,678,680],{"class":679},"sjfSM","\u002F\u002F trade-off: falling back to longtask on non-LoAF engines gains nothing today —\n",[516,682,684],{"class":381,"line":683},10,[516,685,686],{"class":679},"\u002F\u002F the engines without LoAF also lack longtask. The branch only helps older\n",[516,688,690],{"class":381,"line":689},11,[516,691,692],{"class":679},"\u002F\u002F Chromium builds; drop it once their share of your traffic is negligible.\n",[15,694,695,696,698],{},"Expected outcome: within a day, you can see how many slow interactions had zero ",[30,697,36],{}," entries but a LoAF entry — usually a meaningful share on framework-heavy pages.",[499,700,702,703],{"id":701},"_2-rebuild-your-blocking-time-approximation-on-blockingduration","2. Rebuild your blocking-time approximation on ",[30,704,314],{},[15,706,707,708,710],{},"If dashboards chart a field \"TBT-like\" figure from long tasks, switch to summing ",[30,709,314],{}," across frames between FCP and a cutoff.",[507,712,714],{"className":509,"code":713,"language":511,"meta":512,"style":512},"let fieldBlocking = 0;\nfunction queueLoAF(entries) {\n  for (const f of entries) if (f.startTime \u003C 10_000) fieldBlocking += f.blockingDuration;\n}\n\u002F\u002F trade-off: blockingDuration includes rendering time while longtask-derived\n\u002F\u002F TBT did not, so the new series runs higher. Annotate the dashboard on the\n\u002F\u002F switch date rather than comparing the two series directly.\n",[30,715,716,733,748,787,791,796,801],{"__ignoreMap":512},[516,717,718,721,724,727,730],{"class":381,"line":518},[516,719,720],{"class":521},"let",[516,722,723],{"class":532}," fieldBlocking ",[516,725,726],{"class":521},"=",[516,728,729],{"class":525}," 0",[516,731,732],{"class":532},";\n",[516,734,735,738,740,742,745],{"class":381,"line":550},[516,736,737],{"class":521},"function",[516,739,581],{"class":536},[516,741,540],{"class":532},[516,743,744],{"class":571},"entries",[516,746,747],{"class":532},") {\n",[516,749,750,753,756,758,761,764,767,769,772,775,778,781,784],{"class":381,"line":559},[516,751,752],{"class":521},"  for",[516,754,755],{"class":532}," (",[516,757,522],{"class":521},[516,759,760],{"class":525}," f",[516,762,763],{"class":521}," of",[516,765,766],{"class":532}," entries) ",[516,768,553],{"class":521},[516,770,771],{"class":532}," (f.startTime ",[516,773,774],{"class":521},"\u003C",[516,776,777],{"class":525}," 10_000",[516,779,780],{"class":532},") fieldBlocking ",[516,782,783],{"class":521},"+=",[516,785,786],{"class":532}," f.blockingDuration;\n",[516,788,789],{"class":381,"line":593},[516,790,673],{"class":532},[516,792,793],{"class":381,"line":616},[516,794,795],{"class":679},"\u002F\u002F trade-off: blockingDuration includes rendering time while longtask-derived\n",[516,797,798],{"class":381,"line":628},[516,799,800],{"class":679},"\u002F\u002F TBT did not, so the new series runs higher. Annotate the dashboard on the\n",[516,802,803],{"class":381,"line":652},[516,804,805],{"class":679},"\u002F\u002F switch date rather than comparing the two series directly.\n",[15,807,808],{},"Expected outcome: a blocking figure that tracks INP input delay more closely than the old one.",[499,810,812],{"id":811},"_3-retire-the-long-task-beacon-fields","3. Retire the long-task beacon fields",[15,814,815,816,818],{},"Once a release has shipped with both, remove ",[30,817,36],{}," collection from the beacon. Most teams save 200–600 bytes per beacon on heavy pages.",[507,820,822],{"className":509,"code":821,"language":511,"meta":512,"style":512},"\u002F\u002F Before: { longTasks: [{start, duration, attribution: 'unknown'}, ...] }\n\u002F\u002F After:  { loaf: [{start, duration, blocking, topScript: {src, fn, ms}}] }\n\u002F\u002F trade-off: if a third-party RUM vendor still computes metrics from longtask\n\u002F\u002F entries it reads directly from the page, removing YOUR observer does not\n\u002F\u002F affect it — but check their docs before assuming their charts are unchanged.\n",[30,823,824,829,834,839,844],{"__ignoreMap":512},[516,825,826],{"class":381,"line":518},[516,827,828],{"class":679},"\u002F\u002F Before: { longTasks: [{start, duration, attribution: 'unknown'}, ...] }\n",[516,830,831],{"class":381,"line":550},[516,832,833],{"class":679},"\u002F\u002F After:  { loaf: [{start, duration, blocking, topScript: {src, fn, ms}}] }\n",[516,835,836],{"class":381,"line":559},[516,837,838],{"class":679},"\u002F\u002F trade-off: if a third-party RUM vendor still computes metrics from longtask\n",[516,840,841],{"class":381,"line":593},[516,842,843],{"class":679},"\u002F\u002F entries it reads directly from the page, removing YOUR observer does not\n",[516,845,846],{"class":381,"line":616},[516,847,848],{"class":679},"\u002F\u002F affect it — but check their docs before assuming their charts are unchanged.\n",[159,850,852],{"id":851},"verification","Verification",[15,854,855],{},"Pick five interactions that RUM marks as slow and reproduce them in the lab with both observers running. For each, confirm the LoAF entry's script list names the code you would have blamed after manual profiling. If LoAF consistently identifies the culprit and Long Tasks either reports nothing or \"unknown\", the migration is justified. Then confirm beacon payload size dropped and that the INP attribution coverage — the share of INP beacons with a named top script — rose above roughly 70%.",[159,857,859],{"id":858},"when-long-tasks-still-earn-their-place","When Long Tasks Still Earn Their Place",[15,861,862,863,865],{},"Keep a ",[30,864,36],{}," observer only if you have a long-running historical chart you cannot re-baseline, or a Lighthouse-style TBT comparison that requires task semantics. For new instrumentation there is no case for it: LoAF reports a superset of the problem with attribution that actually names code.",[15,867,868],{},[48,869,55,872,55,875,55,878,55,880,55,897,55,900,55,902,55,906,55,911,55,914,55,918,55,925,55,931,55,935,55,940,55,943,55,947,55,949,55,952,55,955,55,958,55,961,55,964,55,967,55,971,55,973,55,976,55,979,55,982,55,986,55,989,55,992,55],{"viewBox":870,"width":51,"role":52,"ariaLabel":871,"style":54},"0 0 760 325","A decision sequence for whether to keep collecting long task entries after adopting the Long Animation Frames API.",[57,873],{"className":874,"x":61,"y":61,"width":51,"height":51,"fill":62},[60],[64,876,877],{},"Keep, migrate or drop the longtask observer",[68,879,871],{},[881,882,883],"defs",{},[884,885,892],"marker",{"id":886,"viewBox":887,"refX":888,"refY":889,"markerWidth":890,"markerHeight":890,"orient":891},"fa2c0f7795","0 0 10 10","9","5","7","auto-start-reverse",[893,894],"path",{"d":895,"fill":77,"style":896},"M0 0 L10 5 L0 10 z","fill-opacity:0.7",[57,898],{"x":72,"y":72,"width":73,"height":899,"rx":75,"fill":76,"stroke":77,"style":78},"323",[80,901,877],{"x":82,"y":83,"fill":77,"style":84},[57,903],{"x":82,"y":87,"width":904,"height":905,"rx":90,"fill":77,"stroke":77,"style":449},"320.0","35.0",[80,907,910],{"x":908,"y":396,"fill":77,"style":909,"textAnchor":405},"188.0","font-size:13px;font-weight:700","Historical chart you cannot re-baseline?",[57,912],{"x":913,"y":87,"width":904,"height":905,"rx":90,"fill":91,"stroke":92,"style":93},"412.0",[80,915,917],{"x":916,"y":396,"fill":77,"style":107,"textAnchor":405},"572.0","Keep longtask for one overlap quarter, then drop",[381,919],{"x1":920,"y1":921,"x2":922,"y2":921,"stroke":77,"strokeWidth":385,"style":923,"markerEnd":924},"348.0","73.5","410.0","stroke-opacity:0.6","url(#fa2c0f7795)",[80,926,930],{"x":927,"y":928,"fill":131,"style":929,"textAnchor":405},"380.0","66.5","font-size:11.5px;font-weight:700","yes",[381,932],{"x1":908,"y1":933,"x2":908,"y2":934,"stroke":77,"strokeWidth":385,"style":923,"markerEnd":924},"91.0","125.0",[80,936,939],{"x":937,"y":938,"fill":464,"style":929},"196.0","113.0","no",[57,941],{"x":82,"y":942,"width":904,"height":905,"rx":90,"fill":77,"stroke":77,"style":449},"127.0",[80,944,946],{"x":908,"y":945,"fill":77,"style":909,"textAnchor":405},"149.0","Debugging INP attribution?",[57,948],{"x":913,"y":942,"width":904,"height":905,"rx":90,"fill":131,"stroke":131,"style":132},[80,950,951],{"x":916,"y":945,"fill":77,"style":107,"textAnchor":405},"Use LoAF only",[381,953],{"x1":920,"y1":954,"x2":922,"y2":954,"stroke":77,"strokeWidth":385,"style":923,"markerEnd":924},"144.5",[80,956,930],{"x":927,"y":957,"fill":131,"style":929,"textAnchor":405},"137.5",[381,959],{"x1":908,"y1":960,"x2":908,"y2":937,"stroke":77,"strokeWidth":385,"style":923,"markerEnd":924},"162.0",[80,962,939],{"x":937,"y":963,"fill":464,"style":929},"184.0",[57,965],{"x":82,"y":966,"width":904,"height":905,"rx":90,"fill":77,"stroke":77,"style":449},"198.0",[80,968,970],{"x":908,"y":969,"fill":77,"style":909,"textAnchor":405},"220.0","Need a field TBT proxy?",[57,972],{"x":913,"y":966,"width":904,"height":905,"rx":90,"fill":131,"stroke":131,"style":132},[80,974,975],{"x":916,"y":969,"fill":77,"style":107,"textAnchor":405},"Sum LoAF blockingDuration",[381,977],{"x1":920,"y1":978,"x2":922,"y2":978,"stroke":77,"strokeWidth":385,"style":923,"markerEnd":924},"215.5",[80,980,930],{"x":927,"y":981,"fill":131,"style":929,"textAnchor":405},"208.5",[381,983],{"x1":908,"y1":984,"x2":908,"y2":985,"stroke":77,"strokeWidth":385,"style":923,"markerEnd":924},"233.0","267.0",[80,987,939],{"x":937,"y":988,"fill":464,"style":929},"255.0",[57,990],{"x":82,"y":991,"width":904,"height":83,"rx":90,"fill":91,"stroke":92,"style":93},"269.0",[80,993,995],{"x":908,"y":994,"fill":77,"style":107,"textAnchor":405},"290.5","Drop longtask collection entirely",[159,997,999],{"id":998},"cost-and-overhead-compared","Cost and Overhead Compared",[15,1001,1002],{},"Neither API adds meaningful work to the browser itself — both are recorded internally whether or not anyone observes them. The difference is in what your code does with the entries.",[15,1004,1005,1006,1008,1009,1012],{},"A ",[30,1007,36],{}," entry is small and flat: a name, a start time, a duration, and a short attribution array. A LoAF entry is larger, and its ",[30,1010,1011],{},"scripts"," array can hold a dozen nested objects with long URL and invoker strings. On a busy page that produces 30 long frames during load, naive collection allocates several hundred objects that sit in memory until the beacon is sent. That is negligible on a laptop and measurable on a low-end phone with an aggressive garbage collector.",[15,1014,1015,1016,1018],{},"The practical rule is to filter in the observer callback, not later: discard frames under ",[30,1017,32],{},", discard frames with no overlap with any interaction once the page is interactive, and keep only the top scripts of the frames you retain. With that discipline the memory footprint of LoAF collection is within a few kilobytes of the old long-task observer while carrying far more useful information.",[15,1020,1021],{},"Throughput is similar. Observer callbacks are batched and delivered asynchronously, so neither API runs code inside the long frame itself. What occasionally surprises teams is that a heavy callback — one that serialises entries to JSON on arrival — becomes a long task of its own and shows up in the next LoAF entry, attributed to your RUM script. If your own beacon code appears in the top-scripts list, move serialisation to the send step.",[159,1023,1025],{"id":1024},"faq","FAQ",[1027,1028,1031,1035],"details",{"className":1029},[1030],"faq-item",[1032,1033,1034],"summary",{},"Is Total Blocking Time in Lighthouse affected by LoAF?",[15,1036,1037,1038,1040],{},"No. Lighthouse still computes TBT from the trace's tasks in the lab; LoAF is a field-and-page API. The two are related — both use a ",[30,1039,32],{}," threshold — but a page can have good lab TBT and still produce long animation frames in the field because real devices are slower and real interactions overlap third-party work.",[1027,1042,1044,1047],{"className":1043},[1030],[1032,1045,1046],{},"Will other browsers implement LoAF?",[15,1048,1049],{},"At the time of writing only Chromium ships it. That limits it to a diagnostic role: you cannot compute a cross-browser metric from it, but you can find the scripts responsible, and those scripts are usually just as expensive in other engines. Fixes discovered through Chromium attribution typically improve Safari and Firefox users too.",[159,1051,1053],{"id":1052},"related","Related",[164,1055,1056,1063,1070],{},[167,1057,1058,1062],{},[19,1059,1061],{"href":1060},"\u002Fcore-web-vitals-measurement\u002Flong-animation-frames-api\u002Ffinding-slow-scripts-with-loaf-script-attribution\u002F","Finding slow scripts with LoAF script attribution"," — putting the script list to work.",[167,1064,1065,1069],{},[19,1066,1068],{"href":1067},"\u002Fcore-web-vitals-measurement\u002Foptimizing-first-input-delay-fid\u002Freducing-total-blocking-time-in-lighthouse\u002F","Reducing Total Blocking Time in Lighthouse"," — the lab metric that still uses task semantics.",[167,1071,1072,1076],{},[19,1073,1075],{"href":1074},"\u002Fcore-web-vitals-measurement\u002Flong-animation-frames-api\u002Fdiagnosing-presentation-delay-with-loaf\u002F","Diagnosing presentation delay with LoAF"," — the rendering tail Long Tasks could never see.",[1078,1079,1081],"script",{"type":1080},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"LoAF vs the Long Tasks API: Which Observer Should Feed Your INP Debugging?\",\n  \"description\": \"Why a frame-based measurement with script attribution beats task-based observation for debugging INP, and when the older API is still useful.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Add a LoAF observer next to the existing one\",\n      \"text\": \"Run both for a release so you can compare coverage before deleting anything.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Rebuild your blocking-time approximation on blockingDuration\",\n      \"text\": \"If dashboards chart a field \\\"TBT-like\\\" figure from long tasks, switch to summing blockingDuration across frames between FCP and a cutoff.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Retire the long-task beacon fields\",\n      \"text\": \"Once a release has shipped with both, remove longtask collection from the beacon.\"\n    }\n  ]\n}\n",[1078,1083,1084],{"type":1080},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"LoAF vs the Long Tasks API: Which Observer Should Feed Your INP Debugging?\",\n  \"description\": \"Why a frame-based measurement with script attribution beats task-based observation for debugging INP, and when the older API is still useful.\",\n  \"datePublished\": \"2026-10-06\",\n  \"dateModified\": \"2026-10-06\",\n  \"author\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"publisher\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"mainEntityOfPage\": {\n    \"@type\": \"WebPage\",\n    \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002Flong-animation-frames-api\u002Floaf-vs-long-tasks-api\u002F\"\n  }\n}\n",[1078,1086,1087],{"type":1080},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 1,\n      \"name\": \"Home\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 2,\n      \"name\": \"Core Web Vitals & Measurement\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 3,\n      \"name\": \"Long Animation Frames (LoAF) API\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002Flong-animation-frames-api\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"LoAF vs the Long Tasks API\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002Flong-animation-frames-api\u002Floaf-vs-long-tasks-api\u002F\"\n    }\n  ]\n}\n",[1089,1090,1091],"style",{},"html pre.shiki code .sPARh, html code.shiki .sPARh{--shiki-default:#A0111F;--shiki-dark:#FF9492;--shiki-light:#A0111F}html pre.shiki code .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}html pre.shiki code .saISM, html code.shiki .saISM{--shiki-default:#0E1116;--shiki-dark:#F0F3F6;--shiki-light:#0E1116}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}html pre.shiki code .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}html pre.shiki code .sQw3B, html code.shiki .sQw3B{--shiki-default:#702C00;--shiki-dark:#FFB757;--shiki-light:#702C00}html pre.shiki code .sjfSM, html code.shiki .sjfSM{--shiki-default:#66707B;--shiki-dark:#BDC4CC;--shiki-light:#66707B}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}",{"title":512,"searchDepth":550,"depth":550,"links":1093},[1094,1095,1096,1097,1103,1104,1105,1106,1107],{"id":161,"depth":550,"text":162},{"id":216,"depth":550,"text":217},{"id":329,"depth":550,"text":330},{"id":496,"depth":550,"text":497,"children":1098},[1099,1100,1102],{"id":501,"depth":559,"text":502},{"id":701,"depth":559,"text":1101},"2. Rebuild your blocking-time approximation on blockingDuration",{"id":811,"depth":559,"text":812},{"id":851,"depth":550,"text":852},{"id":858,"depth":550,"text":859},{"id":998,"depth":550,"text":999},{"id":1024,"depth":550,"text":1025},{"id":1052,"depth":550,"text":1053},"Why a frame-based measurement with script attribution beats task-based observation for debugging INP, and when the older API is still useful.","md",{"slug":1111,"type":1112,"breadcrumb":1113,"datePublished":1122,"dateModified":1122},"loaf-vs-long-tasks-api","article",[1114,1117,1118,1120],{"name":1115,"url":1116},"Home","\u002F",{"name":27,"url":26},{"name":1119,"url":21},"Long Animation Frames (LoAF) API",{"name":5,"url":1121},"\u002Fcore-web-vitals-measurement\u002Flong-animation-frames-api\u002Floaf-vs-long-tasks-api\u002F","2026-10-06",true,"\u002Fcore-web-vitals-measurement\u002Flong-animation-frames-api\u002Floaf-vs-long-tasks-api",{"title":1126,"description":1127},"LoAF vs Long Tasks API: What Changed for INP","Compare the Long Animation Frames API with the Long Tasks API: unit of measurement, attribution quality, rendering visibility, support and when to keep both.","core-web-vitals-measurement\u002Flong-animation-frames-api\u002Floaf-vs-long-tasks-api\u002Findex","Shgv6mNFyG7KR0xGb7NUsqztd7xzWdNrZPDMrVYcJZ0",[1131,1135],{"title":1132,"path":1133,"stem":1134},"Finding Slow Scripts with LoAF Script Attribution","\u002Fcore-web-vitals-measurement\u002Flong-animation-frames-api\u002Ffinding-slow-scripts-with-loaf-script-attribution","core-web-vitals-measurement\u002Flong-animation-frames-api\u002Ffinding-slow-scripts-with-loaf-script-attribution\u002Findex",{"title":1136,"path":1137,"stem":1138},"Sending LoAF Data in RUM Beacons","\u002Fcore-web-vitals-measurement\u002Flong-animation-frames-api\u002Fsending-loaf-data-in-rum-beacons","core-web-vitals-measurement\u002Flong-animation-frames-api\u002Fsending-loaf-data-in-rum-beacons\u002Findex",1791308078312]