[{"data":1,"prerenderedAt":1577},["ShallowReactive",2],{"page:\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Fauditing-third-party-scripts-with-lighthouse":3,"all-docs-nav":1335},{"id":4,"title":5,"body":6,"breadcrumb":1309,"dateModified":1319,"datePublished":1319,"description":1320,"extension":1321,"faq":1322,"meta":1329,"navigation":133,"path":1330,"seo":1331,"slug":12,"stem":1332,"type":1333,"__hash__":1334},"content\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Fauditing-third-party-scripts-with-lighthouse\u002Findex.md","Auditing Third-Party Scripts With Lighthouse",{"type":7,"value":8,"toc":1290},"minimark",[9,13,17,26,31,58,62,69,162,165,168,314,318,330,358,361,365,368,629,632,636,639,792,828,835,839,842,944,947,950,954,957,1053,1149,1153,1192,1196,1201,1205,1210,1213,1217,1220,1224,1227,1231,1238,1242,1245,1249,1286],[10,11,5],"h1",{"id":12},"auditing-third-party-scripts-with-lighthouse",[14,15,16],"p",{},"You cannot budget what you have not attributed. \"The page is slow\" becomes actionable the moment you can say \"the chat widget is 340 ms of the 940 ms of main-thread time, and the tag manager is another 120 ms with an empty container\". Lighthouse produces exactly that attribution, and it can run in CI so the numbers do not drift back.",[14,18,19,20,25],{},"This guide runs the audit end to end: the third-party summary for attribution, the treemap for what is inside each bundle, a long-task trace for costs that appear after load, and a CI gate that fails the build when the total crosses a budget. It is the measurement companion to ",[21,22,24],"a",{"href":23},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002F","Third-Party Script Performance on Static Sites",".",[27,28,30],"h2",{"id":29},"prerequisites","Prerequisites",[32,33,34,47,55],"ul",{},[35,36,37,38,42,43,46],"li",{},"Node 20+ with ",[39,40,41],"code",{},"lighthouse"," available via ",[39,44,45],{},"npx",", or Chrome's built-in Lighthouse panel for interactive runs.",[35,48,49,50,54],{},"A preview URL per pull request — the pattern in ",[21,51,53],{"href":52},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002F","Preview Environments for Pull Requests"," is what makes per-PR auditing possible.",[35,56,57],{},"A representative page: whichever template carries the most third-party code, not the homepage by default.",[27,59,61],{"id":60},"step-1-attribute-the-cost-by-entity","Step 1 — Attribute the Cost by Entity",[14,63,64,65,68],{},"The ",[39,66,67],{},"third-party-summary"," audit groups every request by the entity that owns it and reports both transfer size and main-thread blocking time:",[70,71,76],"pre",{"className":72,"code":73,"language":74,"meta":75,"style":75},"language-bash shiki shiki-themes github-light github-dark","npx lighthouse https:\u002F\u002Fpreview.example.com\u002Fdocs\u002Fdeploying\u002F \\\n  --form-factor=mobile --throttling-method=simulate \\\n  --only-audits=third-party-summary,total-byte-weight,bootup-time \\\n  --output=json --output-path=.\u002Flh.json --quiet\n\njq -r '.audits[\"third-party-summary\"].details.items[]\n       | [.entity, (.transferSize\u002F1024|floor|tostring + \" KB\"),\n          (.blockingTime|floor|tostring + \" ms\")] | @tsv' lh.json\n","bash","",[39,77,78,97,108,116,128,135,147,153],{"__ignoreMap":75},[79,80,83,86,90,93],"span",{"class":81,"line":82},"line",1,[79,84,45],{"class":85},"sScJk",[79,87,89],{"class":88},"sZZnC"," lighthouse",[79,91,92],{"class":88}," https:\u002F\u002Fpreview.example.com\u002Fdocs\u002Fdeploying\u002F",[79,94,96],{"class":95},"sj4cs"," \\\n",[79,98,100,103,106],{"class":81,"line":99},2,[79,101,102],{"class":95},"  --form-factor=mobile",[79,104,105],{"class":95}," --throttling-method=simulate",[79,107,96],{"class":95},[79,109,111,114],{"class":81,"line":110},3,[79,112,113],{"class":95},"  --only-audits=third-party-summary,total-byte-weight,bootup-time",[79,115,96],{"class":95},[79,117,119,122,125],{"class":81,"line":118},4,[79,120,121],{"class":95},"  --output=json",[79,123,124],{"class":95}," --output-path=.\u002Flh.json",[79,126,127],{"class":95}," --quiet\n",[79,129,131],{"class":81,"line":130},5,[79,132,134],{"emptyLinePlaceholder":133},true,"\n",[79,136,138,141,144],{"class":81,"line":137},6,[79,139,140],{"class":85},"jq",[79,142,143],{"class":95}," -r",[79,145,146],{"class":88}," '.audits[\"third-party-summary\"].details.items[]\n",[79,148,150],{"class":81,"line":149},7,[79,151,152],{"class":88},"       | [.entity, (.transferSize\u002F1024|floor|tostring + \" KB\"),\n",[79,154,156,159],{"class":81,"line":155},8,[79,157,158],{"class":88},"          (.blockingTime|floor|tostring + \" ms\")] | @tsv'",[79,160,161],{"class":88}," lh.json\n",[14,163,164],{},"Sort the output by blocking time, not by size. The ranking almost always differs, and blocking time is what a reader feels.",[14,166,167],{},"Run it on mobile with simulated throttling even if your audience skews desktop. The mobile profile models a mid-tier device, and third-party code is precisely the category whose cost scales with how slow the CPU is: a bundle that parses and executes in 40 ms on a laptop routinely takes 300 ms on a phone from three years ago. Auditing on desktop hardware produces a report where every vendor looks affordable.",[169,170,171,310],"figure",{},[172,173,180,181,180,185,180,189,180,196],"svg",{"viewBox":174,"role":175,"ariaLabelledBy":176,"xmlns":179},"0 0 760 300","img",[177,178],"aud-rank-title","aud-rank-desc","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","\n  ",[182,183,184],"title",{"id":177},"Ranking by bytes versus ranking by blocking time",[186,187,188],"desc",{"id":178},"Two ranked lists of the same five vendors. Ranked by transfer size the video player leads with 780 kilobytes, followed by the chat widget, consent platform, tag manager and analytics. Ranked by blocking time the chat widget leads with 340 milliseconds, ahead of the video player, consent platform, tag manager and analytics.",[190,191],"rect",{"x":192,"y":192,"width":193,"height":194,"fill":195},"0","760","300","#ffffff",[197,198,200,201,200,209,200,216,200,225,200,231,200,235,200,239,200,243,200,247,200,251,200,255,200,259,200,263,200,268,200,272,200,277,200,280,200,283,200,288,200,291,200,294,200,297,200,302,200,305,180],"g",{"style":199},"font-family:system-ui, sans-serif;font-size:12px","\n    ",[202,203,208],"text",{"x":204,"y":205,"fill":206,"style":207},"380","28","#1f2937","font-size:16px;font-weight:700;text-anchor:middle","The two rankings disagree — fix the right one",[202,210,215],{"x":211,"y":212,"fill":213,"style":214},"40","60","#556071","font-size:13px;font-weight:700","By transfer size",[190,217],{"x":211,"y":218,"width":219,"height":220,"rx":221,"fill":222,"opacity":223,"stroke":213,"style":224},"72","320","34","6","#d9e2ef","0.55","stroke-width:1.5px",[202,226,230],{"x":227,"y":228,"fill":206,"style":229},"200","94","font-size:12px;text-anchor:middle","video player · 780 KB",[190,232],{"x":211,"y":233,"width":219,"height":220,"rx":221,"fill":222,"opacity":234,"stroke":213,"style":224},"112","0.45",[202,236,238],{"x":227,"y":237,"fill":206,"style":229},"134","chat widget · 96 KB",[190,240],{"x":211,"y":241,"width":219,"height":220,"rx":221,"fill":222,"opacity":242,"stroke":213,"style":224},"152","0.35",[202,244,246],{"x":227,"y":245,"fill":206,"style":229},"174","consent · 58 KB",[190,248],{"x":211,"y":249,"width":219,"height":220,"rx":221,"fill":222,"opacity":250,"stroke":213,"style":224},"192","0.28",[202,252,254],{"x":227,"y":253,"fill":206,"style":229},"214","tag manager · 34 KB",[190,256],{"x":211,"y":257,"width":219,"height":220,"rx":221,"fill":222,"opacity":258,"stroke":213,"style":224},"232","0.22",[202,260,262],{"x":227,"y":261,"fill":206,"style":229},"254","analytics · 6 KB",[202,264,267],{"x":265,"y":212,"fill":266,"style":214},"400","#d83b41","By blocking time",[190,269],{"x":265,"y":218,"width":219,"height":220,"rx":221,"fill":270,"opacity":271,"stroke":266,"style":224},"#ff595e","0.18",[202,273,276],{"x":274,"y":228,"fill":206,"style":275},"560","font-size:12px;font-weight:700;text-anchor:middle","chat widget · 340 ms",[190,278],{"x":265,"y":233,"width":219,"height":220,"rx":221,"fill":270,"opacity":279,"stroke":266,"style":224},"0.13",[202,281,282],{"x":274,"y":237,"fill":206,"style":229},"video player · 310 ms",[190,284],{"x":265,"y":241,"width":219,"height":220,"rx":221,"fill":285,"opacity":286,"stroke":287,"style":224},"#ffca3a","0.34","#a97b00",[202,289,290],{"x":274,"y":245,"fill":206,"style":229},"consent · 190 ms",[190,292],{"x":265,"y":249,"width":219,"height":220,"rx":221,"fill":285,"opacity":293,"stroke":287,"style":224},"0.24",[202,295,296],{"x":274,"y":253,"fill":206,"style":229},"tag manager · 120 ms",[190,298],{"x":265,"y":257,"width":219,"height":220,"rx":221,"fill":299,"opacity":300,"stroke":301,"style":224},"#8ac926","0.2","#5a8a16",[202,303,304],{"x":274,"y":261,"fill":206,"style":229},"analytics · 18 ms",[202,306,309],{"x":211,"y":307,"fill":213,"style":308},"290","font-size:11px","The 96 KB widget costs more main-thread time than the 780 KB player, because bytes are not work",[311,312,313],"figcaption",{},"Ranking by size sends you after the video first; ranking by blocking time sends you after the widget, which is the change readers actually feel on a mid-tier phone.",[27,315,317],{"id":316},"step-2-open-the-treemap-for-what-is-inside","Step 2 — Open the Treemap for What Is Inside",[14,319,320,321,324,325,329],{},"The treemap (",[39,322,323],{},"--view"," in the CLI, or the ",[326,327,328],"em",{},"Treemap"," link in the HTML report) breaks each bundle into modules and marks unused bytes. It answers a different question from the summary: not \"who is expensive\" but \"what part of this is expensive, and are we even using it\".",[70,331,333],{"className":72,"code":332,"language":74,"meta":75,"style":75},"npx lighthouse https:\u002F\u002Fpreview.example.com\u002Fdocs\u002Fdeploying\u002F \\\n  --form-factor=mobile --output=html --output-path=.\u002Flh.html --view\n",[39,334,335,345],{"__ignoreMap":75},[79,336,337,339,341,343],{"class":81,"line":82},[79,338,45],{"class":85},[79,340,89],{"class":88},[79,342,92],{"class":88},[79,344,96],{"class":95},[79,346,347,349,352,355],{"class":81,"line":99},[79,348,102],{"class":95},[79,350,351],{"class":95}," --output=html",[79,353,354],{"class":95}," --output-path=.\u002Flh.html",[79,356,357],{"class":95}," --view\n",[14,359,360],{},"Two patterns show up constantly on content sites. A vendor bundle that is 70-80% unused, because the site enables one of its twelve features — a candidate for a lighter alternative or a self-hosted replacement. And a polyfill bundle shipped to every browser to satisfy one that nobody in the analytics uses any more.",[27,362,364],{"id":363},"step-3-trace-the-costs-that-appear-after-load","Step 3 — Trace the Costs That Appear After Load",[14,366,367],{},"Lighthouse stops recording after the run, so anything periodic is invisible to it. Record a Performance trace with the page idle for thirty seconds and read the Bottom-Up view grouped by URL, or collect it programmatically:",[70,369,373],{"className":370,"code":371,"language":372,"meta":75,"style":75},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F Long tasks with attribution, logged for 30 s\nconst seen = new Map();\nnew PerformanceObserver((list) => {\n  for (const t of list.getEntries()) {\n    if (t.duration \u003C 50) continue;\n    const src = t.attribution?.[0]?.containerSrc || t.attribution?.[0]?.name || 'unknown';\n    seen.set(src, (seen.get(src) || 0) + t.duration);\n  }\n}).observe({ type: 'longtask', buffered: true });\nsetTimeout(() => console.table([...seen].map(([src, ms]) => ({ src, ms: Math.round(ms) }))), 30000);\n","javascript",[39,374,375,381,403,427,452,474,509,539,544,568],{"__ignoreMap":75},[79,376,377],{"class":81,"line":82},[79,378,380],{"class":379},"sJ8bj","\u002F\u002F Long tasks with attribution, logged for 30 s\n",[79,382,383,387,390,393,396,399],{"class":81,"line":99},[79,384,386],{"class":385},"szBVR","const",[79,388,389],{"class":95}," seen",[79,391,392],{"class":385}," =",[79,394,395],{"class":385}," new",[79,397,398],{"class":85}," Map",[79,400,402],{"class":401},"sVt8B","();\n",[79,404,405,408,411,414,418,421,424],{"class":81,"line":110},[79,406,407],{"class":385},"new",[79,409,410],{"class":85}," PerformanceObserver",[79,412,413],{"class":401},"((",[79,415,417],{"class":416},"s4XuR","list",[79,419,420],{"class":401},") ",[79,422,423],{"class":385},"=>",[79,425,426],{"class":401}," {\n",[79,428,429,432,435,437,440,443,446,449],{"class":81,"line":118},[79,430,431],{"class":385},"  for",[79,433,434],{"class":401}," (",[79,436,386],{"class":385},[79,438,439],{"class":95}," t",[79,441,442],{"class":385}," of",[79,444,445],{"class":401}," list.",[79,447,448],{"class":85},"getEntries",[79,450,451],{"class":401},"()) {\n",[79,453,454,457,460,463,466,468,471],{"class":81,"line":130},[79,455,456],{"class":385},"    if",[79,458,459],{"class":401}," (t.duration ",[79,461,462],{"class":385},"\u003C",[79,464,465],{"class":95}," 50",[79,467,420],{"class":401},[79,469,470],{"class":385},"continue",[79,472,473],{"class":401},";\n",[79,475,476,479,482,484,487,489,492,495,497,499,502,504,507],{"class":81,"line":137},[79,477,478],{"class":385},"    const",[79,480,481],{"class":95}," src",[79,483,392],{"class":385},[79,485,486],{"class":401}," t.attribution?.[",[79,488,192],{"class":95},[79,490,491],{"class":401},"]?.containerSrc ",[79,493,494],{"class":385},"||",[79,496,486],{"class":401},[79,498,192],{"class":95},[79,500,501],{"class":401},"]?.name ",[79,503,494],{"class":385},[79,505,506],{"class":88}," 'unknown'",[79,508,473],{"class":401},[79,510,511,514,517,520,523,526,528,531,533,536],{"class":81,"line":149},[79,512,513],{"class":401},"    seen.",[79,515,516],{"class":85},"set",[79,518,519],{"class":401},"(src, (seen.",[79,521,522],{"class":85},"get",[79,524,525],{"class":401},"(src) ",[79,527,494],{"class":385},[79,529,530],{"class":95}," 0",[79,532,420],{"class":401},[79,534,535],{"class":385},"+",[79,537,538],{"class":401}," t.duration);\n",[79,540,541],{"class":81,"line":155},[79,542,543],{"class":401},"  }\n",[79,545,547,550,553,556,559,562,565],{"class":81,"line":546},9,[79,548,549],{"class":401},"}).",[79,551,552],{"class":85},"observe",[79,554,555],{"class":401},"({ type: ",[79,557,558],{"class":88},"'longtask'",[79,560,561],{"class":401},", buffered: ",[79,563,564],{"class":95},"true",[79,566,567],{"class":401}," });\n",[79,569,571,574,577,579,582,585,588,591,594,597,600,603,606,609,612,614,617,620,623,626],{"class":81,"line":570},10,[79,572,573],{"class":85},"setTimeout",[79,575,576],{"class":401},"(() ",[79,578,423],{"class":385},[79,580,581],{"class":401}," console.",[79,583,584],{"class":85},"table",[79,586,587],{"class":401},"([",[79,589,590],{"class":385},"...",[79,592,593],{"class":401},"seen].",[79,595,596],{"class":85},"map",[79,598,599],{"class":401},"(([",[79,601,602],{"class":416},"src",[79,604,605],{"class":401},", ",[79,607,608],{"class":416},"ms",[79,610,611],{"class":401},"]) ",[79,613,423],{"class":385},[79,615,616],{"class":401}," ({ src, ms: Math.",[79,618,619],{"class":85},"round",[79,621,622],{"class":401},"(ms) }))), ",[79,624,625],{"class":95},"30000",[79,627,628],{"class":401},");\n",[14,630,631],{},"Anything that appears here while the page is idle is a recurring cost paid for the whole session — a presence poll, a heartbeat, a re-render on focus. These are the costs that damage Interaction to Next Paint without touching any load metric.",[27,633,635],{"id":634},"step-4-gate-the-budget-in-ci","Step 4 — Gate the Budget in CI",[14,637,638],{},"An audit that runs once is a snapshot; an audit that runs on every pull request is a ratchet. Lighthouse CI's assertions read the same audits:",[70,640,644],{"className":641,"code":642,"language":643,"meta":75,"style":75},"language-json shiki shiki-themes github-light github-dark","{\n  \"ci\": {\n    \"collect\": { \"url\": [\"https:\u002F\u002Fpreview.example.com\u002Fdocs\u002Fdeploying\u002F\"], \"numberOfRuns\": 3 },\n    \"assert\": {\n      \"assertions\": {\n        \"third-party-summary\": [\"error\", { \"maxNumericValue\": 150 }],\n        \"total-byte-weight\": [\"error\", { \"maxNumericValue\": 512000 }],\n        \"interactive\": [\"warn\", { \"maxNumericValue\": 3500 }]\n      }\n    }\n  }\n}\n","json",[39,645,646,651,659,691,698,705,729,749,771,776,781,786],{"__ignoreMap":75},[79,647,648],{"class":81,"line":82},[79,649,650],{"class":401},"{\n",[79,652,653,656],{"class":81,"line":99},[79,654,655],{"class":95},"  \"ci\"",[79,657,658],{"class":401},": {\n",[79,660,661,664,667,670,673,676,679,682,685,688],{"class":81,"line":110},[79,662,663],{"class":95},"    \"collect\"",[79,665,666],{"class":401},": { ",[79,668,669],{"class":95},"\"url\"",[79,671,672],{"class":401},": [",[79,674,675],{"class":88},"\"https:\u002F\u002Fpreview.example.com\u002Fdocs\u002Fdeploying\u002F\"",[79,677,678],{"class":401},"], ",[79,680,681],{"class":95},"\"numberOfRuns\"",[79,683,684],{"class":401},": ",[79,686,687],{"class":95},"3",[79,689,690],{"class":401}," },\n",[79,692,693,696],{"class":81,"line":118},[79,694,695],{"class":95},"    \"assert\"",[79,697,658],{"class":401},[79,699,700,703],{"class":81,"line":130},[79,701,702],{"class":95},"      \"assertions\"",[79,704,658],{"class":401},[79,706,707,710,712,715,718,721,723,726],{"class":81,"line":137},[79,708,709],{"class":95},"        \"third-party-summary\"",[79,711,672],{"class":401},[79,713,714],{"class":88},"\"error\"",[79,716,717],{"class":401},", { ",[79,719,720],{"class":95},"\"maxNumericValue\"",[79,722,684],{"class":401},[79,724,725],{"class":95},"150",[79,727,728],{"class":401}," }],\n",[79,730,731,734,736,738,740,742,744,747],{"class":81,"line":149},[79,732,733],{"class":95},"        \"total-byte-weight\"",[79,735,672],{"class":401},[79,737,714],{"class":88},[79,739,717],{"class":401},[79,741,720],{"class":95},[79,743,684],{"class":401},[79,745,746],{"class":95},"512000",[79,748,728],{"class":401},[79,750,751,754,756,759,761,763,765,768],{"class":81,"line":155},[79,752,753],{"class":95},"        \"interactive\"",[79,755,672],{"class":401},[79,757,758],{"class":88},"\"warn\"",[79,760,717],{"class":401},[79,762,720],{"class":95},[79,764,684],{"class":401},[79,766,767],{"class":95},"3500",[79,769,770],{"class":401}," }]\n",[79,772,773],{"class":81,"line":546},[79,774,775],{"class":401},"      }\n",[79,777,778],{"class":81,"line":570},[79,779,780],{"class":401},"    }\n",[79,782,784],{"class":81,"line":783},11,[79,785,543],{"class":401},[79,787,789],{"class":81,"line":788},12,[79,790,791],{"class":401},"}\n",[70,793,797],{"className":794,"code":795,"language":796,"meta":75,"style":75},"language-yaml shiki shiki-themes github-light github-dark","# .github\u002Fworkflows\u002Fperf.yml\n- name: Lighthouse budget\n  run: npx --yes @lhci\u002Fcli autorun --config=.\u002Flighthouserc.json\n","yaml",[39,798,799,804,818],{"__ignoreMap":75},[79,800,801],{"class":81,"line":82},[79,802,803],{"class":379},"# .github\u002Fworkflows\u002Fperf.yml\n",[79,805,806,809,813,815],{"class":81,"line":99},[79,807,808],{"class":401},"- ",[79,810,812],{"class":811},"s9eBZ","name",[79,814,684],{"class":401},[79,816,817],{"class":88},"Lighthouse budget\n",[79,819,820,823,825],{"class":81,"line":110},[79,821,822],{"class":811},"  run",[79,824,684],{"class":401},[79,826,827],{"class":88},"npx --yes @lhci\u002Fcli autorun --config=.\u002Flighthouserc.json\n",[14,829,830,831,25],{},"Three runs and a median matter here: a single Lighthouse run on a shared CI runner varies enough to fail a passing build. The same discipline applies to any performance gate, as covered in ",[21,832,834],{"href":833},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fmeasuring-build-time-regressions-in-ci\u002F","Measuring Build-Time Regressions in CI",[27,836,838],{"id":837},"step-5-turn-the-report-into-an-owned-list","Step 5 — Turn the Report Into an Owned List",[14,840,841],{},"A report nobody owns changes nothing. Convert the ranked output into a table in the repository, one row per entity, with an owner and a decision. The decision column has only four values, and forcing every vendor into one of them is what makes the audit finish rather than repeat.",[169,843,844,941],{},[172,845,180,849,180,852,180,855,180,857],{"viewBox":174,"role":175,"ariaLabelledBy":846,"xmlns":179},[847,848],"aud-decide-title","aud-decide-desc",[182,850,851],{"id":847},"Four decisions available for each third party",[186,853,854],{"id":848},"A two by two matrix with reader value on the vertical axis and main-thread cost on the horizontal axis. High value and low cost means keep. High value and high cost means gate behind an interaction. Low value and low cost means keep but review. Low value and high cost means remove.",[190,856],{"x":192,"y":192,"width":193,"height":194,"fill":195},[197,858,200,859,200,863,200,870,200,875,200,878,200,882,200,887,200,891,200,894,200,897,200,900,200,904,200,908,200,912,200,914,200,917,200,920,200,923,200,928,200,932,200,937,180],{"style":199},[202,860,862],{"x":204,"y":861,"fill":206,"style":207},"26","Value to the reader against cost to the reader",[190,864],{"x":865,"y":866,"width":867,"height":868,"rx":869,"fill":299,"opacity":271,"stroke":301,"style":224},"170","52","240","96","10",[202,871,874],{"x":307,"y":872,"fill":206,"style":873},"90","font-size:13px;font-weight:700;text-anchor:middle","Keep as is",[202,876,877],{"x":307,"y":233,"fill":213,"style":229},"self-hosted vitals beacon",[202,879,881],{"x":307,"y":880,"fill":213,"style":229},"132","22 ms · high value",[190,883],{"x":884,"y":866,"width":867,"height":868,"rx":869,"fill":885,"opacity":886,"stroke":885,"style":224},"430","#1982c4","0.14",[202,888,890],{"x":889,"y":872,"fill":206,"style":873},"550","Gate behind intent",[202,892,893],{"x":889,"y":233,"fill":213,"style":229},"chat widget, video player",[202,895,896],{"x":889,"y":880,"fill":213,"style":229},"valued by few, paid by all",[190,898],{"x":865,"y":899,"width":867,"height":868,"rx":869,"fill":285,"opacity":250,"stroke":287,"style":224},"164",[202,901,903],{"x":307,"y":902,"fill":206,"style":873},"202","Keep, review yearly",[202,905,907],{"x":307,"y":906,"fill":213,"style":229},"224","small marketing pixel",[202,909,911],{"x":307,"y":910,"fill":213,"style":229},"244","cheap, unclear value",[190,913],{"x":884,"y":899,"width":867,"height":868,"rx":869,"fill":270,"opacity":886,"stroke":266,"style":224},[202,915,916],{"x":889,"y":902,"fill":206,"style":873},"Remove",[202,918,919],{"x":889,"y":906,"fill":213,"style":229},"empty tag manager",[202,921,922],{"x":889,"y":910,"fill":213,"style":229},"120 ms for nothing",[202,924,927],{"x":211,"y":925,"fill":213,"style":926},"104","font-size:12px","high value",[202,929,931],{"x":211,"y":930,"fill":213,"style":926},"216","low value",[202,933,936],{"x":934,"y":935,"fill":213,"style":926},"252","284","low cost",[202,938,940],{"x":939,"y":935,"fill":213,"style":926},"512","high cost",[311,942,943],{},"Most third parties that survive an audit land in the top-right box, and gating is what moves them out of the load path without starting a negotiation about removing them.",[14,945,946],{},"The bottom-right quadrant is the easiest and most contested. An empty tag manager container costing 120 ms is trivially removable in engineering terms and often defended on the grounds that someone might need it later. Bring the number: 120 ms on every page view, for a capability nobody has used in eleven months, is a concrete trade rather than a preference. Keeping a record of when each vendor was last actually used makes that conversation short.",[14,948,949],{},"Re-run the audit after each change and update the row. The list is finished when every entity has an owner, a decision and a measured cost — not when the score reaches a particular number.",[27,951,953],{"id":952},"measured-impact","Measured Impact",[14,955,956],{},"Running the audit on a documentation site's article template and acting on the top two rows:",[584,958,959,981],{},[960,961,962],"thead",{},[963,964,965,969,972,975,978],"tr",{},[966,967,968],"th",{},"Stage",[966,970,971],{},"Third-party blocking",[966,973,974],{},"Transfer",[966,976,977],{},"INP",[966,979,980],{},"Lighthouse perf",[982,983,984,1002,1019,1036],"tbody",{},[963,985,986,990,993,996,999],{},[987,988,989],"td",{},"Before the audit",[987,991,992],{},"760 ms",[987,994,995],{},"1.28 MB",[987,997,998],{},"240 ms",[987,1000,1001],{},"61",[963,1003,1004,1007,1010,1013,1016],{},[987,1005,1006],{},"Chat widget interaction-gated",[987,1008,1009],{},"420 ms",[987,1011,1012],{},"1.18 MB",[987,1014,1015],{},"165 ms",[987,1017,1018],{},"74",[963,1020,1021,1024,1027,1030,1033],{},[987,1022,1023],{},"Video replaced with a facade",[987,1025,1026],{},"110 ms",[987,1028,1029],{},"430 KB",[987,1031,1032],{},"130 ms",[987,1034,1035],{},"92",[963,1037,1038,1041,1044,1047,1050],{},[987,1039,1040],{},"Tag manager removed, analytics self-hosted",[987,1042,1043],{},"22 ms",[987,1045,1046],{},"380 KB",[987,1048,1049],{},"120 ms",[987,1051,1052],{},"97",[169,1054,1055,1146],{},[172,1056,180,1061,180,1064,180,1067,180,1069],{"viewBox":1057,"role":175,"ariaLabelledBy":1058,"xmlns":179},"0 0 760 290",[1059,1060],"aud-burn-title","aud-burn-desc",[182,1062,1063],{"id":1059},"Third-party blocking time across four audit actions",[186,1065,1066],{"id":1060},"A descending bar chart. Third-party blocking time falls from 760 milliseconds before the audit, to 420 after gating the chat widget, to 110 after the video facade, to 22 after removing the tag manager. A dashed line marks the 150 millisecond budget, crossed at the third step.",[190,1068],{"x":192,"y":192,"width":193,"height":307,"fill":195},[197,1070,200,1071,200,1074,200,1078,200,1081,200,1085,200,1091,200,1096,200,1100,200,1104,200,1108,200,1115,200,1119,200,1125,200,1129,200,1133,200,1136,200,1139,200,1142,180],{"style":199},[202,1072,1073],{"x":204,"y":861,"fill":206,"style":207},"Two changes did 85% of the work",[81,1075],{"x1":1076,"y1":866,"x2":1076,"y2":1077,"stroke":213,"style":224},"100","220",[81,1079],{"x1":1076,"y1":1077,"x2":1080,"y2":1077,"stroke":213,"style":224},"710",[81,1082],{"x1":1076,"y1":1083,"x2":1080,"y2":1083,"stroke":299,"style":1084},"188","stroke-width:2px;stroke-dasharray:6 5",[202,1086,1090],{"x":1087,"y":1088,"fill":301,"style":1089},"580","182","font-size:11px;font-weight:700","150 ms budget",[190,1092],{"x":1093,"y":1094,"width":872,"height":1095,"rx":221,"fill":270,"opacity":271,"stroke":266,"style":224},"140","62","158",[202,1097,992],{"x":1098,"y":1099,"fill":266,"style":275},"185","56",[190,1101],{"x":307,"y":1102,"width":872,"height":1103,"rx":221,"fill":270,"opacity":279,"stroke":266,"style":224},"133","87",[202,1105,1009],{"x":1106,"y":1107,"fill":266,"style":275},"335","127",[190,1109],{"x":1110,"y":1111,"width":872,"height":1112,"rx":1113,"fill":299,"opacity":1114,"stroke":301,"style":224},"440","197","23","5","0.26",[202,1116,1026],{"x":1117,"y":1118,"fill":301,"style":275},"485","191",[190,1120],{"x":1121,"y":1122,"width":872,"height":1113,"rx":1123,"fill":299,"opacity":1124,"stroke":301,"style":224},"590","215","2","0.4",[202,1126,1043],{"x":1127,"y":1128,"fill":301,"style":275},"635","209",[202,1130,1132],{"x":1098,"y":867,"fill":213,"style":1131},"font-size:11px;text-anchor:middle","before",[202,1134,1135],{"x":1106,"y":867,"fill":213,"style":1131},"chat gated",[202,1137,1138],{"x":1117,"y":867,"fill":213,"style":1131},"video facade",[202,1140,1141],{"x":1127,"y":867,"fill":213,"style":1131},"tags removed",[202,1143,1145],{"x":1076,"y":1144,"fill":213,"style":308},"270","Median of 3 Lighthouse runs, mobile profile with simulated throttling",[311,1147,1148],{},"The audit's value is the ordering: without attribution, teams typically start with the analytics script, which was 18 ms of the original 760.",[27,1150,1152],{"id":1151},"pitfalls-rollback","Pitfalls & Rollback",[32,1154,1155,1162,1168,1174,1180,1186],{},[35,1156,1157,1161],{},[1158,1159,1160],"strong",{},"Auditing the homepage only."," Article and documentation templates usually carry more third-party code than the marketing front page.",[35,1163,1164,1167],{},[1158,1165,1166],{},"Single-run assertions."," Lighthouse on a shared runner is noisy; use three runs and the median or you will chase phantom regressions.",[35,1169,1170,1173],{},[1158,1171,1172],{},"Chasing the composite score."," It hides which metric moved. Assert on the underlying numbers.",[35,1175,1176,1179],{},[1158,1177,1178],{},"Ignoring the tag manager container."," Its own bundle may be small while the tags inside it are not — audit production, where the real container is live.",[35,1181,1182,1185],{},[1158,1183,1184],{},"Auditing a warm cache."," Run with a fresh profile; a cached vendor bundle understates the first-visit cost that new readers pay.",[35,1187,1188,1191],{},[1158,1189,1190],{},"Rollback:"," the audit changes nothing by itself. The CI assertion is one config file — lowering the threshold or removing the assertion restores the previous pipeline immediately.",[27,1193,1195],{"id":1194},"conclusion","Conclusion",[14,1197,1198,1199,25],{},"Attribution turns an argument about performance into a ranked list. Run the third-party summary against the template that carries the most vendor code, sort by blocking time, use the treemap to see what is inside the worst offenders, trace an idle page for recurring costs, and then freeze the result with a Lighthouse CI assertion. The fixes themselves — gating, facades, self-hosting — are covered in ",[21,1200,24],{"href":23},[27,1202,1204],{"id":1203},"faq","FAQ",[1206,1207,1209],"h3",{"id":1208},"what-is-the-difference-between-transfer-size-and-blocking-time-in-the-report","What is the difference between transfer size and blocking time in the report?",[14,1211,1212],{},"Transfer size is what came down the wire; blocking time is how long the main thread was unavailable to respond to input because that script was executing. They correlate loosely at best — a small script that builds UI can block for longer than a large one that only sends a request.",[1206,1214,1216],{"id":1215},"why-does-the-treemap-show-different-numbers-from-the-network-panel","Why does the treemap show different numbers from the network panel?",[14,1218,1219],{},"The treemap reports unminified script bytes and, when source maps are available, attributes them to modules, so it answers \"what is inside this bundle\". The network panel reports compressed transfer. Use the treemap to find unused code and the network panel to budget bandwidth.",[1206,1221,1223],{"id":1222},"should-i-audit-a-preview-deploy-or-production","Should I audit a preview deploy or production?",[14,1225,1226],{},"Both, for different reasons. Audit a preview deploy on every pull request to catch regressions before they ship. Audit production monthly, because tag managers and vendor updates change what runs without any change to your repository.",[1206,1228,1230],{"id":1229},"how-do-i-attribute-a-long-task-to-a-specific-vendor","How do I attribute a long task to a specific vendor?",[14,1232,1233,1234,1237],{},"Record a Performance trace, open the Bottom-Up view and group by URL. Anything attributed to a script whose origin is not yours is third-party work, and the ",[39,1235,1236],{},"attribution"," field on long-task entries gives you the same mapping programmatically.",[1206,1239,1241],{"id":1240},"is-a-lighthouse-score-a-good-performance-budget","Is a Lighthouse score a good performance budget?",[14,1243,1244],{},"No. The score is a weighted composite that hides which metric moved, and it is noisy run to run. Budget the underlying numbers you care about — third-party blocking time, transfer size, LCP and INP — and treat the score as a headline only.",[27,1246,1248],{"id":1247},"related","Related",[32,1250,1251,1260,1267,1274,1279],{},[35,1252,1253,1256,1257,1259],{},[1158,1254,1255],{},"Parent:"," ",[21,1258,24],{"href":23}," — what to do with what the audit finds.",[35,1261,1262,1266],{},[21,1263,1265],{"href":1264},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Flazy-loading-youtube-embeds-on-static-sites\u002F","Lazy-Loading YouTube Embeds on Static Sites"," — usually the second row of the ranking.",[35,1268,1269,1273],{},[21,1270,1272],{"href":1271},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Fself-hosting-analytics-to-cut-third-party-requests\u002F","Self-Hosting Analytics to Cut Third-Party Requests"," — removing an origin entirely.",[35,1275,1276,1278],{},[21,1277,53],{"href":52}," — the URL the CI audit runs against.",[35,1280,1281,1285],{},[21,1282,1284],{"href":1283},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002F","JavaScript Hydration & Partial Rendering"," — auditing your own bundle with the same tools.",[1287,1288,1289],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}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 pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":75,"searchDepth":99,"depth":99,"links":1291},[1292,1293,1294,1295,1296,1297,1298,1299,1300,1301,1308],{"id":29,"depth":99,"text":30},{"id":60,"depth":99,"text":61},{"id":316,"depth":99,"text":317},{"id":363,"depth":99,"text":364},{"id":634,"depth":99,"text":635},{"id":837,"depth":99,"text":838},{"id":952,"depth":99,"text":953},{"id":1151,"depth":99,"text":1152},{"id":1194,"depth":99,"text":1195},{"id":1203,"depth":99,"text":1204,"children":1302},[1303,1304,1305,1306,1307],{"id":1208,"depth":110,"text":1209},{"id":1215,"depth":110,"text":1216},{"id":1222,"depth":110,"text":1223},{"id":1229,"depth":110,"text":1230},{"id":1240,"depth":110,"text":1241},{"id":1247,"depth":99,"text":1248},[1310,1313,1316,1317],{"name":1311,"item":1312},"Home","\u002F",{"name":1314,"item":1315},"Performance Optimization & Core Web Vitals for SSGs","\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002F",{"name":24,"item":23},{"name":5,"item":1318},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Fauditing-third-party-scripts-with-lighthouse\u002F","2026-08-01","Use the third-party summary, the treemap and a long-task trace to attribute every kilobyte and millisecond to a vendor — then gate the total in CI so it cannot creep back.","md",[1323,1324,1325,1326,1328],{"q":1209,"a":1212},{"q":1216,"a":1219},{"q":1223,"a":1226},{"q":1230,"a":1327},"Record a Performance trace, open the Bottom-Up view and group by URL. Anything attributed to a script whose origin is not yours is third-party work, and the attribution field on long-task entries gives you the same mapping programmatically.",{"q":1241,"a":1244},{},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Fauditing-third-party-scripts-with-lighthouse",{"title":5,"description":1320},"performance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Fauditing-third-party-scripts-with-lighthouse\u002Findex","article","93bApKZvnO4s1piIUmX4HTF5pXTN486NmEHAi_v1jPk",[1336,1339,1342,1345,1348,1351,1354,1357,1360,1363,1366,1369,1372,1375,1378,1381,1384,1387,1390,1393,1396,1399,1402,1405,1408,1411,1414,1417,1420,1423,1426,1429,1432,1435,1438,1441,1444,1447,1450,1453,1456,1459,1462,1465,1468,1471,1473,1476,1479,1482,1485,1488,1489,1491,1493,1495,1498,1501,1504,1507,1510,1513,1516,1519,1522,1525,1528,1531,1534,1537,1539,1542,1545,1548,1551,1554,1557,1560,1563,1565,1568,1571,1574],{"path":1337,"title":1338},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fchoosing-between-astro-and-eleventy-for-large-docs","Astro vs Eleventy for Large Docs (1000+ Pages)",{"path":1340,"title":1341},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fcontent-collections-vs-eleventy-data-cascade","Content Collections vs the Eleventy Data Cascade",{"path":1343,"title":1344},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites","Astro vs Eleventy for Documentation Sites",{"path":1346,"title":1347},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fhow-to-benchmark-hugo-vs-astro-build-speeds","How to Benchmark Hugo vs Astro Build Speeds",{"path":1349,"title":1350},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories","Hugo Build Times for Large Repositories",{"path":1352,"title":1353},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fprofiling-hugo-templates-with-template-metrics","Profiling Hugo Templates With Template Metrics",{"path":1355,"title":1356},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fspeeding-up-hugo-builds-with-render-hooks-and-caching","Speeding Up Hugo Builds with Render Hooks & Caching",{"path":1358,"title":1359},"\u002Fchoosing-the-right-static-site-generator-for-production","Choosing the Right Static Site Generator for Production",{"path":1361,"title":1362},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Feleventy-vs-jekyll-for-markdown-heavy-blogs","Eleventy vs Jekyll for Markdown-Heavy Blogs",{"path":1364,"title":1365},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem","Jekyll Plugin Ecosystem",{"path":1367,"title":1368},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Freplacing-jekyll-plugins-when-migrating-to-eleventy","Replacing Jekyll Plugins When Migrating to Eleventy",{"path":1370,"title":1371},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Frunning-jekyll-on-github-pages-without-plugins","Running Jekyll on GitHub Pages Without Plugins",{"path":1373,"title":1374},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators","Migrating Between Static Site Generators",{"path":1376,"title":1377},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fkeeping-redirects-working-after-an-ssg-migration","Keeping Redirects Working After an SSG Migration",{"path":1379,"title":1380},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-a-docs-site-from-jekyll-to-hugo","Migrating a Docs Site From Jekyll to Hugo",{"path":1382,"title":1383},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-from-hugo-to-astro-without-breaking-urls","Migrating From Hugo to Astro Without Breaking URLs",{"path":1385,"title":1386},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fporting-shortcodes-and-includes-between-generators","Porting Shortcodes and Includes Between Generators",{"path":1388,"title":1389},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Fhandling-dynamic-routes-in-nextjs-static-export","Handling Dynamic Routes in Next.js Static Export",{"path":1391,"title":1392},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites","Next.js Static Export for Content Sites",{"path":1394,"title":1395},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Fmigrating-from-gatsby-to-nextjs-static-export","Migrating from Gatsby to Next.js Static Export",{"path":1397,"title":1398},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Fnextjs-static-export-vs-astro-for-marketing-sites","Next.js Static Export vs Astro for Marketing",{"path":1400,"title":1401},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fbest-ssg-for-technical-writers-without-coding-experience","Best SSG for Non-Developer Technical Writers",{"path":1403,"title":1404},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fchoosing-an-ssg-for-api-reference-documentation","Choosing an SSG for API Reference Documentation",{"path":1406,"title":1407},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix","SSG Framework Selection Matrix",{"path":1409,"title":1410},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fpicking-an-ssg-for-a-multi-language-documentation-site","Picking an SSG for a Multi-Language Docs Site",{"path":1412,"title":1413},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fssg-selection-checklist-for-engineering-teams","SSG Selection Checklist for Engineering Teams",{"path":1415,"title":1416},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs","CDN Caching Rules for SSGs",{"path":1418,"title":1419},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fpurging-the-cdn-cache-after-a-static-deploy","Purging the CDN Cache After a Static Deploy",{"path":1421,"title":1422},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fsetting-cache-control-headers-on-cloudflare-pages","Cache-Control Headers on Cloudflare Pages",{"path":1424,"title":1425},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fsetting-up-proper-cache-headers-on-netlify","Proper Cache Headers on Netlify for SSGs",{"path":1427,"title":1428},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Feliminating-layout-shift-from-web-fonts","Eliminating Layout Shift From Web Fonts",{"path":1430,"title":1431},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-late-loading-embeds","Fixing CLS From Late-Loading Embeds",{"path":1433,"title":1434},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites","Cumulative Layout Shift Fixes for Static Sites",{"path":1436,"title":1437},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Fmeasuring-cls-in-the-field-with-web-vitals-js","Measuring CLS in the Field With web-vitals.js",{"path":1439,"title":1440},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Freserving-space-for-images-and-embeds-to-stop-layout-shift","Reserving Space for Images and Embeds",{"path":1442,"title":1443},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites","Font Loading Strategies for Static Sites",{"path":1445,"title":1446},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fself-hosting-google-fonts-to-eliminate-layout-shift","Self-Host Google Fonts to Eliminate Layout Shift",{"path":1448,"title":1449},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fsubsetting-variable-fonts-for-faster-first-render","Subsetting Variable Fonts for Faster First Render",{"path":1451,"title":1452},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Fbuilding-an-image-cdn-pipeline-for-static-sites","Building an Image CDN Pipeline for Static Sites",{"path":1454,"title":1455},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro","Image Optimization Pipelines in Astro",{"path":1457,"title":1458},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Foptimizing-webp-images-in-hugo-without-plugins","Optimizing WebP Images in Hugo Without Plugins",{"path":1460,"title":1461},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Fserving-avif-with-fallbacks-on-static-sites","Serving AVIF With Fallbacks on Static Sites",{"path":1463,"title":1464},"\u002Fperformance-optimization-core-web-vitals-for-ssgs","Core Web Vitals Optimization for SSGs",{"path":1466,"title":1467},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fastro-islands-vs-full-hydration-performance","Astro Islands vs Full Hydration Performance",{"path":1469,"title":1470},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fhow-to-reduce-bundle-size-in-eleventy-builds","How to Reduce Bundle Size in Eleventy Builds",{"path":1472,"title":1284},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering",{"path":1474,"title":1475},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fmeasuring-inp-on-static-sites-with-real-user-monitoring","Measuring INP on Static Sites with RUM",{"path":1477,"title":1478},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Feliminating-render-blocking-css-on-static-sites","Eliminating Render-Blocking CSS on Static Sites",{"path":1480,"title":1481},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites","Largest Contentful Paint Optimization for Static Sites",{"path":1483,"title":1484},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Foptimizing-lcp-on-astro-with-priority-hints","Optimizing LCP on Astro with Priority Hints",{"path":1486,"title":1487},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Freducing-lcp-from-hero-images-on-static-sites","Reducing LCP from Hero Images on Static Sites",{"path":1330,"title":5},{"path":1490,"title":24},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites",{"path":1492,"title":1265},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Flazy-loading-youtube-embeds-on-static-sites",{"path":1494,"title":1272},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Fself-hosting-analytics-to-cut-third-party-requests",{"path":1496,"title":1497},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fautomating-eleventy-deployments-with-cloudflare-pages","Automating Eleventy Deployments on Cloudflare Pages",{"path":1499,"title":1500},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fdeploying-hugo-to-cloudflare-pages-and-workers","Deploying Hugo to Cloudflare Pages and Workers",{"path":1502,"title":1503},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup","Cloudflare Pages Edge Caching Setup",{"path":1505,"title":1506},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fdocs-as-code-review-workflow-for-writers","Docs-as-Code Review Workflow for Writers",{"path":1508,"title":1509},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams","Content Workflows for Documentation Teams",{"path":1511,"title":1512},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fscheduling-content-publication-with-cron-triggered-builds","Scheduling Content Publication With Cron-Triggered Builds",{"path":1514,"title":1515},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fwiring-a-headless-cms-to-a-static-build","Wiring a Headless CMS to a Static Build",{"path":1517,"title":1518},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fcaching-node-modules-in-github-actions-for-faster-ssg-builds","Caching node_modules in GitHub Actions",{"path":1520,"title":1521},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fdeploying-to-multiple-environments-from-one-workflow","Deploying to Multiple Environments From One Workflow",{"path":1523,"title":1524},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fhow-to-set-up-github-actions-for-hugo-deployments","GitHub Actions for Hugo Deployments",{"path":1526,"title":1527},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds","GitHub Actions for Automated SSG Builds",{"path":1529,"title":1530},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fcaching-hugo-builds-in-github-actions","Caching Hugo Builds in GitHub Actions",{"path":1532,"title":1533},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fenabling-incremental-builds-in-eleventy","Enabling Incremental Builds in Eleventy",{"path":1535,"title":1536},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs","Incremental Builds and Build Caching for SSGs",{"path":1538,"title":834},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fmeasuring-build-time-regressions-in-ci",{"path":1540,"title":1541},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fsharing-build-cache-across-ci-runners","Sharing Build Cache Across CI Runners",{"path":1543,"title":1544},"\u002Fproduction-ready-deployment-cicd-workflows","Production-Ready Deployment & CI\u002FCD for SSGs",{"path":1546,"title":1547},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies","Netlify vs Vercel Deployment Strategies",{"path":1549,"title":1550},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fnetlify-build-hooks-for-content-updates","Netlify Build Hooks for Content Updates",{"path":1552,"title":1553},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fsetting-up-deploy-previews-on-netlify-for-every-pull-request","Netlify Deploy Previews for Every Pull Request",{"path":1555,"title":1556},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fvercel-isr-vs-static-generation-for-ssgs","Vercel ISR vs Static Generation for SSGs",{"path":1558,"title":1559},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fautomating-preview-deploy-pipelines-with-github-actions","Automating Preview Deploy Pipelines with GitHub Actions",{"path":1561,"title":1562},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fcleaning-up-stale-preview-deployments","Cleaning Up Stale Preview Deployments",{"path":1564,"title":53},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests",{"path":1566,"title":1567},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Fatomic-deploys-vs-incremental-uploads","Atomic Deploys vs Incremental Uploads",{"path":1569,"title":1570},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites","Rollbacks and Deploy Safety for Static Sites",{"path":1572,"title":1573},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frolling-back-a-bad-static-deploy-in-under-a-minute","Rolling Back a Bad Static Deploy in Under a Minute",{"path":1575,"title":1576},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frunning-smoke-tests-against-a-preview-url","Running Smoke Tests Against a Preview URL",1785611671575]