ads.txt 找不到或延迟:5 类原因 + 排查修复

AdSense 面板报 "Earnings at risk — your ads.txt file is missing"——ads.txt 为什么重要、怎么部署。

AdSense 控制台横幅写着 “Earnings at risk — your ads.txt file is missing”。你加了文件。警告没消。或者 https://yourdomain.com/ads.txt 返回 404,但你确定推送了。ads.txt 规范很简单——根目录一个纯文本文件,列授权 seller——但部署上有 4 个坑能套住大多数独立站。

下面讲 ads.txt 究竟该放哪、怎么验证、以及 AdSense 那个让你修对之后横幅还要挂几天的对账延迟。

常见原因

按命中率从高到低。

1. 文件路径错

ads.txt 必须在 https://yourdomain.com/ads.txt——不是 /public/ads.txt、不是 /assets/ads.txt、不是 /static/ads.txt。爬虫只命中这一个 URL。

怎么判断

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

要看到 HTTP/2 200。其它(404、301、403)都说明路径不对。

2. 框架没把文件 ship 出去

Astro:ads.txtpublic/。Next.js:也是 public/。Vercel:Next 项目放 public/,静态站放根。SvelteKit:static/。放进 src/ 不会被部署。

怎么判断:部署后 curl https://yourdomain.com/ads.txt。404 就是 build 没带它。

3. Content-Type 错或内容被 gzip 成 HTML

某些平台(nginx 配错、CDN 规则不当)会把 .txt 文件返回 Content-Type: text/html,或者把它包在一个 200 状态的 404 HTML 页里。AdSense 看到 HTML,找不到 seller 行,就当文件缺失。

怎么判断

curl -sI "https://yourdomain.com/ads.txt" | grep -i content-type

应该是 Content-Type: text/plain(或 text/plain; charset=utf-8)。如果是 text/html,平台在做改写。

4. publisher ID 错或格式问题

行必须是:

google.com, pub-XXXXXXXXXXXXXXXX, DIRECT, f08c47fec0942fa0

常见错误:尾部空格、复制粘贴带智能引号、文件开头有 BOM、publisher 号错、漏了逗号。

怎么判断

curl -s "https://yourdomain.com/ads.txt" | od -c | head -3

看开头有没有奇怪的字符(BOM 是 357 273 277)。

5. Cloudflare / CDN 缓存返回旧版

你改了但缓存还在返回旧版。AdSense 爬到的还是旧的(缺失)状态。

怎么判断:加 ?nocache=$(date +%s) 绕缓存:curl "https://yourdomain.com/ads.txt?nocache=$(date +%s)"。内容不一样就是 CDN 缓存陈旧。

6. AdSense 还没重新爬

修对后横幅会挂 24-48 小时——AdSense 按自己的节奏重查。

怎么判断curl 验证 ads.txt 正确、修完不到 48 小时,就是等。

最短修复路径

第 1 步:从 AdSense 拿到精确文本

AdSense → Sites → 你的站 → “Get snippet”。复制那一行——别手敲。

应该像:

google.com, pub-XXXXXXXXXXXXXXXX, DIRECT, f08c47fec0942fa0

第 2 步:放到正确路径

框架文件放哪URL
Astropublic/ads.txt/ads.txt
Next.js (pages 或 app)public/ads.txt/ads.txt
SvelteKitstatic/ads.txt/ads.txt
Nuxtstatic/ads.txt/ads.txt
Hugostatic/ads.txt/ads.txt
纯 HTMLwebroot 的 ads.txt/ads.txt

部署,验证。

第 3 步:用 curl 验证

curl -sI "https://yourdomain.com/ads.txt"
# 期望:HTTP/2 200, Content-Type: text/plain

curl -s "https://yourdomain.com/ads.txt"
# 期望:google.com, pub-XXXXX, DIRECT, f08c47fec0942fa0

Content-Typetext/html 或其它,说明平台 / CDN 在改写。加显式规则:

Vercelvercel.json

{
  "headers": [
    { "source": "/ads.txt", "headers": [{ "key": "Content-Type", "value": "text/plain" }] }
  ]
}

Netlify_headers

/ads.txt
  Content-Type: text/plain

Cloudflare Pages — 根目录的 _headers

/ads.txt
  Content-Type: text/plain

第 4 步:清 CDN 缓存

Cloudflare → Caching → Purge → Custom Purge → 输入 https://yourdomain.com/ads.txt

Vercel 通常部署时自动清。

第 5 步:等 24-48 小时 AdSense 重新核对

横幅不会瞬间消。只要 curl https://yourdomain.com/ads.txt 返回正确的纯文本,AdSense 48 小时内会识别。

第 6 步:CI 加校验

# .github/workflows/verify-ads-txt.yml 或 postdeploy 脚本
curl -sf "https://yourdomain.com/ads.txt" | grep -q "pub-$ADSENSE_PUB_ID" || \
  { echo "ads.txt missing or wrong"; exit 1; }

每次部署后跑一次。能瞬间发现回归。

哪些情况可能不是你操作错了

AdSense 按周期重查 ads.txt,不按需。修对后控制台横幅 24-48 小时才消失。别反复重发——等就行。

容易误判的情况

ads.txt 放错目录(或框架 404 掉)——静态站最常见的错误。用 curl 验证,别只看代码库。

预防建议

  • ads.txt 永远放在静态 / public 目录,每次部署自动带上。
  • CI 里加校验:curl -sf yourdomain.com/ads.txt | grep -q pub-$PUB_ID
  • 平台配置里强制 Content-Type: text/plain
  • 改 CDN 设置后再验证一次 ads.txt 仍然正确返回。
  • 接第二家广告网络(Mediavine、Ezoic 等),ads.txt 同步加它们的行。

FAQ

  • 只用 AdSense 也要 ads.txt 吗? 要——Google 对 AdSense 完整收益有要求。
  • ads.txt 能多行吗? 能,每个授权 seller 一行。多家广告网络各自一行。

相关阅读

标签: #AdSense #变现 #排查 #ads.txt