Skip to content

从 reCAPTCHA 迁移到 Cap

Google 正在把 reCAPTCHA 迁入 Google Cloud,并把 Classic 密钥自动迁移到带账单的项目上。也就是说,无论如何你都得调整现有的集成。好消息是:正好借这个机会告别 Google 那套基于追踪的 CAPTCHA(人机验证),换成更快、更私密还免费的方案。

真正关键的那部分,Cap 可以直接替换;其余几乎每一处,都是升级。

为什么团队纷纷换用 Cap

  • Turnstile 级别的检测,却不依赖第三方。 Cap 将工作量证明与 instrumentation 质询(浏览器环境检测)结合,后者正是 YouTube 和 Twitter/X 在超大规模下使用的浏览器验证技术。它与 Cloudflare Turnstile 处于同一检测梯队,同时保持完全自托管。
  • 经过大规模验证。2026 年第一季度就解决了约 10 亿次质询(据 JSDelivr 统计),并被 AdGuardBunny.net 等团队用于生产环境。这不是一个实验品。
  • 体积不到十分之一,而且是隐形的。 Cap 的验证组件 gzip 后约 21 KB,而 reCAPTCHA 的客户端有 200 到 600 KB,通常能缩小 10 倍以上。默认质询在后台 2 到 3 秒内解完,没有红绿灯谜题,用户不需要点任何东西。
  • 真正免费,不计量。 不需要 Google Cloud 项目,不需要绑定账单账户,没有按评估收费。一个 Docker 容器加一个 Valkey 实例,一台 5 美元的 VPS 就能承载大多数负载。
  • 默认私密。 reCAPTCHA 会从 google.com 加载脚本并把用户信号发送给 Google。Cap 不向任何地方发送数据,没有任何第三方内容触碰你的页面。
  • 控制权在你手里。 reCAPTCHA v3 会悄悄惩罚使用 VPN、Tor 和隐私浏览器的用户,且投诉无门。用 Cap,难度由你设定,每个真实用户永远有一条走得通的路。
  • 永远开源。 Apache 2.0。可审计、可分叉、可部署。没有哪家供应商能单方面更改条款。

完整分析见 Cap vs reCAPTCHA

reCAPTCHA 正在发生什么变化

想知道迁移邮件为什么现在纷纷到来,背景如下:

  • 旧版 reCAPTCHA 管理控制台已无法创建新密钥。
  • 现有的 reCAPTCHA Classic 密钥正被自动迁移到 Google Cloud 项目中,Google 从 2025 年底一直执行到 2026 年。
  • 迁移完成后,密钥的 API 访问将绑定到某个 Google Cloud 项目。超出每月 10,000 次评估的免费额度后,你必须在该项目上启用计费。

现在继续用 reCAPTCHA,意味着一个 Google Cloud 项目、一个登记在案的账单账户和按量计费的评估。而迁移到 Cap,这些统统不需要,节奏还完全由你掌控。

迁移过程

Cap 的 /siteverify 端点刻意仿照了 reCAPTCHA 的请求形态,因此服务端几乎可以直接替换。验证组件的替换是一比一换标签。总共三步,切换期间还可以两者并行运行。

1. 部署一个 Cap 实例

按照快速上手用 Docker 运行 Cap Standalone 模式。在控制台中创建站点密钥,记下 site key 和对应的 secret key。保持 instrumentation 质询开启(默认即开启)以获得最强的机器人防护。

2. 替换客户端验证组件

把 reCAPTCHA 的脚本和元素替换为 Cap 的验证组件。

替换前:

html
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<div class="g-recaptcha" data-sitekey="<your-recaptcha-site-key>"></div>

替换后:

html
<script src="https://cdn.jsdelivr.net/npm/cap-widget"></script>
<cap-widget data-cap-api-endpoint="https://<your-instance>/<site-key>/"></cap-widget>

如果你的 reCAPTCHA 组件原本放在 <form> 里,令牌处理方式可以照搬:reCAPTCHA 会自动注入 g-recaptcha-response 字段,Cap 则在提交时自动注入 cap-token 字段。如果不在表单内,监听 solve 事件即可:

js
document.querySelector("cap-widget").addEventListener("solve", (e) => {
  const token = e.detail.token;
});

3. 替换服务端验证

reCAPTCHA 的验证是把 secretresponse POST 到 Google 的固定 URL。Cap 接收同样的两个参数,只是 POST 到你自己的实例:

替换前:

js
const { success } = await (
  await fetch("https://www.google.com/recaptcha/api/siteverify", {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({ secret: RECAPTCHA_SECRET, response: token }),
  })
).json();

替换后:

js
const { success } = await (
  await fetch("https://<your-instance>/<site-key>/siteverify", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ secret: CAP_SECRET, response: token }),
  })
).json();

服务端读取的令牌字段名也变了:从提交的表单中取 cap-token(或你在 solve 事件中捕获的值),而不是 g-recaptcha-response

哪些兼容,哪些不兼容

我们更希望你在了解全部差异后再迁移,而不是在生产环境里遇到意外。兼容性是真实的,但并非逐字节一致:

reCAPTCHACap
请求参数secretresponse,可选 remoteipsecretresponseremoteip 会被忽略)
端点固定的 google.com URL你自己的 /<site-key>/siteverify
成功字段success(布尔值)success(布尔值)
错误报告error-codes(数组)error(字符串)
额外字段challenge_tshostnamescore(v3)

实际情况是:

  • 只检查 response.success 的代码,换掉 URL 和密钥后即可工作。这是最常见的情况,只是一行改动。
  • 检查 error-codeschallenge_tshostname 或 v3 score 的代码需要更新。Cap 是一个验证系统,不是行为风险评分,所以这些字段不存在。
  • 如果你的后端 SDK 把 Google 的验证 URL 写死了,换成一个允许自定义端点的 SDK,或者直接调用 /siteverify,总共就两个参数。

零停机迁移

你完全不必"一键切换然后祈祷"。把 Cap 挂载到一个单独的元素上,让后端在过渡期同时接受有效的 cap-token 或有效的 g-recaptcha-response。在日志里观察 Cap 的验证通过率,等数据看起来健康了,再删掉 reCAPTCHA 的脚本、元素和服务端调用。大多数团队一个下午就能完成切换。

另请参阅