AdSense Shows on Homepage But Not Article Pages: 6 Causes + Fix

Homepage AdSense renders, article pages stay blank. Usually a template-only difference: a missing script tag, a CSS-collapsed slot, a wrong ad-slot ID, or thin content. A DevTools side-by-side method to pin which one.

Your homepage shows AdSense ads fine. You click into an article and the slots are blank. Same ad-unit IDs, same domain, same approved account. This is the “different template” failure mode, and it is almost never an AdSense bug. Something is structurally different between your two templates: a missing script tag, a CSS rule that collapses the slot to zero, a wrong data-ad-slot value, or content thin enough to fail on a single article but not on the aggregated homepage.

Fastest fix: open the article in Chrome, press F12, go to the Network tab, type ads? in the filter. If you see no request starting with ads?client, your article template never loaded or fired the AdSense code — that is causes 1 or 5 below, and the fix is moving the script and push() into one shared layout. If the request is there but returns 403 or the slot shows data-ad-status="unfilled", it is a content/policy or ad-unit-ID problem (causes 3, 4, 6).

The diagnostic key is comparing the two templates side by side in DevTools, not re-reading your AdSense settings. The Google Publisher Toolbar extension that older guides recommend was retired in 2020 — as of June 2026 the supported tool is plain Chrome DevTools plus the in-account ad-serving troubleshooter.

Which bucket are you in (30-second triage)

What you see on the article pageLikely causeJump to
No ads?client request in NetworkScript/push() missing in article templateCause 1 / 5
Request present, <ins> has width/height = 0CSS collapses the slotCause 2
Request returns 403Account/site-level serving block (ads.txt, policy)Cause 3 / 4
data-ad-status="unfilled" on a normal-size slotThin content or wrong ad-unit IDCause 4 / 6
ERR_BLOCKED_BY_CLIENT in ConsoleAd blocker (yours), not a site bugNot on you

Common causes

Ordered by hit rate, highest first.

1. AdSense script loads on homepage but not the article template

A common scenario: you added the AdSense loader to your homepage layout, but the article uses a different layout that does not include it. The article’s <ins> tag is there, but adsbygoogle.js never executed.

How to spot it: DevTools → Network → on an article page, type ads? in the filter. If there is no request beginning with ads?client, no ad request left the page. Also check for the loader itself by filtering adsbygoogle.js — 0 results means the script tag is absent from the article template.

2. Article template wraps the slot in a CSS-collapsed container

The slot exists in the DOM, but its parent is display: none, width: 0, height: 0, or inside a tab/accordion that is not open. The homepage uses a different parent, so the slot renders there. AdSense runs a width validation: if the responsive <ins> has no measurable space, it refuses to fill and the Console logs an adsbygoogle.js validation error such as No slot size for availableWidth=0.

How to spot it: Inspect <ins class="adsbygoogle"> on the article → Computed → check width and height. If 0, the parent is collapsing it. Compare to the homepage version.

3. Different ad-unit IDs — only the homepage’s is correctly configured

The two templates use different data-ad-slot values. The homepage’s was set up correctly in AdSense; the article’s points to a slot that was deleted or never created. A request to a non-existent unit can come back 403 or simply stay unfilled.

How to spot it:

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

Compare the values to AdSense → Ads → By ad unit. The article’s value must match an existing, active unit.

4. Article content too thin to serve ads

AdSense program policies and the Google-served ads on screens without publisher content policy restrict serving on low-value or sparse pages. The homepage aggregates content (latest posts, hero text, categories), so it clears the bar; a very short individual article may not. There is no published hard word count, but as of June 2026 pages where more than half the visible area is non-original or under ~300 words are the usual trigger, and AdSense will set data-ad-status="unfilled" on those articles while still serving the homepage.

How to spot it: Word count under ~300, thin structure, little original text. Confirm with the bucket: a normal-size slot reporting unfilled across many refreshes, while other (longer) articles fill, points here.

5. Article template fires push() before the slot exists (or never)

If your framework hydrates the article asynchronously and adsbygoogle.js runs push({}) before the <ins> is in the DOM — or the push() never runs at all on the article route — the slot stays blank. SPA route changes are the classic trap: the first page load works, but client-side navigation into an article does not re-run push().

How to spot it: Console on the article page: window.adsbygoogle?.loaded. If undefined on the article but defined on the homepage, that template never pushed. With Astro view transitions or Next.js client navigation, also reload the article URL directly — if a hard reload fills but soft navigation does not, the push is not wired to route changes.

6. CSP or iframe sandbox blocks ad rendering on the article template

If the article template uses a stricter Content Security Policy, or wraps content in an <iframe sandbox>, AdSense cannot inject its frame.

How to spot it: DevTools Console on the article page. Look for Refused to load / Refused to frame CSP errors, or iframe sandbox errors mentioning googlesyndication.com or doubleclick.net. Your CSP must allow these in script-src and frame-src.

Shortest path to fix

Step 1: Verify an ad request actually leaves the article page

Open the article, press F12, go to Network, type ads? in the filter (this is Google’s official DevTools check).

  • A request beginning with ads?client = the code ran and asked for an ad. Read its status:
    • 200 but blank slot → ads.txt or content/unit issue, continue to Step 4 and Step 5.
    • 403 → Google refused to serve to this page (account/site block, policy, or unknown unit). Check AdSense → Sites and Policy center.
  • No ads?client request → the script never fired here. Continue to Step 2.

Step 2: Confirm the loader is present on both pages

// Run in the DevTools Console on each page
document.querySelectorAll('script[src*="adsbygoogle"]').length
// Should be 1 on both pages

If it is 0 on the article page, your article template does not include the loader. Move it into a single shared layout component so every page inherits it.

Step 3: Compare <ins> computed dimensions and status

// Run in the Console on each page
Array.from(document.querySelectorAll('ins.adsbygoogle'))
  .map(el => ({ status: el.getAttribute('data-ad-status'), w: el.offsetWidth, h: el.offsetHeight }));

data-ad-status is filled (ad served), unfilled (no ad returned, blank space kept), or unfill-optimized (fill-optimization on, intentionally empty). See the official reference.

HomepageArticleDiagnosis
filled, w/h > 0unfilled, w/h = 0Article CSS is collapsing the slot (cause 2)
filled, w/h > 0undefined, w/h > 0push() never ran in the article template (cause 5)
filled, w/h > 0unfilled, w/h > 0Content thin or wrong ad-unit ID (cause 4 / 6)

Step 4: Confirm push() runs after the slot exists

The script tag must be present and push() must run once per slot, after the <ins> is in the DOM. For SSR/static markup:

<ins class="adsbygoogle" ...></ins>
<script>(adsbygoogle = window.adsbygoogle || []).push({});</script>

For SPA route changes (Next.js, Astro view transitions), re-run push({}) after each navigation, once per newly mounted <ins>. Pushing twice for the same slot logs adsbygoogle.push() error: All ins elements ... already have ads in them. in the Console.

Step 5: Verify ad-unit IDs match

grep -rn "data-ad-slot" src/ | sort -u

Open AdSense → Ads → By ad unit. Every data-ad-slot value above must match an active unit. A typo or a deleted unit yields a 403 or a permanently unfilled slot.

Step 6: Test on a different article

If only one article is affected and others fill, that article is too thin (cause 4). Add ~500 words of substantive, original content.

If every article is affected, it is a template-level issue (causes 1, 2, 3, 5) — fix the shared layout, not the article.

Step 7: Run the in-account troubleshooter

In AdSense, open Help → Troubleshoot → “Ads not showing” (the ad-serving troubleshooter). It scans your account for serving issues — site not added/verified, policy actions, ads.txt problems — that DevTools cannot see from the page alone.

How to confirm it’s fixed

  1. Hard-reload (Cmd/Ctrl+Shift+R) the article with an ad blocker disabled.
  2. Network filter ads? shows a 200 ads?client request.
  3. document.querySelector('ins.adsbygoogle').getAttribute('data-ad-status') returns filled.
  4. Repeat on at least 3 different article URLs, including one reached by client-side navigation (not just a hard load).

When this is not on you

AdSense fill rate fluctuates through the day with advertiser demand. A 10–30% swing is normal, so an occasional blank slot on a healthy page is expected. The threshold for “something is wrong” is “blank consistently across refreshes for hours on the same page,” not “blank on one refresh.” Likewise, ERR_BLOCKED_BY_CLIENT in your own Console means your browser’s ad blocker ate the request — test in a clean profile before assuming a site bug.

Easy to misdiagnose as

People assume “ads not showing on articles” is an AdSense outage or account problem. When the homepage on the same account is serving, the account is fine — the difference is almost always template structure, CSS, the wrong ad-unit ID, or thin content on that page.

Prevention

  • Use one shared <AdSlot> component across templates. No copy-pasted <ins> markup.
  • Pin the AdSense loader in a single root layout that every page inherits.
  • Validate ad-container CSS in CI: every <ins> parent must have non-zero width.
  • Keep total ad area well under ~30% of the viewport per page; over-dense pages serve blank silently as of June 2026.
  • Set a minimum word-count gate (~500 words) for articles you want monetized.
  • After framework upgrades or routing changes, re-verify ads on at least 3 article URLs, including one via soft navigation.

FAQ

  • Ads work on the homepage but every article is blank — is my account banned? No. If any page on the account serves, the account is serving. A site-wide block returns 403 on the homepage too. Article-only blanks are a template/content difference.
  • The Network request returns 200 but the slot is still empty. Why? A 200 with no ad usually means ads.txt is missing or wrong, or the page is too thin/low-value to fill. Verify ads.txt at yourdomain.com/ads.txt lists your publisher ID, then check content depth.
  • Why does fill rate vary? Advertiser demand changes by content, audience, geography, and season. A 10–30% daily swing is normal.
  • Will adding more ad slots improve fill? Only up to a point. Too many slots dilutes each one; 2–3 manual slots per article (optionally plus Auto ads) is the sweet spot for most niches.
  • Do I still need the Google Publisher Toolbar extension? No — it was retired in 2020. Use Chrome DevTools and the in-account ad-serving troubleshooter instead.

Tags: #AdSense #Monetization #Troubleshooting #Fill rate