组件配置
组件负责在浏览器里完成挑战、拿到 token。这里说明怎样加载、选择模式、调整样式、处理回调,以及和 CSP、无障碍相关的设置。
加载组件
在页面里引入 https://captcha.moe/widget.js,页面上所有 class="moe-captcha" 的元素会自动渲染成组件。组件放在 form 里时,完成验证后会写入隐藏字段 moe-captcha-response。
<script src="https://captcha.moe/widget.js" async defer></script>
<form method="post" action="/signup">
<div class="moe-captcha"
data-sitekey="{{ sitekey }}"
data-intent="{{ intent_id }}"
data-endpoint="https://captcha.moe"
data-mode="auto"
data-error-callback="onCaptchaError"></div>
<button type="submit">注册</button>
</form>
<script>
function onCaptchaError(code) {
console.warn('验证未完成:', code);
}
</script>组件不写 Cookie、不使用本地存储。滑条模式在访客与组件交互之前不会发出网络请求;无感和隐形模式在渲染后就开始验证。sitekey 和 intent_id 必须由服务端在渲染页面时填入,见快速接入。
页面属性
| 属性 | 取值 | 默认 | 说明 |
|---|---|---|---|
data-sitekey | mc_pub_… | 必填 | 站点的 Site key |
data-intent | UUID | 必填 | 服务端刚创建的 intent_id |
data-endpoint | 网址 | 请填写 | 验证服务地址,托管服务填 https://captcha.moe,自己部署时填你的地址 |
data-mode | auto / interactive / passive / invisible | auto | 交互方式,见下文 |
data-theme | auto / light / dark | auto | auto 跟随系统的深浅色设置 |
data-size | normal / compact | normal | 滑条 normal 最大 340×48、compact 最大 260×40;无感徽标高 36(compact 32),都会随容器缩窄 |
data-brand | hidden | 显示 | 设为 hidden 时隐藏小猫标志和隐形模式的说明文字,见品牌标志 |
data-accent | CSS 颜色 | #b83e65 | 主色,等同于 --mc-accent |
data-radius | 数字(px)或 CSS 长度 | 6(紧凑 5) | 圆角,等同于 --mc-radius |
data-font | inherit 或字体名 | 系统字体 | inherit 表示使用你页面的字体 |
data-lang | 语言代码 | 页面的 lang | 例如 zh-CN、en;不支持的语言回退到英文 |
data-callback | 函数名 | — | 完成验证时调用,参数是 token |
data-expired-callback | 函数名 | — | token 过期时调用 |
data-error-callback | 函数名 | — | 出错时调用,参数是错误码 |
四种模式
四种模式的安全性相同,工作量证明完全一样,区别只在访客看到什么、要不要动手。
| 模式 | 访客看到什么 | 适合 |
|---|---|---|
auto(推荐) | 通常显示滑条;访客开启了「减少动态效果」、强制颜色或使用辅助技术时,自动改为无感徽标。 | 绝大多数表单 |
interactive | 一行滑条,访客拖动(或用键盘)完成验证,计算在拖动期间进行。 | 希望每位访客都明确完成一步操作的场景 |
passive | 不需要任何操作。一行小徽标(高 36px)先显示「验证中…」,完成后显示「已验证」;通常在访客填完表单前就已完成。 | 低风险表单,或不希望增加任何步骤的场景 |
invisible | 平时只有一行「由 captcha.moe 保护」的小字(可以去掉)。只有出错、需要稍后重试或 token 过期时,才在原位置显示徽标和重试按钮。 | 希望表单看起来完全不变的场景 |
可以在在线试用里切换模式看效果。无论哪种模式,服务端都必须调用 /siteverify。
使用隐形模式
- 仍然需要服务端先创建 intent、提交后调用
/siteverify;token 同样写进隐藏字段moe-captcha-response。 - 在
callback触发之前保持提交按钮禁用;收到expired-callback或error-callback时再次禁用。 - 一定要处理
error-callback。组件会在说明文字的位置显示原因和重试按钮;如果那个位置在你的布局里不容易看到,或者你隐藏了品牌,请同时显示你自己的提示。 - 状态变化照样会被读屏软件播报。
moecaptcha.execute(id)会立即开始计算,例如在reset()之后。
<form method="post" action="/signup" id="signup">
<input name="email" type="email" required>
<div class="moe-captcha"
data-sitekey="{{ sitekey }}"
data-intent="{{ intent_id }}"
data-endpoint="https://captcha.moe"
data-mode="invisible"
data-callback="onCaptchaReady"
data-expired-callback="onCaptchaLost"
data-error-callback="onCaptchaLost"></div>
<button type="submit" disabled>注册</button>
</form>
<script>
const submit = document.querySelector('#signup button');
function onCaptchaReady() { submit.disabled = false; }
function onCaptchaLost() { submit.disabled = true; /* 组件会在原位置显示原因和重试 */ }
</script>匹配网站风格
三种方式,从快到细:
- 页面属性:
data-accent、data-radius、data-font能满足大多数网站。 - CSS 变量:写在组件元素上,会传进组件内部,由你自己的样式表控制。
::part():需要更细的调整时,直接改某个部件。
<div class="moe-captcha"
data-sitekey="{{ sitekey }}"
data-intent="{{ intent_id }}"
data-endpoint="https://captcha.moe"
data-mode="passive"
data-accent="#2563eb"
data-radius="12"
data-font="inherit"></div>| 变量 | 浅色默认 | 深色默认 | 用在哪里 |
|---|---|---|---|
--mc-accent | #b83e65 | — | 滑块箭头、重试按钮、焦点 |
--mc-accent-dark | — | #f48caa | 深色主题使用的主色 |
--mc-accent-soft | 主色按 16% 混入背景 | 同左规则 | 滑块、已填充的滑条、徽标底色 |
--mc-surface | #fff9fb | #2d252d | 滑条和徽标的背景 |
--mc-text | #66505c | #eadce3 | 提示文字、状态文字、品牌标志 |
--mc-border | 跟随主色(未设置主色时为 #a86a80) | 跟随深色主色(未设置时为 #a27b8f) | 滑条和徽标的边框 |
--mc-success | 主色加深:主色 85% 混入黑色(默认粉色约 #9c3556) | 主色提亮:主色 85% 混入白色(约 #f6a2bb) | 「已验证」文字和边框 |
--mc-error | #ba1a1a | #ffb4ab | 错误文字和边框 |
--mc-radius | 6px(紧凑 5px) | 同左 | 圆角 |
--mc-font | 系统字体 | 系统字体 | 字体;inherit 表示使用你页面的字体 |
可用的部件:widget(整行)、rail(滑条)、thumb(滑块)、label(文字)、retry(重试按钮)、brand(品牌标志)、note(隐形模式的说明文字)。
只设一个主色就能换掉整个组件的配色:浅色主色、边框和「已验证」的颜色都会跟着它变,除非你单独设置。改了颜色之后,对比度由你负责:--mc-text、--mc-error、--mc-success、--mc-accent 与 --mc-surface 之间至少 4.5:1,--mc-border 与页面背景之间至少 3:1。主色很浅或很深时,跟随它变化的边框和「已验证」颜色可能不够醒目,这时请单独设置 --mc-border 和 --mc-success。组件自带的对比度测试只覆盖默认配色。只为一种主题设置了颜色时,请同时把 data-theme 固定成那种主题。
品牌标志
设置 data-brand="hidden"(JavaScript 渲染时用 brand: false)会隐藏小猫标志,以及隐形模式里「由 captcha.moe 保护」那行字。不需要申请,也不收费。隐藏后,请在你自己的隐私政策里告诉访客:表单使用 captcha.moe 防范机器人,以及浏览器里运行了什么、发送了哪些数据,可以链接到我们的隐私说明。
回调与过期
- token 约 2 分钟后过期。组件会清空隐藏字段、调用
expired-callback。请在回调里禁用提交,并提示访客重新验证。 - 网络长时间没有响应时,组件停止等待并返回
request-timeout;挑战超时返回challenge-expired。组件会显示重试按钮,不会自动循环重试。 - 访客点击重试会继续使用当前 intent;如果 intent 也过期了(5 分钟),需要服务端创建新的 intent,再重新渲染组件。
- 回调只更新页面状态。是否放行由服务端兑换 token 决定,回调里不要直接执行业务。
用 JavaScript 渲染
单页应用里,在脚本地址加上 ?render=explicit,脚本加载完后调用 moecaptcha.render,页面卸载时调用 remove。同一张表单只能挂载一个组件。
<script src="https://captcha.moe/widget.js?render=explicit" async defer></script>
<div id="captcha"></div>
<script>
window.onMoeCaptchaLoad = () => {
const id = moecaptcha.render(document.querySelector('#captcha'), {
sitekey: '{{ sitekey }}',
intent: '{{ intent_id }}',
endpoint: 'https://captcha.moe',
mode: 'passive', // interactive / passive / invisible / auto
theme: 'auto',
accent: '#2563eb', // 可选:brand: false、radius: 12、font: 'inherit'
callback: (token) => { /* 允许提交;token 已写进表单 */ },
'expired-callback': () => { /* 禁用提交,提示重新验证 */ },
'error-callback': (code) => { /* 显示错误,见错误码页面 */ },
});
// moecaptcha.getResponse(id) 未完成时返回空字符串
// moecaptcha.reset(id) 清空结果,用同一个 intent 重新验证
// moecaptcha.execute(id) 立即开始计算(passive / invisible)
// moecaptcha.remove(id) 页面卸载时销毁组件
};
</script>前端框架
React、Vue、SolidJS、Svelte、Angular 和 Expo 可以使用 @captcha-moe/frontend,它负责加载脚本、在配置变化时重新渲染和卸载时销毁,并支持和组件相同的选项:mode(包括 invisible)、theme、size、lang、brand、accent、radius、font。安装命令 npm install @captcha-moe/frontend即将发布,发布前请从仓库的 integrations/frontend 目录安装(需要 Node.js 22.22+ 或 24.15+)。使用它时不要再手动引入 widget.js。
CSP
页面启用了内容安全策略时,需要允许:
script-src https://captcha.moe;
connect-src https://captcha.moe;
worker-src blob:;
img-src 'self' data:;worker-src blob: 让计算在后台线程进行;不允许时组件会回退到主线程,仍然可用但更慢。组件不需要 unsafe-inline 或 unsafe-eval。使用增强采集脚本 /widget-risk.js 时,请在你的隐私说明中告知访问者。
无障碍
滑条支持键盘方向键;验证状态会用文字播报,无感和隐形模式也一样;减少动态效果时停用装饰动画。小猫只是装饰,访客不需要识别任何图片。完整清单见无障碍。