Your homepage shows AdSense ads fine. You click into an article — blank slots. The same ad unit IDs, the same domain, the same approved AdSense account. This is the “different template” failure mode and it’s almost never an AdSense bug. It’s something structurally different between your two templates: a CSS rule, a missing script tag, a layout the article view collapses to zero, or content thinness that fires on individual articles but not the homepage.
The diagnostic key is comparing the two templates side-by-side in DevTools rather than re-reading your AdSense settings.
Common causes
Ordered by hit rate, highest first.
1. AdSense script loads on homepage but not article template
A common scenario: you added the AdSense script to your homepage layout but the article uses a different layout that doesn’t include it. The article’s <ins> tag is there but the script never executed.
How to spot it: DevTools Network → on an article page, filter by adsbygoogle.js. If 0 results, the script isn’t loading.
2. Article template wraps the ad 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 isn’t open. Homepage uses a different parent so the slot renders fine there.
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 homepage’s is correctly configured
You used different data-ad-slot values per template. The homepage’s was set up correctly in AdSense; the article’s value points to a slot that was deleted or never created.
How to spot it:
grep -rn "data-ad-slot" src/
Compare the values to AdSense → Ads → By ad unit. Article’s must match an existing approved unit.
4. Article content too thin to host ads
AdSense has content policies that restrict serving on pages with little content. Homepages typically have aggregated content (latest posts, hero text, categories). A very short article page may individually fall below the threshold.
How to spot it: Word count under 300 + minimal images/structure = likely too thin. AdSense will set data-ad-status="unfilled" on individual articles while serving the homepage.
5. Article template lazy-loads AdSense after slot renders
If your framework hydrates the article asynchronously and the AdSense script loads after the <ins> tag is already in the DOM but never gets pushed to, slots stay blank.
How to spot it: Console: window.adsbygoogle?.loaded. On article page if undefined, the push() never fired. On homepage if it works, that template has the push at the right time.
6. CSP / iframe sandbox blocks ad rendering on article template
If your article template uses a stricter Content Security Policy or wraps content in an <iframe sandbox>, AdSense can’t render into it.
How to spot it: DevTools Console on article page. Look for “Refused to load” or “iframe sandbox” errors mentioning googlesyndication.
Shortest path to fix
Step 1: Verify the script loads on both pages
// Run in DevTools console on each page
document.querySelectorAll('script[src*="adsbygoogle"]').length
// Should be 1 on both pages
If 0 on the article page, your article template doesn’t include the script tag. Move it to a shared layout component.
Step 2: Compare <ins> tag computed dimensions
// Run on each page
Array.from(document.querySelectorAll('ins.adsbygoogle'))
.map(el => ({ status: el.getAttribute('data-ad-status'), w: el.offsetWidth, h: el.offsetHeight }));
| Homepage | Article | Diagnosis |
|---|---|---|
filled, w/h > 0 | unfilled, w/h = 0 | Article CSS is collapsing the slot |
filled, w/h > 0 | undefined, w/h > 0 | push() never ran in article template |
filled, w/h > 0 | unfilled, w/h > 0 | Content thin or different ad unit ID |
Step 3: Check that the AdSense push() runs on article template
In the article template, the script tag must be present and push() must execute. For SSR frameworks:
<ins class="adsbygoogle" ...></ins>
<script>(adsbygoogle = window.adsbygoogle || []).push({});</script>
For SPA route changes (Next, Astro view-transitions, etc.), re-run push() on route change.
Step 4: Verify ad unit IDs match
grep -rn "data-ad-slot" src/ | sort -u
Open AdSense → Ads → By ad unit. Every grep result should match an active slot.
Step 5: Test on a different article
If only one article is affected and others work fine, the article is too thin (cause #4). Add ~500 words of substantive content.
If all articles are affected, it’s a template-level issue (causes #1, #2, #3, #5).
Step 6: Run Ad Inspector
Install Google’s Ad Inspector Chrome extension. Open the article. Inspector shows: “no ad served because [reason].” The reason text usually points exactly at the cause.
When this is not on you
AdSense fill rate fluctuates 10-30% over the day. Some blank slots are normal even on healthy pages. The diagnostic threshold is “blank consistently across refreshes for hours,” not “blank on one refresh.”
Easy to misdiagnose as
People often assume “ads not showing on articles” is an AdSense bug. It’s almost always a template / structure / content issue specific to that template.
Prevention
- Use the same
<AdSlot>component across templates. No copy-paste of<ins>markup. - Pin the AdSense script in one root layout shared by every page.
- Validate ad container CSS dimensions in CI: every
<ins>parent must have non-zero width. - Set a minimum word count requirement for articles you want monetized (~500 words).
- After framework upgrades or routing changes, re-verify ads serve on at least 3 article URLs.
FAQ
- Why does fill rate vary? Advertiser demand fluctuates by content, audience, geography, season — 10-30% variability is normal.
- Will more ads improve fill? Up to a point — too many slots dilutes each. 2-3 slots per article is the sweet spot for most niches.