Client SDK support
人机验证 exposes one challenge and proof protocol to every supported client:
| Client | client_type |
|---|---|
| Web | web |
| iOS | ios |
| Android | android |
| HarmonyOS NEXT | harmonyos |
| WeChat Mini Program | wechat_miniprogram |
| Alipay Mini Program | alipay_miniprogram |
| Douyin Mini Program | douyin_miniprogram |
Create a separate client application for each deployable client, with an active
default policy for its application, environment and client type. Business actions
such as register, login and password_login inherit this policy until an
explicit scene rule is configured; pre-creating each action is unnecessary.
Explicitly disabled scenes remain denied. Inheritance preserves the requested
action in challenges and proofs, so a registration proof cannot authorize login.
Creating or
rotating credentials issues the Public Key and Server Key atomically as one
pair. A proof is bound to its business application, client application, key
pair, environment, scene, and client type. A Server Key from another pair is
rejected even when it belongs to the same merchant and business application.
Use one stable client identifier per deployable client: a short internal code for Web, Bundle ID for iOS/HarmonyOS, package name for Android, and AppID for a mini-program. Native and mini-program production pairs accept exactly that one identifier. Web pairs may allow several exact HTTPS origins when those origins are deployments of the same logical Web client.
Client authorization policy
Test keys (environment=test) are development-only. They bypass Web Origin and
native application-identifier checks, so localhost, 127.0.0.1, and other
local development clients do not need an allowlist. This bypass never disables
key-pair binding: a proof created with Public Key A can only be consumed by
Server Key A from the same pair.
Legacy unpaired test keys remain usable for local migration. Legacy unpaired live keys fail closed and must be rotated from the client-key screen before a production rollout. The rotation returns both plaintext keys once. The previous active pair enters a 24-hour retirement window and is then rejected automatically; manual revocation ends that window immediately.
Live keys (environment=live) fail closed:
- Web requests must include an
Originthat exactly matches one of the Public Key's configured HTTPS origins. An empty origin allowlist is not authorized. - iOS, Android, HarmonyOS, and mini-program requests must send
client_id. The value must exactly match one of the Public Key's configured client IDs. Use the iOS Bundle ID, Android package name, HarmonyOS bundle name, or mini-program AppID. An empty client-ID allowlist is not authorized. - A missing, malformed, or mismatched identity receives
403 Forbidden.
The public client_id comparison prevents accidental cross-application use but
is not device attestation: a modified client can copy a declared identifier.
High-risk native applications should additionally validate Apple App Attest,
Google Play Integrity, or the equivalent platform attestation on their backend
before accepting the captcha proof.
Flutter
All client SDKs expose frontend presentation settings. See client configuration for defaults, platform-specific names, UI binding, callbacks and migration. Appearance never replaces server risk policy.
Flutter Android/iOS integrations can use sdks/flutter.
The package embeds the Web UI in a system WebView and automatically sends the
native android/ios type and package/Bundle ID. It exposes a cancellable dialog
and typed proof, rather than requiring the application to implement puzzle UI.
Each platform still needs its own matching key pair. Flutter Web uses the Web SDK.
Language negotiation
Scenes may use auto or lock one BCP 47 locale. auto reads the client's
X-Roze-Captcha-Language header; the Web SDK sends the normalized browser
language automatically. Applications may override it with language:
RozeCaptcha.init({
container: '#pink-captcha',
captchaId: 'your_public_key',
language: 'pt-BR'
})
Supported policies are zh-CN, zh-TW, en, es, pt-BR, fr, de,
ja, ko, ru, ar, hi, id, tr, vi, th, it, nl, pl,
uk, fa, he, ms, and fil. Common regional variants are normalized;
unsupported values fall back to English. Arabic, Persian, and Hebrew render
RTL while the slider gesture remains left-to-right. Mini-program and native
clients should send the same language header and localize stable error states
with their native resource system.
Public client flow
Clients use the public key only. These examples use the public gateway prefix
/api/captcha; the generated internal service routes use /api/v1/captcha.
Do not confuse the two when configuring a gateway or direct service deployment.
GET /api/captcha/configPOST /api/captcha/challenge- Render the returned OneTap, slide, ordered-click, category-grid, rotation, IconCrush, Gobang, spatial, dynamic-SVG, or voice challenge.
POST /api/captcha/challenge/complete- Send the returned proof to the merchant backend.
The completion response keeps the four proof fields and also returns:
duration_ms: measured interaction duration from the client track.speed_percentile: percentage of successful users in the same challenge type whose completion time was slower.sample_count: successful samples used for the displayed percentile.
Speed ranking uses a Redis-backed, daily, bounded sample set per challenge type. It contains at most 50,000 recent successful samples, and ranking collection fails open so an auxiliary statistics failure never invalidates a successfully issued proof.
The challenge response retains background_svg, puzzle_svg, and
click_icon_svgs for Web renderers. Native and mini-program renderers should
prefer background_image, puzzle_image, and click_icon_images. These are
image data URLs when populated; inspect the MIME type rather than assuming
every field is PNG. Some modes/releases do not populate every image field.
Verify the selected mode against the actual SDK and deployed response before
promising native UI support; do not treat protocol support as a complete UI.
All renderers submit coordinates in the challenge coordinate system described
by width and height. Scale displayed pointer coordinates back to that
coordinate system before completing a challenge.
Single-file Web SDK
Web and H5 use the same client_type=web SDK. It emits structured lifecycle
events for RUM, supports bounded configuration retries and request timeouts,
and can force the accessible slider flow. See docs/web-h5-integration.md for
the compatibility matrix and production example.
Build sdks/web/pink.js with:
npm run build:sdk
The output is an IIFE bundle that exposes window.RozeCaptcha. It includes its
Vue runtime, widget styles, slide interaction, ordered-click interaction,
category-grid, rotation, reasoning, dynamic-SVG, voice, adaptive, and invisible
interactions, and
animations; no separate CSS or npm dependency is required by the consumer.
Web integrations can select product: 'popup' | 'float' | 'bind' | 'invisible'.
For bind, pass bindTrigger as an existing button selector or element. Invisible
mode performs the low-risk OneTap flow without opening UI and displays a challenge
only after risk escalation. offlineBypass is deliberately false by default;
enabling it reports the captcha as not required when configuration networking fails,
so the business backend must explicitly apply its reviewed fail-open policy.
<div id="pink-captcha"></div>
<script src="/sdk/pink.js"></script>
<script>
const captcha = RozeCaptcha.init({
container: '#pink-captcha',
apiBase: '/api/captcha',
captchaId: 'your_public_key',
scene: 'login',
onSuccess(proof) {
// Send the proof fields with the protected business request.
}
})
</script>
The full npm run build:web command copies this file into the platform and
merchant distributions, where Nginx serves it as /sdk/pink.js.
Proof and server verification
Every platform returns the same proof:
{
"lot_number": "...",
"captcha_output": "...",
"pass_token": "...",
"gen_time": "..."
}
Only the merchant backend may call POST /api/captcha/verify. It supplies
the Server Key, the same scene and client_type, a stable idempotency key,
and the proof. The service atomically consumes stored proof state, then checks
the embedded bindings and signature before authorizing the request. A rejected
binding can therefore also invalidate that proof; do not retry it with another
key pair. Proofs are short-lived and single-use.
Mini-program transport
sdks/miniprogram contains working request adapters for wx.request,
my.request, and tt.request. UI components can share these adapters while
using platform-native templates and animation.
For a deployment exposed below the required pink prefix, configure:
const baseUrl = 'https://captcha.example/pink'
Pass the platform application identifier when creating the client:
const client = createWechatCaptchaClient({
baseUrl,
publicKey,
scene: 'login',
clientId: 'wx1234567890'
})
The public host and image/request host must be configured as legal HTTPS domains in each mini-program console. Production clients must not use a LAN IP or disable domain validation.
Native transport
iOS, Android, and HarmonyOS source SDKs are available under sdks/ios,
sdks/android, and sdks/harmonyos. Download archives are published below
/sdk/native/ by npm run package:native-sdks. They use each platform's
native networking stack and expose strongly typed config, challenge, track,
result, and proof models. Applications render the PNG data URLs with native
views; a controlled WebView remains an optional integration strategy.
Every live request supplies its configured Bundle ID or package name as
client_id. The client must never contain a Server Key. Native clients do not
rely on a Web Origin; Web scenes continue to enforce their configured exact
Origin list.
Exact artifact names, versions, download paths, maturity levels, and release
checks are listed in sdk-downloads.md.