[{"data":1,"prerenderedAt":885},["ShallowReactive",2],{"content:\u002Fjavascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance\u002Fisolating-ad-scripts-from-the-main-thread":3,"surroundings:\u002Fjavascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance\u002Fisolating-ad-scripts-from-the-main-thread":876},{"id":4,"title":5,"body":6,"description":855,"extension":856,"meta":857,"navigation":869,"path":870,"seo":871,"stem":874,"__hash__":875},"content\u002Fjavascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance\u002Fisolating-ad-scripts-from-the-main-thread\u002Findex.md","Isolating Ad Scripts from the Main Thread",{"type":7,"value":8,"toc":839},"minimark",[9,14,29,32,126,131,165,169,175,181,187,193,268,272,277,280,394,402,406,529,532,536,543,547,550,666,670,673,677,680,684,710,714,720,726,732,738,742,754,763,772,781,798,802,824,829,832,835],[10,11,13],"h1",{"id":12},"how-to-isolate-ad-scripts-from-the-main-thread","How to Isolate Ad Scripts from the Main Thread",[15,16,17,18,23,24,28],"p",{},"This guide covers the heaviest category in ",[19,20,22],"a",{"href":21},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance\u002F","Third-Party Script Performance",", within ",[19,25,27],{"href":26},"\u002Fjavascript-bundle-optimization-code-splitting\u002F","JavaScript Bundle Optimization & Code Splitting",". Programmatic advertising runs header-bidding auctions, identity resolution, viewability measurement and brand-safety checks in the page's JavaScript context, then renders creatives that load their own scripts. On ad-supported publishers, ad tech regularly accounts for the majority of main-thread time and requests.",[15,30,31],{},"Removing ads is not an option for businesses that depend on them, but much of the cost is structural rather than inherent: auctions running before content renders, creatives injected without reserved space, every slot on a long article requested at load, and creative code executing in the same thread as the page. Isolation — in time (lazy loading), in space (reserved slots) and in execution context (cross-origin iframes) — reduces the cost substantially while preserving revenue.",[15,33,34],{},[35,36,42,43,42,50,42,54,42,57,42,66,42,72,42,80,42,86,42,92,42,96,42,100,42,103,42,109,42,113,42,116,42,119,42,123,42],"svg",{"viewBox":37,"width":38,"role":39,"ariaLabel":40,"style":41},"0 0 760 268","100%","img","Layers of display advertising cost from auction scripts to creatives, each paired with its containment technique.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[44,45],"rect",{"className":46,"x":48,"y":48,"width":38,"height":38,"fill":49},[47],"svg-canvas","0","#ffffff",[51,52,53],"title",{},"Where ad cost lands and how to contain it",[55,56,40],"desc",{},[44,58],{"x":59,"y":59,"width":60,"height":61,"rx":62,"fill":63,"stroke":64,"style":65},"1","758","266","10","none","currentColor","stroke-opacity:0.18",[67,68,53],"text",{"x":69,"y":70,"fill":64,"style":71},"28.0","34.0","font-size:16px;font-weight:700",[44,73],{"x":69,"y":74,"width":75,"height":76,"rx":77,"fill":78,"stroke":78,"style":79},"56.0","704.0","40.0","6","#0466c8","fill-opacity:0.14;stroke-opacity:0.9",[67,81,85],{"x":82,"y":83,"fill":64,"style":84},"42.0","80.5","font-size:13px;font-weight:700","Ad library + auction",[67,87,91],{"x":88,"y":83,"fill":64,"style":89,"textAnchor":90},"189.9","font-size:12px","start","prebid \u002F GPT on your main thread — defer until after LCP, lazy-load slots",[44,93],{"x":69,"y":94,"width":75,"height":76,"rx":77,"fill":64,"stroke":64,"style":95},"106.0","fill-opacity:0.06;stroke-opacity:0.4",[67,97,99],{"x":82,"y":98,"fill":64,"style":84},"130.5","Slot rendering",[67,101,102],{"x":88,"y":98,"fill":64,"style":89,"textAnchor":90},"creative inserted into the page — reserve size to prevent CLS",[44,104],{"x":69,"y":105,"width":75,"height":76,"rx":77,"fill":106,"stroke":107,"style":108},"156.0","#ffc300","#b8860b","fill-opacity:0.24;stroke-opacity:0.9",[67,110,112],{"x":82,"y":111,"fill":64,"style":84},"180.5","Creative code",[67,114,115],{"x":88,"y":111,"fill":64,"style":89,"textAnchor":90},"runs inside an iframe — cross-origin keeps it off your event loop when isolated",[44,117],{"x":69,"y":118,"width":75,"height":76,"rx":77,"fill":78,"stroke":78,"style":79},"206.0",[67,120,122],{"x":82,"y":121,"fill":64,"style":84},"230.5","Measurement scripts",[67,124,125],{"x":88,"y":121,"fill":64,"style":89,"textAnchor":90},"viewability and verification — scope to visible slots only",[127,128,130],"h2",{"id":129},"rapid-diagnosis","Rapid Diagnosis",[132,133,134,142,148,159],"ul",{},[135,136,137,141],"li",{},[138,139,140],"strong",{},"Attribute main-thread time by domain"," in a throttled trace; sum ad-tech domains (ad servers, bidders, verification vendors).",[135,143,144,147],{},[138,145,146],{},"Check CLS sources."," In the Layout Shifts track, shifts attributed to ad containers or content below them indicate unreserved slots.",[135,149,150,153,154,158],{},[138,151,152],{},"Check slot loading."," Are below-the-fold slots requested at load? GPT's ",[155,156,157],"code",{},"enableLazyLoad"," and similar settings control this.",[135,160,161,164],{},[138,162,163],{},"Check frame isolation."," Are creatives rendered in cross-origin iframes (SafeFrames) or friendly (same-origin) iframes that share your process and can run on your main thread?",[127,166,168],{"id":167},"root-cause-analysis","Root Cause Analysis",[15,170,171,174],{},[138,172,173],{},"1. Auctions on the critical path."," Header bidding waits for many bidders before requesting ads, and its scripts parse and run during page load.",[15,176,177,180],{},[138,178,179],{},"2. Unreserved slot sizes."," Creatives of varying sizes insert into collapsed containers, pushing content and producing large layout shifts.",[15,182,183,186],{},[138,184,185],{},"3. Same-origin creative execution."," Friendly iframes and direct DOM injection let creative scripts run in your process and event loop, competing with your interactions.",[15,188,189,192],{},[138,190,191],{},"4. Eager loading of all slots."," A long article with ten slots requests all ten auctions at load, even though most users never scroll to most of them.",[15,194,195],{},[35,196,42,199,42,202,42,205,42,207,42,210,42,212,42,219,42,226,42,231,42,235,42,240,42,244,42,248,42,252,42,256,42,260,42,264,42],{"viewBox":197,"width":38,"role":39,"ariaLabel":198,"style":41},"0 0 760 194","Bar chart of main-thread time attributed to advertising on an article page across four increasingly isolated setups.",[44,200],{"className":201,"x":48,"y":48,"width":38,"height":38,"fill":49},[47],[51,203,204],{},"Main-thread time on an article page by ad setup (mid-tier phone)",[55,206,198],{},[44,208],{"x":59,"y":59,"width":60,"height":209,"rx":62,"fill":63,"stroke":64,"style":65},"192",[67,211,204],{"x":69,"y":70,"fill":64,"style":71},[67,213,218],{"x":214,"y":215,"fill":64,"style":216,"textAnchor":217},"213.9","70.0","font-size:13px","end","All slots at load, friendly iframes",[44,220],{"x":221,"y":74,"width":222,"height":223,"rx":224,"fill":106,"stroke":107,"style":225},"225.9","442.1","19","3","fill-opacity:0.7;stroke-opacity:0.9",[67,227,230],{"x":228,"y":215,"fill":64,"style":229},"674.0","font-size:12px;font-weight:600","1840ms",[67,232,234],{"x":214,"y":233,"fill":64,"style":216,"textAnchor":217},"101.0","+ lazy-load slots",[44,236],{"x":221,"y":237,"width":238,"height":223,"rx":224,"fill":78,"stroke":78,"style":239},"87.0","230.7","fill-opacity:0.55;stroke-opacity:0.9",[67,241,243],{"x":242,"y":233,"fill":64,"style":229},"462.5","960ms",[67,245,247],{"x":214,"y":246,"fill":64,"style":216,"textAnchor":217},"132.0","+ auction after LCP",[44,249],{"x":221,"y":250,"width":251,"height":223,"rx":224,"fill":78,"stroke":78,"style":239},"118.0","209.1",[67,253,255],{"x":254,"y":246,"fill":64,"style":229},"440.9","870ms",[67,257,259],{"x":214,"y":258,"fill":64,"style":216,"textAnchor":217},"163.0","+ SafeFrame creatives",[44,261],{"x":221,"y":262,"width":263,"height":223,"rx":224,"fill":78,"stroke":78,"style":239},"149.0","146.6",[67,265,267],{"x":266,"y":258,"fill":64,"style":229},"378.4","610ms",[127,269,271],{"id":270},"step-by-step-resolution","Step-by-Step Resolution",[273,274,276],"h3",{"id":275},"_1-reserve-slot-sizes","1. Reserve slot sizes",[15,278,279],{},"Give every ad container a minimum height equal to the most common creative size for that slot (or the largest, if you prefer no shift at all), and avoid collapsing empty slots above content.",[281,282,287],"pre",{"className":283,"code":284,"language":285,"meta":286,"style":286},"language-css shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast",".ad-slot--leaderboard { min-height: 90px; }\n@media (max-width: 727px) { .ad-slot--leaderboard { min-height: 50px; } }\n.ad-slot--mpu { min-height: 250px; }\n\u002F* trade-off: reserving the largest possible size wastes space when a smaller\n   creative fills; reserving the most common size risks a shift for larger ones.\n   Use your ad server's fill data to choose per slot. *\u002F\n","css","",[155,288,289,318,356,375,382,388],{"__ignoreMap":286},[290,291,294,298,302,305,308,311,315],"span",{"class":292,"line":293},"line",1,[290,295,297],{"class":296},"sPXB4",".ad-slot--leaderboard",[290,299,301],{"class":300},"saISM"," { ",[290,303,304],{"class":296},"min-height",[290,306,307],{"class":300},": ",[290,309,310],{"class":296},"90",[290,312,314],{"class":313},"sPARh","px",[290,316,317],{"class":300},"; }\n",[290,319,321,324,327,330,332,335,337,340,342,344,346,348,351,353],{"class":292,"line":320},2,[290,322,323],{"class":313},"@media",[290,325,326],{"class":300}," (",[290,328,329],{"class":296},"max-width",[290,331,307],{"class":300},[290,333,334],{"class":296},"727",[290,336,314],{"class":313},[290,338,339],{"class":300},") { ",[290,341,297],{"class":296},[290,343,301],{"class":300},[290,345,304],{"class":296},[290,347,307],{"class":300},[290,349,350],{"class":296},"50",[290,352,314],{"class":313},[290,354,355],{"class":300},"; } }\n",[290,357,359,362,364,366,368,371,373],{"class":292,"line":358},3,[290,360,361],{"class":296},".ad-slot--mpu",[290,363,301],{"class":300},[290,365,304],{"class":296},[290,367,307],{"class":300},[290,369,370],{"class":296},"250",[290,372,314],{"class":313},[290,374,317],{"class":300},[290,376,378],{"class":292,"line":377},4,[290,379,381],{"class":380},"sjfSM","\u002F* trade-off: reserving the largest possible size wastes space when a smaller\n",[290,383,385],{"class":292,"line":384},5,[290,386,387],{"class":380},"   creative fills; reserving the most common size risks a shift for larger ones.\n",[290,389,391],{"class":292,"line":390},6,[290,392,393],{"class":380},"   Use your ad server's fill data to choose per slot. *\u002F\n",[15,395,396,397,401],{},"Expected outcome: ad rendering stops shifting content; see ",[19,398,400],{"href":399},"\u002Fcore-web-vitals-measurement\u002Freducing-cumulative-layout-shift-cls\u002Fdebugging-cls-caused-by-dynamic-ad-injection\u002F","debugging CLS caused by dynamic ad injection",".",[273,403,405],{"id":404},"_2-lazy-load-below-the-fold-slots","2. Lazy-load below-the-fold slots",[281,407,411],{"className":408,"code":409,"language":410,"meta":286,"style":286},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","googletag.cmd.push(() => {\n  googletag.pubads().enableLazyLoad({\n    fetchMarginPercent: 200,      \u002F\u002F request when within 2 viewports\n    renderMarginPercent: 100,     \u002F\u002F render when within 1 viewport\n    mobileScaling: 2.0,           \u002F\u002F larger margins on mobile (faster scrolling)\n  });\n  googletag.enableServices();\n});\n\u002F\u002F trade-off: smaller margins save more work but risk empty slots when users\n\u002F\u002F scroll quickly, which can reduce viewability and revenue. Tune with your\n\u002F\u002F ad operations team using viewability data.\n","javascript",[155,412,413,431,447,461,475,489,494,505,511,517,523],{"__ignoreMap":286},[290,414,415,418,422,425,428],{"class":292,"line":293},[290,416,417],{"class":300},"googletag.cmd.",[290,419,421],{"class":420},"smZ65","push",[290,423,424],{"class":300},"(() ",[290,426,427],{"class":313},"=>",[290,429,430],{"class":300}," {\n",[290,432,433,436,439,442,444],{"class":292,"line":320},[290,434,435],{"class":300},"  googletag.",[290,437,438],{"class":420},"pubads",[290,440,441],{"class":300},"().",[290,443,157],{"class":420},[290,445,446],{"class":300},"({\n",[290,448,449,452,455,458],{"class":292,"line":358},[290,450,451],{"class":300},"    fetchMarginPercent: ",[290,453,454],{"class":296},"200",[290,456,457],{"class":300},",      ",[290,459,460],{"class":380},"\u002F\u002F request when within 2 viewports\n",[290,462,463,466,469,472],{"class":292,"line":377},[290,464,465],{"class":300},"    renderMarginPercent: ",[290,467,468],{"class":296},"100",[290,470,471],{"class":300},",     ",[290,473,474],{"class":380},"\u002F\u002F render when within 1 viewport\n",[290,476,477,480,483,486],{"class":292,"line":384},[290,478,479],{"class":300},"    mobileScaling: ",[290,481,482],{"class":296},"2.0",[290,484,485],{"class":300},",           ",[290,487,488],{"class":380},"\u002F\u002F larger margins on mobile (faster scrolling)\n",[290,490,491],{"class":292,"line":390},[290,492,493],{"class":300},"  });\n",[290,495,497,499,502],{"class":292,"line":496},7,[290,498,435],{"class":300},[290,500,501],{"class":420},"enableServices",[290,503,504],{"class":300},"();\n",[290,506,508],{"class":292,"line":507},8,[290,509,510],{"class":300},"});\n",[290,512,514],{"class":292,"line":513},9,[290,515,516],{"class":380},"\u002F\u002F trade-off: smaller margins save more work but risk empty slots when users\n",[290,518,520],{"class":292,"line":519},10,[290,521,522],{"class":380},"\u002F\u002F scroll quickly, which can reduce viewability and revenue. Tune with your\n",[290,524,526],{"class":292,"line":525},11,[290,527,528],{"class":380},"\u002F\u002F ad operations team using viewability data.\n",[15,530,531],{},"Expected outcome: only slots near the viewport run auctions and render; main-thread time at load roughly halves on long pages.",[273,533,535],{"id":534},"_3-start-the-auction-after-the-main-content-has-rendered","3. Start the auction after the main content has rendered",[15,537,538,539,542],{},"Load the ad library and run header bidding after LCP (or after ",[155,540,541],{},"load","), unless an above-the-fold slot is the business priority. Most revenue comes from slots the user sees after content appears anyway.",[273,544,546],{"id":545},"_4-render-creatives-in-cross-origin-iframes","4. Render creatives in cross-origin iframes",[15,548,549],{},"Prefer SafeFrame \u002F cross-origin rendering for creatives. With site isolation in modern browsers, cross-origin iframes can run in separate processes, keeping creative JavaScript off your page's main thread and away from your interactions.",[15,551,552],{},[35,553,42,556,42,559,42,562,42,564,42,567,42,569,42,573,42,579,42,583,42,588,42,591,42,595,42,598,42,602,42,606,42,610,42,612,42,615,42,617,42,619,42,621,42,624,42,627,42,631,42,633,42,635,42,637,42,640,42,642,42,644,42,647,42,651,42,653,42,656,42,658,42,661,42,663,42],{"viewBox":554,"width":38,"role":39,"ariaLabel":555,"style":41},"0 0 760 198","Comparison of direct injection, friendly iframes and cross-origin iframes for rendering ad creatives.",[44,557],{"className":558,"x":48,"y":48,"width":38,"height":38,"fill":49},[47],[51,560,561],{},"Creative rendering modes compared",[55,563,555],{},[44,565],{"x":59,"y":59,"width":60,"height":566,"rx":62,"fill":63,"stroke":64,"style":65},"196",[67,568,561],{"x":69,"y":70,"fill":64,"style":71},[44,570],{"x":69,"y":74,"width":571,"height":572,"rx":48,"fill":64,"stroke":64,"style":95},"206.7","30.0",[67,574,578],{"x":575,"y":576,"fill":64,"style":577,"textAnchor":90},"38.0","75.5","font-size:12.5px;font-weight:700","Rendering mode",[44,580],{"x":581,"y":74,"width":582,"height":572,"rx":48,"fill":64,"stroke":64,"style":95},"234.7","165.8",[67,584,587],{"x":585,"y":576,"fill":64,"style":577,"textAnchor":586},"317.6","middle","Shares your main thread",[44,589],{"x":590,"y":74,"width":582,"height":572,"rx":48,"fill":64,"stroke":64,"style":95},"400.4",[67,592,594],{"x":593,"y":576,"fill":64,"style":577,"textAnchor":586},"483.3","Can touch your DOM",[44,596],{"x":597,"y":74,"width":582,"height":572,"rx":48,"fill":64,"stroke":64,"style":95},"566.2",[67,599,601],{"x":600,"y":576,"fill":64,"style":577,"textAnchor":586},"649.1","Rich media features",[44,603],{"x":69,"y":604,"width":571,"height":572,"rx":48,"fill":63,"stroke":64,"style":605},"86.0","stroke-opacity:0.35",[67,607,609],{"x":575,"y":608,"fill":64,"style":577,"textAnchor":90},"105.5","Direct DOM injection",[44,611],{"x":581,"y":604,"width":582,"height":572,"rx":48,"fill":106,"stroke":107,"style":108},[67,613,614],{"x":585,"y":608,"fill":64,"style":89,"textAnchor":586},"yes",[44,616],{"x":590,"y":604,"width":582,"height":572,"rx":48,"fill":106,"stroke":107,"style":108},[67,618,614],{"x":593,"y":608,"fill":64,"style":89,"textAnchor":586},[44,620],{"x":597,"y":604,"width":582,"height":572,"rx":48,"fill":78,"stroke":78,"style":79},[67,622,623],{"x":600,"y":608,"fill":64,"style":89,"textAnchor":586},"all",[44,625],{"x":69,"y":626,"width":571,"height":572,"rx":48,"fill":63,"stroke":64,"style":605},"116.0",[67,628,630],{"x":575,"y":629,"fill":64,"style":577,"textAnchor":90},"135.5","Friendly (same-origin) iframe",[44,632],{"x":581,"y":626,"width":582,"height":572,"rx":48,"fill":106,"stroke":107,"style":108},[67,634,614],{"x":585,"y":629,"fill":64,"style":89,"textAnchor":586},[44,636],{"x":590,"y":626,"width":582,"height":572,"rx":48,"fill":106,"stroke":107,"style":108},[67,638,639],{"x":593,"y":629,"fill":64,"style":89,"textAnchor":586},"yes, via parent",[44,641],{"x":597,"y":626,"width":582,"height":572,"rx":48,"fill":78,"stroke":78,"style":79},[67,643,623],{"x":600,"y":629,"fill":64,"style":89,"textAnchor":586},[44,645],{"x":69,"y":646,"width":571,"height":572,"rx":48,"fill":63,"stroke":64,"style":605},"146.0",[67,648,650],{"x":575,"y":649,"fill":64,"style":577,"textAnchor":90},"165.5","Cross-origin iframe (SafeFrame)",[44,652],{"x":581,"y":646,"width":582,"height":572,"rx":48,"fill":78,"stroke":78,"style":79},[67,654,655],{"x":585,"y":649,"fill":64,"style":89,"textAnchor":586},"isolated when site-isolated",[44,657],{"x":590,"y":646,"width":582,"height":572,"rx":48,"fill":78,"stroke":78,"style":79},[67,659,660],{"x":593,"y":649,"fill":64,"style":89,"textAnchor":586},"no",[44,662],{"x":597,"y":646,"width":582,"height":572,"rx":48,"fill":64,"stroke":64,"style":95},[67,664,665],{"x":600,"y":649,"fill":64,"style":89,"textAnchor":586},"via API",[127,667,669],{"id":668},"verification","Verification",[15,671,672],{},"Compare traces before and after on the same article at the same scroll depth: main-thread time attributed to ad domains should fall, layout shifts from ad containers should disappear, and the interactions you script (opening a menu, tapping a share button) should no longer overlap ad tasks. In the field, compare INP and CLS p75 on ad-supported templates and monitor revenue metrics (fill rate, viewability, RPM) with the ad operations team.",[127,674,676],{"id":675},"worked-example-a-news-publisher","Worked Example: A News Publisher",[15,678,679],{},"A news publisher's article template had nine ad slots, all requested at load with friendly-iframe rendering, and a header-bidding wrapper with eleven bidders. Field data: INP p75 380ms, CLS p75 0.21. The team reserved slot sizes from fill data, enabled lazy loading with margins tuned for mobile scrolling, moved the bidding wrapper to load after LCP, cut bidders to the seven that produced 97% of revenue, and switched to SafeFrame rendering where demand partners supported it. Six weeks later: INP p75 210ms, CLS p75 0.04, LCP p75 improved by 600ms, and RPM was within 2% of before — viewability had risen because ads now rendered where users actually were.",[127,681,683],{"id":682},"common-mistakes","Common Mistakes",[132,685,686,692,698,704],{},[135,687,688,691],{},[138,689,690],{},"Collapsing empty slots above content."," An unfilled slot that collapses after layout shifts everything below it.",[135,693,694,697],{},[138,695,696],{},"Lazy-loading without mobile tuning."," Mobile users scroll faster; margins that work on desktop leave mobile slots empty.",[135,699,700,703],{},[138,701,702],{},"Adding bidders without measuring."," Each bidder adds script and network cost; prune by revenue contribution.",[135,705,706,709],{},[138,707,708],{},"Testing without ads."," Ad blockers on developer machines hide the problem entirely.",[127,711,713],{"id":712},"edge-cases","Edge Cases",[15,715,716,719],{},[138,717,718],{},"Sticky and anchor ads."," These overlay content and usually do not shift layout, but their scripts still run and they can obscure the LCP element on small screens.",[15,721,722,725],{},[138,723,724],{},"Video ads."," Outstream video players are heavy; lazy-load them strictly and never above the fold on mobile.",[15,727,728,731],{},[138,729,730],{},"Ad refresh."," Refreshing slots on a timer re-runs auctions and creative code repeatedly during the visit, adding main-thread work long after load. Limit refresh to visible slots and reasonable intervals.",[15,733,734,737],{},[138,735,736],{},"Consent states."," Ad behaviour differs before and after consent; measure both, as non-consented sessions may load lighter stacks.",[127,739,741],{"id":740},"faq","FAQ",[743,744,747,751],"details",{"className":745},[746],"faq-item",[748,749,750],"summary",{},"Do cross-origin iframes always run in a separate process?",[15,752,753],{},"With site isolation (default on desktop Chromium and increasingly on Android), cross-site iframes run in separate renderer processes. On devices or browsers without full isolation, they may share a process but still cannot touch your DOM. Either way they are better contained than same-origin frames.",[743,755,757,760],{"className":756},[746],[748,758,759],{},"Will delaying the auction reduce revenue?",[15,761,762],{},"It can reduce above-the-fold impressions slightly. In practice many publishers see neutral or positive revenue after performance work, because faster pages retain users longer and viewability improves. Test with a holdout group and measure.",[743,764,766,769],{"className":765},[746],[748,767,768],{},"Can ad code run in a Web Worker?",[15,770,771],{},"Parts of header bidding logic could in principle, and some vendors experiment with it, but most ad libraries assume DOM access. Isolation via iframes and timing via lazy loading are the practical levers today.",[743,773,775,778],{"className":774},[746],[748,776,777],{},"How do I attribute INP problems to specific ad vendors?",[15,779,780],{},"Collect LoAF script attribution in RUM and group by script origin. Vendors whose scripts appear in INP frames are the ones to prune, defer or isolate first.",[743,782,784,787],{"className":783},[746],[748,785,786],{},"Should ad slots use content-visibility or containment?",[15,788,789,790,793,794,797],{},"Containment on the slot container (",[155,791,792],{},"contain: layout",") limits how far a creative's layout changes propagate, which can reduce layout cost. Avoid ",[155,795,796],{},"content-visibility: auto"," on slots themselves: it can interfere with viewability measurement, which ad partners rely on for billing.",[127,799,801],{"id":800},"related","Related",[132,803,804,810,817],{},[135,805,806,809],{},[19,807,808],{"href":399},"Debugging CLS caused by dynamic ad injection"," — the layout half of the problem.",[135,811,812,816],{},[19,813,815],{"href":814},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance\u002Fauditing-google-tag-manager-container-weight\u002F","Auditing Google Tag Manager container weight"," — the other big third-party layer.",[135,818,819,823],{},[19,820,822],{"href":821},"\u002Fcore-web-vitals-measurement\u002Flong-animation-frames-api\u002Fsending-loaf-data-in-rum-beacons\u002F","Sending LoAF data in RUM beacons"," — attributing slow interactions to vendors.",[825,826,828],"script",{"type":827},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"How to Isolate Ad Scripts from the Main Thread\",\n  \"description\": \"Techniques for containing the main-thread, layout and network cost of display advertising so ads stop dominating INP, LCP and CLS.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Reserve slot sizes\",\n      \"text\": \"Give every ad container a minimum height equal to the most common creative size for that slot (or the largest, if you prefer no shift at all), and avoid collapsing empty slots above content.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Lazy-load below-the-fold slots\",\n      \"text\": \"Expected outcome: only slots near the viewport run auctions and render; main-thread time at load roughly halves on long pages.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Start the auction after the main content has rendered\",\n      \"text\": \"Load the ad library and run header bidding after LCP (or after load), unless an above-the-fold slot is the business priority.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Render creatives in cross-origin iframes\",\n      \"text\": \"Prefer SafeFrame \u002F cross-origin rendering for creatives.\"\n    }\n  ]\n}\n",[825,830,831],{"type":827},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"How to Isolate Ad Scripts from the Main Thread\",\n  \"description\": \"Techniques for containing the main-thread, layout and network cost of display advertising so ads stop dominating INP, LCP and CLS.\",\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\u002Fjavascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance\u002Fisolating-ad-scripts-from-the-main-thread\u002F\"\n  }\n}\n",[825,833,834],{"type":827},"\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\": \"JavaScript Bundle Optimization & Code Splitting\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 3,\n      \"name\": \"Third-Party Script Performance\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"Isolating Ad Scripts from the Main Thread\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fjavascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance\u002Fisolating-ad-scripts-from-the-main-thread\u002F\"\n    }\n  ]\n}\n",[836,837,838],"style",{},"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 .sPARh, html code.shiki .sPARh{--shiki-default:#A0111F;--shiki-dark:#FF9492;--shiki-light:#A0111F}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);}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}",{"title":286,"searchDepth":320,"depth":320,"links":840},[841,842,843,849,850,851,852,853,854],{"id":129,"depth":320,"text":130},{"id":167,"depth":320,"text":168},{"id":270,"depth":320,"text":271,"children":844},[845,846,847,848],{"id":275,"depth":358,"text":276},{"id":404,"depth":358,"text":405},{"id":534,"depth":358,"text":535},{"id":545,"depth":358,"text":546},{"id":668,"depth":320,"text":669},{"id":675,"depth":320,"text":676},{"id":682,"depth":320,"text":683},{"id":712,"depth":320,"text":713},{"id":740,"depth":320,"text":741},{"id":800,"depth":320,"text":801},"Techniques for containing the main-thread, layout and network cost of display advertising so ads stop dominating INP, LCP and CLS.","md",{"slug":858,"type":859,"breadcrumb":860,"datePublished":868,"dateModified":868},"isolating-ad-scripts-from-the-main-thread","article",[861,864,865,866],{"name":862,"url":863},"Home","\u002F",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":867},"\u002Fjavascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance\u002Fisolating-ad-scripts-from-the-main-thread\u002F","2026-10-06",true,"\u002Fjavascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance\u002Fisolating-ad-scripts-from-the-main-thread",{"title":872,"description":873},"Isolating Ad Scripts to Protect INP and CLS","Ad tech runs auctions, viewability checks and creatives on your main thread. Use cross-origin iframes, lazy slots and reserved sizes to contain the cost.","javascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance\u002Fisolating-ad-scripts-from-the-main-thread\u002Findex","13w7ZPbPpOZddbX60LwUnapOXIC30u1V3_bglbYGMX4",[877,881],{"title":878,"path":879,"stem":880},"Auditing Google Tag Manager Container Weight","\u002Fjavascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance\u002Fauditing-google-tag-manager-container-weight","javascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance\u002Fauditing-google-tag-manager-container-weight\u002Findex",{"title":882,"path":883,"stem":884},"Loading Chat Widgets on Interaction","\u002Fjavascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance\u002Floading-chat-widgets-on-interaction","javascript-bundle-optimization-code-splitting\u002Fthird-party-script-performance\u002Floading-chat-widgets-on-interaction\u002Findex",1791308076586]