Adsterra 300×250 实战:从页面劫持到 iframe、Referer 和 CPM 恢复
记录 Warhounds 接入 Adsterra 300×250 Banner 后遇到的移动端页面跳转、iframe 隔离、Cloudflare 308、Referer 与 CPM 异常,以及最终稳定方案。
最近给 Warhounds 做广告变现实验时,我原本以为接一个 300×250 Banner 只是把 Adsterra 后台的 GET CODE 贴进页面。
结果这个小广告位前后改了好几版,踩到了几个很典型的问题:
- 广告能正常展示,但某个移动端 creative 会直接把当前 Warhounds 页面跳到广告主页面;
- 加 sandbox 后安全了,但 Referer / Origin 又发生变化;
- 把广告执行页放到
ads.warhounds.org后,后台有 impressions,却一度没有 CPM; - Cloudflare Pages 会把
.html自动 308 到无扩展名 URL,导致_headers规则看起来写对了、实际却没命中; - 广告放在文章标题下面虽然曝光高,但手机首屏体验很差。
现在这套方案已经稳定运行了一段时间。这篇只记录真实踩坑和最终做法,不讨论“广告位越多越赚钱”这种泛泛建议。
最开始:直接使用 Adsterra 官方 Banner 代码
最初的 300×250 就是 Adsterra Publisher Dashboard 给出的标准代码,结构类似:
<script>
atOptions = {
'key': 'YOUR_KEY',
'format': 'iframe',
'height': 250,
'width': 300,
'params': {}
};
</script>
<script
src="https://www.highrevenueformat.com/YOUR_KEY/invoke.js"
></script>
这一版最大的优点是简单,而且一开始展示、统计、计费都正常。
问题出在手机端。我实际遇到过某个广告 creative 不是正常新开落地页,而是把 Warhounds 当前顶层页面直接替换成广告主页面。
这就不是普通的“广告有点烦”了,而是会直接破坏网站体验。
还有一个容易混淆的地方:
format: 'iframe'
只是 Adsterra Banner 自己的广告格式,不代表 Publisher 页面已经获得了浏览器 sandbox 隔离。
也就是说,官方代码直接在主页面执行时,invoke.js 本身仍然运行在当前页面上下文里。
第一版保护:给广告再套一层 sandbox iframe
为了阻止第三方广告导航顶层页面,我把结构改成:
Warhounds 文章页
└─ sandbox iframe
└─ 独立广告执行页
└─ Adsterra 官方 Banner
外层 iframe 最终只保留这几个权限:
sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"
允许:
allow-scripts
allow-same-origin
allow-popups
allow-popups-to-escape-sandbox
明确不加:
allow-top-navigation
allow-top-navigation-by-user-activation
allow-modals
allow-downloads
正常广告点击仍然可以打开新 tab / window,但不给广告顶层导航权限。
这里还有一个之前踩过的坑:不要简单去掉 allow-same-origin。
早期我试过只给:
allow-scripts allow-popups allow-popups-to-escape-sandbox
这样 iframe 会进入 opaque origin,后续第三方请求的来源上下文会变得很难看,Referer / 来源识别也更容易出问题。
所以后来保留了 allow-same-origin,同时把广告执行页放到另一个 Origin。
第二版:ads.warhounds.org 跨域隔离
当时的结构是:
https://warhounds.org
↓
https://ads.warhounds.org/adsterra/300x250
↓
Adsterra invoke.js
这样 allow-scripts + allow-same-origin 的同时,广告执行页仍然和主站是不同 Origin,浏览器安全边界更清晰。
同时 iframe 使用:
referrerpolicy="strict-origin-when-cross-origin"
广告执行页里加:
<meta name="referrer" content="origin" />
从安全设计看,这一版是我最满意的。
但是上线后又遇到了两个现实问题。
Cloudflare Pages 的一个坑:.html 会被 308
最初 iframe 地址写的是:
https://ads.warhounds.org/adsterra/300x250.html
Cloudflare Pages 实际会把它 308 到:
https://ads.warhounds.org/adsterra/300x250
而我的 _headers 一开始只匹配了 .html 地址。
结果就是:
- 第一个
.html请求命中了允许 iframe 的规则; - Cloudflare 308 到无扩展名 URL;
- 最终 200 响应重新继承全局
X-Frame-Options: SAMEORIGIN; - 手机端直接显示
ads.warhounds.org拒绝连接。
修复方式很简单:iframe src 和 _headers 都直接使用 Cloudflare 最终 URL,不要依赖中间跳转。
例如:
/adsterra/300x250
这个坑非常隐蔽,因为源码和第一跳响应头看起来都可能是对的,必须检查最终 200 Response Headers。
广告能展示,不代表计费一定正常
跨域版稳定展示后,我又观察到一个异常:
Adsterra 后台已经出现新的 impressions,但这批流量一度是:
Impressions > 0
CPM = $0
Revenue = $0
这时我没有继续加广告位,也没有乱改 key,而是只改一个变量:广告执行页的来源。
把:
ads.warhounds.org
改回:
warhounds.org
最终结构变成:
https://warhounds.org/文章
↓
/adsterra/300x250
↓
Adsterra invoke.js
浏览器里实际抓到的 vendor 请求 Referer 也从:
https://ads.warhounds.org/
变成:
https://warhounds.org/
随后 Adsterra 后台重新开始出现非 0 CPM,后续运行也稳定下来。
这里我不会下结论说“Adsterra 一定不支持子域”。我的样本只是一个真实站点的一次实验,能确定的是:
对 Warhounds 这个 Placement 来说,广告执行 Origin 确实是一个会影响实际 monetization 结果的重要变量。
以后再遇到“广告能显示、后台也有 impression、但 CPM 长时间为 0”,我会第一时间检查实际 Referer 和广告执行 Origin,而不是只盯前端是否渲染成功。
目前 Warhounds 的 300×250 结构
现在文章页使用同源 iframe:
<iframe
src="/adsterra/300x250"
width="300"
height="250"
sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"
referrerpolicy="strict-origin-when-cross-origin"
loading="lazy"
></iframe>
广告执行页继续使用 Dashboard 当前给出的官方 Banner 代码,不去改它内部的:
format: 'iframe'
height: 250
width: 300
params: {}
并保留:
<meta name="referrer" content="origin" />
如果是 Cloudflare Pages,广告执行页额外设置:
X-Robots-Tag: noindex, nofollow
Content-Security-Policy: frame-ancestors https://warhounds.org
因为现在 iframe 与主站同源,所以全站原本的:
X-Frame-Options: SAMEORIGIN
也可以正常工作。
这不是一个完美的安全边界
这里必须单独说明。
当前方案是:
同源 iframe
+ allow-scripts
+ allow-same-origin
它的隔离强度 弱于之前的 ads.warhounds.org 跨 Origin 方案。
所以我把它理解成一个经过实际收入验证的工程折中,而不是“绝对安全”的通用广告沙箱。
另外,我后来在 Adsterra Publisher 条款里还看到一条非常重要的限制:Publisher 未经 Adsterra 事先书面同意,不允许把 Adsterra Ad Tag 放到 iframe 里。
因此这套实现如果要复制到其他站点,应该先检查你当前账户的最新条款,并向广告平台确认是否允许这种结构。技术上能跑,不代表合同上自动允许。
广告位置也改了:不要挡住用户第一答案
除了安全和计费,这次还顺便改了广告位置。
一开始 300×250 是:
文章标题
摘要
更新时间
↓
300×250
↓
正文
桌面端还能接受,手机端就很明显:用户从 Google 进来还没看到攻略内容,先占掉一大块屏幕展示广告。
现在改成:
标题 / 摘要
↓
正文第一小节(大多数文章是 Quick Answer)
↓
300×250
↓
第二小节及后续内容
而且:
- 一篇文章只放 1 个 300×250;
loading="lazy";- 不恢复文章 footer 的第二个相同 Placement;
- Native、728×90、320×50 Sticky 暂时都不加。
因为 Warhounds 同时还在申请 Google AdSense,这个阶段我宁愿广告少一点,也不想为了短期曝光把页面做得像广告站。
如果你也遇到类似问题,可以直接把这段丢给 AI
如果不想自己研究整套过程,直接把下面要求交给 Codex、Claude Code 或其他能改仓库的 Agent:
请把文章页第三方 300×250 Banner 改成单独的同源 sandbox iframe。
目标:
主站文章页
→ /adsterra/300x250
→ 广告平台官方 Banner GET CODE
要求:
1. 主文章页不要直接执行第三方 invoke.js。
2. iframe 使用:
sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"
3. 禁止加入任何 allow-top-navigation*。
4. iframe 使用 referrerpolicy="strict-origin-when-cross-origin" 和 loading="lazy"。
5. 广告执行页设置 <meta name="referrer" content="origin">。
6. 广告执行页内部保持广告平台官方 key、format、width、height、params 和 invoke.js URL 不变。
7. Cloudflare Pages 直接使用最终无扩展名 URL,不要依赖 .html → 308。
8. 一篇文章只保留一个 Placement,位置放在正文第一小节结束后、第二个 H2 前。
9. 检查最终 HTML、Response Headers 和广告 vendor 请求 Referer。
10. 不要顺手增加 Native、Sticky 或其它广告位。
11. 保留 master switch,只有精确 true 才输出广告。
12. 修改前确认广告平台当前条款是否允许 Publisher 把 Ad Tag 放入 iframe。
修改后运行 lint、typecheck、test、production build,并检查最终 dist HTML。
这基本就是这次 Warhounds 实验最后沉淀下来的实现要求。
这次最值得记住的几条经验
最后把这次来回折腾浓缩一下:
- 广告能显示,不代表接入就是正确的。 还要看主页面是否会被劫持、后台有没有 CPM 和 Revenue。
- 平台自己的
format: iframe不等于浏览器 sandbox。 两者不是同一层。 - 没有
allow-same-origin的 sandbox 会变成 opaque origin。 Referer / 来源识别可能随之变化。 - 跨 Origin 更安全,但广告网络不一定按你预期识别来源。 必须看真实后台数据。
- 一次只改一个变量。 这次能发现 Origin 和 CPM 的关联,就是因为没有同时换 key、位置和格式。
- Cloudflare Pages 要检查最终 URL。
.html的 308 足够让一条正确的_headers规则彻底失效。 - Network Referer 比“页面看起来正常”更有价值。 最后要看第三方脚本实际收到什么来源。
- 不要主动刷 impression 或 click。 用自然流量看数据,避免把测试本身变成异常流量。
- 移动端第一屏先给答案,再给广告。 对攻略站尤其重要。
- 广告平台条款优先于技术实现。 如果 iframe 需要书面许可,就先拿许可。
这次最大的感受是,第三方广告其实是一个“运行别人 JavaScript + 还要让统计平台正确识别流量”的系统问题,不只是前端页面里多一段 <script>。
对独立站来说,收益重要,但页面控制权更重要。至少现在 Warhounds 的 300×250 已经从“能展示”变成了“展示、位置、Referer、统计和回滚都可控”。
相关文章
projects
YY 直播团队的开源项目,极力推荐
大家好 今天发现一款由YY直播团队开源的全新的移动端视频动画解决方案 - YYEVA 简介 YYEVA(YY Effect Video Animate)是YY直播团队开源的移动端适配动画解决方案,该方案包含了客户端渲染引擎,设计配套工具等,可以说是很全面,很完善的一套方案。 项目流程图 YYEVA工具链 工作流程 通过 A...
projects
又一个完整的开源商城
大家好,我是阿白今天产品说要整个一套的商城系统,速度要快,最好几天之内搞定…还让人愉快的玩耍吗?作为程序员怎么能不尝试下就放弃呢~要快还要好使,想想,只能去 GitHub 里面找找了。好在上天眷顾,找到了 Mall4j 这个项目。简介Mall4j项目是一个完整的开源的电商系统,采用现阶段流行技术实现
projects
炫酷的路径规划算法可视化项目,不进来看看?
大家好,我是阿白大家如果准备过面试,或者刷过算法题应该多少都有接触过动态规划。在学习中,由于没有可视化的展示算法,只是强行理解,看着看着就懵了。今天推荐一款可视化的动态规划的项目 PathPlanning,可以辅助我们理解动态规划的相关算法,一次性搞定它。简介PathPlanning 项目实现了一些
这篇文章有帮助吗?
感谢反馈。