AdSense Approved But Ads Not Showing: Fix It Fast

Code is on the page but the ad spot is blank. The fastest fix, plus the 7 real causes ordered by how often they break, with exact checks for each.

AdSense status says “Approved.” You pasted the snippet. You open the article and the spot where the ad should be is just empty space. Almost everyone suspects the code first, but the code is right about 80% of the time.

Fastest fix first: open AdSense, click Sites, and read the status next to your domain. If it says Getting ready instead of Ready, ad serving is still gated and there is nothing to fix in your code yet. If it says Ready but the slot is still blank, inspect the ad placeholder in DevTools and read the data-ad-status value on the <ins> tag. Those two checks resolve most cases in under two minutes.

The real culprits, in order: AdSense is still warming up the site or slot, the slot can’t get a fillable impression, ads.txt isn’t authorized, or your page is missing a signal Google needs to serve an ad. This article goes through them in the order they actually break.

First, read these two status signals

Before changing anything, collect two facts. They tell you which of the seven causes below you actually have.

Signal 1 — Site status (AdSense → Sites). As of June 2026 a site shows one of four states:

StatusWhat it meansWhat to do
ReadySite is cleared to show adsMove on to the slot-level checks below
Getting readyStill under review (usually a few days, up to 2-4 weeks)Wait. Code changes won’t help yet
Needs attentionA policy or technical issue is blocking servingOpen the site, fix the listed issue, then click Request review
Requires reviewSite hasn’t been checked, or went inactiveClick Request review

Signal 2 — data-ad-status on the <ins> tag. Open the page, right-click the blank ad spot, Inspect, and find the <ins class="adsbygoogle"> element. After the ad request finishes, AdSense writes one of three values (per the official AdSense docs):

data-ad-status valueMeaningWhere to look next
filledAn ad was returned and is showingIf you still see nothing: ad blocker, CSP, or an iframe sandbox is hiding it
unfilledNo ad was returned; the unit is emptyInventory (#5), CMP/consent (#7), warm-up (#1), or invalid-traffic muting (#6)
unfill-optimizedNo ad returned; AdSense collapsed the slotSame as unfilled — it’s a fill problem, not a code problem

If there’s no data-ad-status attribute at all, the script never ran on this slot: the unit is inside a display:none block, the adsbygoogle.push() call didn’t fire, or the loader script is missing. Jump to causes #3 and #4.

Common causes

Ordered by hit rate, highest first.

1. First 24-72 hours post-approval — site or slot is warming up

After approval, AdSense needs time to start serving on a new site or a newly created ad unit. The dashboard can say “Approved” while the Sites status still reads Getting ready, and even after it flips to Ready, fresh slots may stay unfilled for a day or two while the auction begins filling your inventory.

How to spot it: approval (or unit creation) was less than ~72 hours ago, data-ad-status="unfilled", and Sites status is Getting ready or freshly Ready. This is warm-up. Wait.

2. ads.txt missing or not authorized

If https://yourdomain.com/ads.txt doesn’t exist, or doesn’t contain your publisher ID, AdSense rejects ad requests from the site. The Sites page reports this directly under an ads.txt column with values Authorized, Unauthorized, or Not found.

How to spot it:

curl -s "https://yourdomain.com/ads.txt"

You should see exactly one Google line (the trailing f08c47fec0942fa0 is Google’s fixed certification/TAG ID — copy it verbatim):

google.com, pub-XXXXXXXXXXXXXXXX, DIRECT, f08c47fec0942fa0

The pub- ID must match your AdSense account exactly. Missing file, wrong ID, or extra/garbled fields = Unauthorized = no ads. Note: the AdSense crawler can take a few days, and up to a month to re-read ads.txt on a low-traffic site. To speed it up, go to Sites, click the site, and use Check for updates.

3. The ad slot doesn’t have a fillable width

AdSense responsive units need the parent container to have a defined, non-zero width before the script runs. If the <ins> is inside a display:none block, a 0-width sidebar, or a collapsed mobile drawer, the unit returns unfilled. The AdSense minimum renderable width is 250px for most display formats.

How to spot it: in DevTools, select the <ins class="adsbygoogle"> and read its computed width. If it’s 0px (or below ~250px on a desktop display slot), find the parent container and give it a real width.

4. Ad slot ID typo, or the loader/push never fired

Two related code faults. First, a copy-paste mistake: data-ad-slot="1234567890" doesn’t match any unit you created in AdSense → Ads → By ad unit. AdSense silently returns no ad rather than erroring. Second, the page is missing the loader script or the push() call, so the script never runs (no data-ad-status appears at all).

How to spot it: confirm the loader is present once in <head> (with your client ID):

<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXXXXXXXXXXXXXX" crossorigin="anonymous"></script>

Then list your units in AdSense → Ads → By ad unit and match every data-ad-slot in your code against that list. Any mismatch = no ad.

5. Page topic has no advertisers right now

AdSense has far more demand for “credit card” pages than “vintage typewriter restoration” pages. Pages on extremely niche topics, or in low-CPM regions, may genuinely have no fillable bids at a given moment. This shows as unfilled on the niche page only.

How to spot it: test the same code on your homepage (broader topic). If the homepage fills but the niche article doesn’t, it’s inventory, not code. Confirm in AdSense → Reports by checking the Coverage metric — healthy sites sit near 90%+; a low coverage number on specific pages confirms a fill problem.

6. AdSense detected and is muting “invalid traffic”

If you’ve been reloading your own page, clicking your own ads, or you have bot traffic, AdSense quietly throttles or disables serving to protect advertisers — often with no warning email until the pattern persists.

How to spot it: check AdSense → Brand safety → Policy center for invalid-traffic notes. Even without a formal warning, suspicious traffic patterns reduce fill silently. Never click or refresh your own live ads.

Since 16 January 2024 for the EEA and UK (and 31 July 2024 for Switzerland), serving personalized ads to users in those regions requires a Google-certified Consent Management Platform integrated with the IAB TCF. If a user hasn’t made a consent choice, or your CMP isn’t certified, AdSense serves non-personalized/limited ads at best and in some configurations nothing at all.

How to spot it: open the page in incognito and accept all cookies in the consent dialog. If ads now appear, the CMP gate is the cause. Confirm your CMP is on Google’s certified list, and decide your default for non-consenters: non-personalized ads, or nothing.

Shortest path to fix

Step 1: Confirm the two status signals (above)

If Sites status is not Ready, or data-ad-status is unfilled/unfill-optimized, you have a serving/fill problem, not a code problem. If there’s no data-ad-status at all, you have a code problem — continue.

Step 2: Verify ads.txt is authorized

curl -s "https://yourdomain.com/ads.txt"
diff <(curl -s "https://yourdomain.com/ads.txt") <(echo "google.com, pub-YOURID, DIRECT, f08c47fec0942fa0")

If empty or different, create/fix the file at the site root. For Astro, Next.js, and Vercel, place it at public/ads.txt. Then trigger a re-crawl from Sites → (your site) → Check for updates, and allow a few days for the status to flip to Authorized.

Step 3: Verify the ad unit exists and the slot ID matches

In AdSense → Ads → By ad unit, copy each slot ID. Grep your codebase:

grep -rn "data-ad-slot" src/

Every value should match a unit in AdSense. Delete unused snippets.

Step 4: Force a fillable width

If the slot is inside a flex/grid container that collapses on certain breakpoints:

.ad-slot {
  display: block;
  min-width: 250px;   /* AdSense minimum renderable width */
  min-height: 100px;
}

Or wrap the <ins> in a div with explicit width: 100%; min-height: 250px.

Open in incognito, reject the CMP, and see if any ad shows. If nothing, your CMP is blocking all ads for non-consenters. Make sure you’re on a Google-certified CMP, then allow non-personalized ads as the default for non-consenters. As a code-level fallback you can request non-personalized ads before the loader runs:

<script>
  (adsbygoogle = window.adsbygoogle || []).requestNonPersonalizedAds = 1;
</script>

Step 6: Confirm it’s fixed

Reconciliation isn’t instant. After fixing code or ads.txt, reload the live page in incognito (no ad blocker) and re-check data-ad-status: you want filled. Then check Reports → Coverage climbs toward ~90% over the next 24-48 hours. Don’t declare it broken again until you’ve waited at least 48 hours after the fix.

Prevention

  • Add an ads.txt validity check to CI: curl -sf yourdomain.com/ads.txt | grep -q "$PUB_ID".
  • Lint all data-ad-slot values against a known list at build time.
  • Keep ad slots out of conditionally-hidden containers; render the placeholder always, and only let AdSense collapse empty units (via the data-ad-status="unfilled" CSS rule) rather than hiding the whole container.
  • Never reload or click your own live ads — it triggers invalid-traffic flags.
  • Use a Google-certified CMP so EEA/UK/Switzerland traffic stays eligible for at least non-personalized ads.

FAQ

My account is approved but Sites still says “Getting ready” — is something broken? No. “Getting ready” means the per-site review is still running. It usually clears in a few days but can take 2-4 weeks. No code change speeds it up; ads won’t serve until it flips to Ready.

Why is data-ad-status="unfilled" even though everything is configured correctly? unfilled means the auction returned no ad for that request — warm-up, a niche/low-CPM page with no bids right now, a consent gate, or invalid-traffic muting. It’s a fill problem, not a code bug. Check the page topic against your homepage and your Coverage report.

How long does AdSense take to read a new or fixed ads.txt? A few days for most sites, and up to a month for low-traffic sites. Force a re-crawl from Sites → (your site) → Check for updates and wait for the status to read Authorized.

Ads show on my homepage but not on one article. Why? Almost always inventory (#5) or a width/visibility issue (#3) specific to that page’s layout. The homepage’s broader topic attracts more bids; a niche article may have none at that moment. Verify the slot’s computed width is non-zero and check that page’s coverage.

Should I hide the empty box when there’s no ad? Yes, but carefully. Use ins.adsbygoogle[data-ad-status="unfilled"]{display:none !important;} so the blank box collapses. Note this won’t catch unfill-optimized units, and never apply display:none to a slot before it requests — that causes the unfilled result in the first place.

Do I really need a consent banner just to show ads? If any of your traffic is in the EEA, the UK, or Switzerland, yes: a Google-certified CMP integrated with the IAB TCF has been required since 16 January 2024 for the EEA and UK (31 July 2024 for Switzerland) to serve personalized ads. Without it, that traffic may get no ads at all.

External references: AdSense: check the status of your sites, AdSense: data-ad-status parameter, Google consent management requirements (EEA/UK/Switzerland).

Tags: #AdSense #Monetization #Debug #Troubleshooting