Migrate from reCAPTCHA
Caputchin's /siteverify is intentionally shape-compatible with Google's reCAPTCHA verify endpoint. The browser surface differs (custom element instead of a script + global), but your server-side code mostly keeps working as-is.
This guide assumes you already have Caputchin site keys. See quickstart if not.
Field mapping
Browser HTML
| reCAPTCHA | Caputchin |
|---|---|
<script src="https://www.google.com/recaptcha/api.js"></script> |
<script src="https://cdn.jsdelivr.net/npm/@caputchin/widget@1/dist/widget.js"></script> |
<div class="g-recaptcha" data-sitekey="..."></div> |
<caputchin-widget sitekey="cpt_pub_..."></caputchin-widget> |
Form field g-recaptcha-response |
Form field caputchin-token |
data-callback="onSubmit" |
addEventListener("complete", onSubmit) |
For invisible reCAPTCHA v2, the equivalent is the Caputchin invisible default — just omit the game attribute. For v3 (no challenge UI), use the same invisible default.
Backend /siteverify
| reCAPTCHA request body | Caputchin request body |
|---|---|
secret=YOUR_SECRET |
secret: "cpt_sec_..." |
response=USER_TOKEN |
response: "<caputchin-token>" |
remoteip=USER_IP (optional) |
not used — Caputchin does not collect IPs |
| reCAPTCHA response | Caputchin response |
|---|---|
success: true | false |
success: true | false (same) |
error-codes: [] |
error-codes: [] (same) |
score: 0.0–1.0 (v3) |
not provided — Caputchin treats game score as metadata, not a trust signal |
action: "..." (v3) |
not provided — see principles below |
challenge_ts |
not provided |
hostname |
not provided |
The shape compatibility means a server using recaptcha.verify(token) can usually be redirected to Caputchin by changing only the URL and only the secret.
Step-by-step swap
1. Replace the script tag
Remove the reCAPTCHA <script> and replace <div class="g-recaptcha"> with <caputchin-widget>. If your form uses g-recaptcha-response, rename the field accessor in your backend to caputchin-token.
2. Update the secret
Replace your reCAPTCHA secret in your environment with the Caputchin secret (cpt_sec_...). Same env var name is fine.
3. Update the verify URL
Change the verify endpoint:
-const VERIFY_URL = "https://www.google.com/recaptcha/api/siteverify";
+const VERIFY_URL = "https://api.caputchin.com/api/v1/siteverify";
4. Drop reCAPTCHA-specific assertions
If your verifier reads score, action, hostname, or challenge_ts, remove those checks. Caputchin gives you success + error-codes and that is the entire trust signal. The wrapped token also carries game_id, score, and duration_ms, but those are client-claimed metadata, not security signals — do not gate access on them.
5. Test in staging
Submit the form with a real challenge and inspect the verdict. The shape should be familiar:
{
"success": true,
"platform": { "game_id": "bubble-pop", "score": 0.847, "duration_ms": 4200 }
}
If anything is wrong, the troubleshooting guide maps every error code.
Principles {#principles}
Two things are intentionally different from reCAPTCHA:
| Difference | Why |
|---|---|
| No risk score | Caputchin makes no behavioral risk claims. Cap's proof-of-work is the entire humanity signal. |
| No IP / user-agent / fingerprint collection | Caputchin is structurally private — there is no remoteip field because the platform does not store user IPs. |
The full positioning is in privacy.
Rollback plan
If you need to roll back, keep both the old and new scripts side-by-side for one deploy. The form field name is the only meaningful collision — rename one of them temporarily, then swap when you are confident.