你已经把 <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-..."> 和 <ins class="adsbygoogle"> 标签都贴上去了。DevTools Network 确认 adsbygoogle.js 返回 200。但刷新再刷新、等了几个小时,广告位还是空白。这是 AdSense 里最典型的”看着对、其实不对”的故障——基本上都能归到 6 种接线问题之一,跟代码本身关系不大。
诊断关键是 AdSense 脚本回写到 <ins> 标签上的 data-ad-status 属性。读懂这个,修复通常 5 分钟。
常见原因
按命中率从高到低。
1. (adsbygoogle = window.adsbygoogle || []).push({}) 没执行
脚本加载了,但激活 slot 的 push({}) 调用要么缺失,要么放在一个永远跑不到的地方(某个没触发的路由切换 hook、被 if 拦了、SSR vs hydration 时丢了)。
怎么判断:DevTools 控制台执行 window.adsbygoogle.loaded。如果是 undefined 或 false,push 就没跑。同时 <ins> 上完全没有 data-ad-status 属性(连 unfilled 都没有)。
2. slot 渲染时宽度为 0
<ins> 元素存在,但它的父容器是 display: none、当前断点宽度 0、或者在没展开的 tab/accordion 里。AdSense 对 0 宽度 slot 静默拒绝,位置就一直空着。
怎么判断:右键 → 检查 <ins> → Computed → width。是 0px 就是这条。常见于会塌掉的 flex 容器、width: max-content 的包裹。
3. 同时有多个 <script async ...adsbygoogle.js> 标签
如果你 layout 把 AdSense 脚本贴了两次(一次在 head 一次在组件里),脚本会加载两次,第二次有时绑不上,slot 半推半就。
怎么判断:控制台 Array.from(document.querySelectorAll('script[src*="adsbygoogle"]')).length。应该是 1。
4. <ins> 标签写错了
常见拼写错误:data-ad-clinet、data-ad-slt、漏 class="adsbygoogle"、漏 style="display:block",或者 React 把你写的 dataAdClient 转换成 camelCase 丢了 kebab-case。
怎么判断:查看源代码(不是 React render tree)。真实 HTML 必须包含 class="adsbygoogle" 和 data-ad-client="ca-pub-..."。
5. 页面达不到 AdSense 内容阈值
某些页面——只有 50 字的”Hello world”占位、只有一堆链接列表没有说明文字的分类页、搜索结果页——内容不够撑起广告。data-ad-status="unfilled" 会出现。
怎么判断:跟同一站上已知正常的文章对比。长文章填、薄页面不填,就是内容阈值问题。
6. 你的 IP 或测试会话被限流
你一直 F5 测广告,AdSense 可能会在当天对你的 IP 限流投放。用手机蜂窝、朋友电脑能看到广告,自己电脑看不到。
怎么判断:手机切到蜂窝(不同 IP)打开页面。那边能投,就是本地被限流。
最短修复路径
第 1 步:读渲染后 <ins> 的 data-ad-status
控制台:
document.querySelectorAll('ins.adsbygoogle').forEach((el, i) =>
console.log(i, el.getAttribute('data-ad-status'), el.offsetWidth));
| 状态 | 宽度 | 含义 |
|---|---|---|
undefined | 任意 | push 没跑(原因 #1 或 #4) |
unfilled | > 0 | push 跑了但拍卖没拿到广告(原因 #5 或 #6) |
unfilled | 0 | 宽度问题(原因 #2) |
filled | > 0 | 正常——看不到就查浏览器广告拦截 |
第 2 步:手动触发 push 验证
控制台:
(window.adsbygoogle = window.adsbygoogle || []).push({});
如果 slot 现在填了之前没填,就是你的 push 代码没跑到。SPA / Next / Astro 项目里,把 push 放在:
<ins class="adsbygoogle" ...></ins>
<script>(adsbygoogle = window.adsbygoogle || []).push({});</script>
紧跟在 <ins> 后面。SPA 路由切换:每次切换都重新 push。
第 3 步:修正标签
按这个模板原样贴,不要改属性名:
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-XXXXXXXXXXXXXXXX"
data-ad-slot="1234567890"
data-ad-format="auto"
data-full-width-responsive="true"></ins>
React / Astro 里用 dangerouslySetInnerHTML,或确保框架保留 kebab-case(Astro 默认保留;React 需要 data-ad-client 形式)。
第 4 步:删除重复的 script 标签
grep -rn "adsbygoogle.js" src/ public/
应该只出现一次(在某个 layout/template 文件里)。重复的删掉。
第 5 步:给 slot 强制最小宽度
.adsbygoogle {
display: block;
min-width: 250px;
min-height: 100px;
}
不要在 display: none 的容器里塞广告。需要隐藏的话用 visibility: hidden。
第 6 步:换个 IP 测
手机蜂窝、朋友的网、VPN。那边能投,AdSense 大概 24 小时会自动给你解封——别再 F5 自己的站测试了。
预防建议
- 用单一的
<AdSlot>组件 / partial 统一渲染。所有 slot 走它,不要复制粘贴。 - AdSense 脚本只在一个地方加载——根 layout 或 document head。
- 加 lint 校验每个
<ins class="adsbygoogle">都有对应的push({})调用。 - 全局样式里给
.adsbygoogle加min-width: 250px。 - 测试时不要反复刷新自己的页面——用手机或别人的浏览器。