Skip to main content
Builder’s Journal

Why Your AdSense Impressions Suddenly Dropped to Zero

· · 4 min read

Why Your AdSense Impressions Suddenly Dropped to Zero

If your AdSense impressions collapsed right after a "tidy up the empty ad boxes" change — even though the ad code is still on every page — you probably hid the ad slots before AdSense could measure them. AdSense measures a slot’s available width before it fills it, and it will not fill a slot that measures 0px wide. A display:none (or otherwise collapsed) wrapper reports availableWidth = 0, so nothing serves. "Hide until filled" becomes a deadlock: hidden because it’s empty, empty because it’s hidden.

What you’ll learn: the exact chicken-and-egg mechanic that silently kills impressions, and the correct pattern — visible by default, collapse only after a confirmed unfilled status.

Evidence note: this happened on my own WordPress site. The before/after logic is verified in the live code; I’m describing the impression change from memory of the incident rather than pasting my AdSense figures.

What I did (and why it seemed reasonable)

Empty ad slots look bad — a grey box or dead space where no ad loaded. So I shipped what felt like an obvious tidy-up: hide the ad wrapper until it’s filled. The CSS collapsed the container by default, and the plan was to reveal it once an ad arrived. Cleaner pages, no empty boxes. What could go wrong?

What broke

Impressions cratered — effectively to zero — across the whole site, within a day. The confusing part: the ad code was still on every page. View source, and there’s the <ins class="adsbygoogle"> exactly where it should be. Nothing looked broken. But AdSense was serving almost nothing.

The root cause

AdSense decides whether (and what) to serve by measuring the slot’s available width first. The flow is: the slot exists in the layout → AdSense reads its width → if there’s usable width, it requests and fills an ad.

Hide the wrapper with display:none and that first measurement returns availableWidth = 0. AdSense won’t fill a zero-width slot, so it reports the slot as unfilled — and my CSS, seeing "not filled," kept it hidden. That’s the deadlock:

  • The slot is hidden because it’s empty.
  • The slot is empty because, while hidden, it measures 0px and can’t be filled.

Nothing ever breaks the loop. Every slot on the site sat collapsed and unfillable. My "cleaner pages" change had quietly switched off the ads.

The recovery

The fix inverts the default. Slots are visible by default so AdSense can measure a real width and fill them; you only collapse a slot after it’s confirmed dead — never pre-emptively.

AdSense writes its outcome to a data-ad-status attribute on the <ins> (filled or unfilled). Watch for that and act only on a confirmed result:

document.querySelectorAll('ins.adsbygoogle').forEach(function(ins){
  var wrap = ins.closest('.ad-wrap');
  if (!wrap) return;

  var check = function(){
    var s = ins.getAttribute('data-ad-status');
    if (s === 'unfilled') wrap.style.display = 'none'; // collapse ONLY when confirmed empty
  };
  check();
  new MutationObserver(check)
    .observe(ins, { attributes: true, attributeFilter: ['data-ad-status'] });

  // Fallback: no status after 4s means adsbygoogle.js never ran
  // (ad blocker / DNS blocking) — safe to collapse then, too.
  setTimeout(function(){
    if (!ins.getAttribute('data-ad-status')) wrap.style.display = 'none';
  }, 4000);
});

The key change: the slot has real width during measurement, so filled slots serve normally; only slots AdSense itself marks unfilled — or where the script was blocked entirely — get collapsed. No empty boxes, no deadlock. Impressions recovered once this shipped.

To avoid the ugly-empty-box problem that started all this, keep the pre-fill wrapper visually neutral (on a dark theme, an empty transparent wrapper is invisible anyway, and the "Advertisement" label stays hidden until filled). You get clean pages without starving the measurement step.

The warning signs I missed

  • "Impressions to zero" with the code still present is almost never an account problem — it’s a rendering/measurement problem on your side.
  • Any CSS that touches an ad container — display:none, height:0, visibility:hidden, collapsing parents — is a prime suspect. AdSense needs a measurable, visible slot at fill time.
  • I tested that the page looked right, not that ads still served. Those are different checks.

Prevention

  1. Never hide an ad slot before it’s filled. Visible by default.
  2. Collapse only on a confirmed data-ad-status="unfilled" (or a timeout for blocked scripts).
  3. Treat any change to an ad container’s box model as revenue-affecting — verify serving, not just appearance.
  4. After any ad/layout change, check a real page (logged out, no ad blocker) and confirm data-ad-status="filled" on the slots.

The lesson

The instinct to hide empty ad boxes is right; doing it before the fill is the mistake, because AdSense measures the slot before it fills it and won’t touch a zero-width one. Visible-by-default, collapse-on-confirmed-unfilled is the only ordering that works. A one-line CSS "tidy-up" turned off my ads while every page still looked perfect — so after any ad change, verify that slots serve, not just that they look clean.

AI assisted with drafting; the mistake, the deadlock, and the fix are from my own site; exact AdSense figures are omitted deliberately.

Share this article

Leave a Reply

Your email address will not be published. Required fields are marked *