组件配置

组件负责在浏览器里完成挑战、拿到 token。这里说明怎样加载、选择模式、调整样式、处理回调,以及和 CSP、无障碍相关的设置。

加载组件

在页面里引入 https://captcha.moe/widget.js,页面上所有 class="moe-captcha" 的元素会自动渲染成组件。组件放在 form 里时,完成验证后会写入隐藏字段 moe-captcha-response

HTML
<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-sitekeymc_pub_…必填站点的 Site key
data-intentUUID必填服务端刚创建的 intent_id
data-endpoint网址请填写验证服务地址,托管服务填 https://captcha.moe,自己部署时填你的地址
data-modeauto / interactive / passive / invisibleauto交互方式,见下文
data-themeauto / light / darkautoauto 跟随系统的深浅色设置
data-sizenormal / compactnormal滑条 normal 最大 340×48、compact 最大 260×40;无感徽标高 36(compact 32),都会随容器缩窄
data-brandhidden显示设为 hidden 时隐藏小猫标志和隐形模式的说明文字,见品牌标志
data-accentCSS 颜色#b83e65主色,等同于 --mc-accent
data-radius数字(px)或 CSS 长度6(紧凑 5)圆角,等同于 --mc-radius
data-fontinherit 或字体名系统字体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() 之后。
HTML
<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>

匹配网站风格

三种方式,从快到细:

  1. 页面属性data-accentdata-radiusdata-font 能满足大多数网站。
  2. CSS 变量:写在组件元素上,会传进组件内部,由你自己的样式表控制。
  3. ::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-radius6px(紧凑 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。同一张表单只能挂载一个组件。

JavaScript
<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)、themesizelangbrandaccentradiusfont。安装命令 npm install @captcha-moe/frontend即将发布,发布前请从仓库的 integrations/frontend 目录安装(需要 Node.js 22.22+ 或 24.15+)。使用它时不要再手动引入 widget.js。

CSP

页面启用了内容安全策略时,需要允许:

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 时,请在你的隐私说明中告知访问者。

无障碍

滑条支持键盘方向键;验证状态会用文字播报,无感和隐形模式也一样;减少动态效果时停用装饰动画。小猫只是装饰,访客不需要识别任何图片。完整清单见无障碍