AdSense on Blogger Without Hurting Core Web Vitals (Fixed-Size Responsive Ads)

Stop AdSense from wrecking your Core Web Vitals. Fixed-size responsive ads, delayed loading and smart placement for zero CLS, fast LCP and INP on blog

  • AdSense and Core Web Vitals guide cover

    AdSense pays the bills, but the default ad code is one of the most common reasons a Blogger site fails Core Web Vitals. Ads appear late and push the text down, Google's ad script keeps the browser busy, and auto ads drop units wherever they like. This guide shows the fix we use on our own blog: fixed-size responsive ad units, a script that loads only when the reader starts to read, and placements that never touch the first screen. The method follows AdSense's own guide for modifying responsive ad code, so it's fully within the program policies.

    How ads hurt Core Web Vitals

    Google measures three things on every page. Ads can damage all three:

    MetricWhat it measuresGoodHow default ads hurt it
    CLS (Cumulative Layout Shift)How much the page jumps while loading0.1 or lessA responsive ad starts at zero height, then grows to 250 or 280 px when the ad arrives and pushes everything below it down.
    LCP (Largest Contentful Paint)How fast the main content appears2.5 s or lessThe ad script and its extra requests compete with your cover image and fonts. An ad on the first screen can even become the "largest" element.
    INP (Interaction to Next Paint)How fast the page reacts to taps and clicks200 ms or lessAd scripts run a lot of JavaScript. While they run, the reader's taps wait.

    Auto ads make it worse: they insert units at places you didn't choose, after the page has already been drawn, so each one is a new layout shift.

    The good news: you don't have to choose between ads and speed. The three problems above have three direct fixes, one for each metric.

    Is changing the ad size allowed?

    Yes. AdSense doesn't allow changing the ad code in general, but it publishes an official guide called "How to modify your responsive ad code". It explains exactly what we do here: set the width and height of a responsive unit with CSS, per screen size. As long as you:

    • use a display ad unit created in your account,
    • keep the <ins> tag, the data-ad-client and data-ad-slot values unchanged,
    • pick sizes AdSense supports (see the table below),

    you're following the rules. Don't hide ads behind other content, don't make them look like menus or downloads, and don't put them where readers click by accident.

    Step 1: Create a display ad unit

    1. Open AdSenseSign in to your AdSense account and open Ads from the side menu.
    2. By ad unitChoose the By ad unit tab, then Display ads.
    3. Name itGive it a clear name, for example in_article_1. One unit per place makes the reports easier to read.
    4. Keep it responsiveLeave the size on Responsive and click Create.
    5. Copy two valuesFrom the code AdSense gives you, you only need data-ad-client (your publisher ID, starts with ca-pub-) and data-ad-slot (the ID of this unit).

    Step 2: Give the ad a fixed size

    This is the step that fixes CLS. Instead of letting the ad decide its height after it loads, we tell the browser the exact size before anything arrives. The space is reserved from the first paint, so nothing moves when the ad fills it.

    <style>
    .ad-in-article{display:inline-block;width:300px;height:250px}
    @media (min-width:500px){.ad-in-article{width:468px;height:60px}}
    @media (min-width:800px){.ad-in-article{width:728px;height:90px}}
    </style>
    <div style="text-align:center;margin:24px 0">
      <ins class="adsbygoogle ad-in-article"
           data-ad-client="ca-pub-XXXXXXXXXXXXXXXX"
           data-ad-slot="1234567890"></ins>
      <script>(adsbygoogle = window.adsbygoogle || []).push({});</script>
    </div>

    Replace the two values with yours. What the code does:

    Screen widthDeviceAd size
    Under 500 pxPhone300 × 250 (medium rectangle)
    500 to 799 pxTablet468 × 60 (banner)
    800 px and upDesktop728 × 90 (leaderboard)

    Notice what's missing compared with the default code: data-ad-format="auto" and data-full-width-responsive="true". Those two attributes let AdSense resize the unit after loading, which is exactly the jump we want to avoid. Remove them when you set your own sizes.

    Need several units on one page? Copy the block, give each one its own class name and its own data-ad-slot. Only one <style> per class is needed.

    Optional: hide empty slots

    Sometimes AdSense has no ad to show and the reserved box stays empty. AdSense marks those units with data-ad-status="unfilled", and you can hide them:

    ins.adsbygoogle[data-ad-status="unfilled"]{display:none!important}

    Hiding an empty box below the reader's screen is harmless. If the unit is on the first screen, keep the empty space instead: hiding it would cause the very shift we just removed.

    Step 3: Load the AdSense script later

    This step fixes LCP and INP. Normally the AdSense script (adsbygoogle.js) starts downloading together with your page, then pulls in many more files. With the code below it waits until the reader actually does something: scrolls, taps, moves the mouse or presses a key. By then your text and cover are already on screen. If the reader does nothing, it loads anyway after a few seconds.

    Add this once, before </body> in your theme (Theme › Edit HTML) or in an HTML/JavaScript gadget, and remove any other line that loads adsbygoogle.js:

    <script>
    (function(){
      var done = false, ev = ['scroll','mousemove','touchstart','keydown'];
      function load(){
        if (done) return; done = true;
        ev.forEach(function(e){ removeEventListener(e, load); });
        var s = document.createElement('script');
        s.async = true; s.crossOrigin = 'anonymous';
        s.src = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXXXXXXXXXXXXXX';
        document.head.appendChild(s);
      }
      ev.forEach(function(e){ addEventListener(e, load, {once:true, passive:true}); });
      setTimeout(load, 5000);
    })();
    </script>

    The ad units from step 2 keep working without any change. Their push({}) line puts each ad in a queue, and the script serves the whole queue as soon as it arrives.

    Will this lower my earnings? In practice, no. Ads below the first screen are only seen when the reader scrolls, and scrolling is one of the events that loads the script. Readers who leave without scrolling never saw those ads anyway.

    Step 4: Place ads below the first screen

    The first screen is what decides LCP, and it's what the reader judges your site by. Keep it free of ads, and use the places that perform best:

    1. Inside the post, after the second or third paragraph. Usually the best earning spot, and already below the first screen on phones.
    2. In the middle of long posts. Between two sections, never in the middle of a step list or a code block.
    3. At the end of the post, before the comments or related posts.
    4. In the sidebar on desktop, where a 300 × 600 or 300 × 250 unit doesn't touch the text.
    5. Above the footer, for one wide unit.
    • Manual units in planned places: stable layout, better reader experience, clearer reports.
    • Fewer, well-placed ads often earn more than many random ones.
    • Ads under the header: push the content down and slow the first screen.
    • Auto ads in-page formats: placed after load, so every unit is a layout shift.

    If you keep Auto ads on for the overlay formats (anchor and vignette), turn off the in-page formats in Ads › By site › Edit. Overlays sit on top of the page and don't shift it.

    Which ad sizes earn the most

    Size matters. Popular sizes have more advertisers competing for them, which means more ads to show and better prices. These are the safest choices:

    SizeNameBest for
    300 × 250Medium rectanglePhones, inside posts, sidebar. The most requested size.
    336 × 280Large rectangleInside posts on wide screens. Too wide for some phones.
    728 × 90LeaderboardDesktop and tablet, between sections.
    300 × 600Half pageDesktop sidebar. Popular with advertisers.
    320 × 100Large mobile bannerPhones, between sections.
    320 × 50Mobile leaderboardPhones, when you want a light ad.
    160 × 600Wide skyscraperNarrow sidebars.
    970 × 250BillboardAbove the footer on desktop. Fewer advertisers.

    Don't invent sizes. An unsupported size may stay empty or overflow the page on small screens. Make sure each size fits the narrowest screen it's used on: a 336 px ad on a 320 px phone will stick out.

    Measure the result

    1. Test before you changeOpen pagespeed.web.dev, paste a post address and save the Mobile scores for LCP, CLS and TBT.
    2. Apply steps 2 to 4Change the ad code on that post and the script in your theme.
    3. Test againRun the same test. CLS from ads should now be close to 0, and TBT (the lab version of INP) should drop clearly.
    4. Wait for real dataThe field data at the top of PageSpeed and the Core Web Vitals report in Search Console use real visits from the last 28 days. Give them a few weeks.

    After switching to fixed sizes you may see a few empty slots for a day or two while AdSense adjusts. That's normal; fill rates come back once the new units have some history.

    Questions

    Is this against AdSense policies?

    No. Setting the size of a responsive unit with CSS is described in AdSense's own help page for modifying responsive ad code. You keep the original unit, publisher ID and slot ID.

    Can I delay the AdSense script like this?

    Yes. You're only choosing when the official script loads; the ads themselves, the code and the clicks are untouched. Just keep a fallback timer so readers who don't interact still get ads.

    Do I still need data-ad-format="auto"?

    No. Remove it together with data-full-width-responsive when you set the size yourself, otherwise AdSense can resize the unit after loading and the layout shift comes back.

    My ads show as empty boxes. What's wrong?

    Check that the size is supported and fits the screen, that the publisher and slot IDs are correct, and that the site is approved in Ads › Sites. New units can also stay empty for a short time.

    Does this work with any Blogger theme?

    Yes. Ad units can go into the post HTML or into an HTML/JavaScript gadget, and the loader script works in any theme. Make sure adsbygoogle.js is loaded only once on the page.