Caputchin
Migration guides

Migrate from hCaptcha

Caputchin uses the same two-part model as hCaptcha, a widget on the page that produces a token, and a server-side check that confirms it, so migrating is mostly a mechanical swap, not a rewrite. The server exchange in particular mirrors the siteverify shape hCaptcha itself follows. This guide gives the before-and-after for each piece.

If you have not yet created a Caputchin account and site key, do create your account first; you will need a public key (cpt_pub_...) for the page and a secret (cpt_sec_...) for your backend, the same split as hCaptcha's site key and secret key.

The mental model is unchanged

Everything you already built around hCaptcha, render a widget, collect a token, POST it to your server, verify it before trusting the request, stays. Only the names and endpoints change.

1. Swap the client snippet

hCaptchaCaputchin
Script<script src="https://js.hcaptcha.com/1/api.js" async defer><script src="https://cdn.jsdelivr.net/npm/@caputchin/widget@3/dist/widget.js">
Element<div class="h-captcha" data-sitekey="..."><caputchin-widget sitekey="cpt_pub_...">
Token field in a formh-captcha-response (auto-injected)caputchin-token (auto-injected)
Reading the token in JShcaptcha.getResponse()the pass event detail.token

Like hCaptcha, the Caputchin widget auto-injects a hidden token field into the form it sits in, so if your form already did a normal POST, you only change the element and the field name your backend reads. See add the widget for the full client setup and the CDN vs npm choice.

2. Swap the server verify

This is where the two are closest, the request and response shapes line up almost field for field.

hCaptchaCaputchin
EndpointPOST https://api.hcaptcha.com/siteverifyPOST https://caputchin.com/api/v1/siteverify
Request fieldssecret, responsesecret, response (identical)
Response{ success, challenge_ts, hostname, "error-codes", score? }{ success, challenge_ts, hostname, error-codes, score? }
Trust ruleact only if success === trueact only if success === true (identical)

One format note: hCaptcha's verify endpoint expects application/x-www-form-urlencoded, while Caputchin's accepts JSON. If your existing code sent form-encoded fields, switch the body to JSON ({"secret":"...","response":"..."}) with Content-Type: application/json. The fields themselves are unchanged. The full request/response reference is on verify a token on your backend; framework snippets are in backend examples.

3. Drop the score, if you used hCaptcha Enterprise

hCaptcha Enterprise returns a risk score (where a higher number means more risk) and asks you to pick a threshold. Caputchin does not work that way: success is an authoritative pass/fail, because the verification was actually cleared (a proof-of-work check, or a game round re-derived on the server), not a risk estimate.

If your code had if (data.score < 0.7), replace it with if (data.success). Caputchin's score field is unrelated: it exists only for game rounds and is the game's score (informational, for your own leaderboards), never a risk or bot-likelihood, so do not gate access on it. (Note the direction is also opposite, hCaptcha's score rises with risk; Caputchin's rises with game performance.)

What carries over, and what gets better

  • The privacy posture you chose hCaptcha for, kept. Caputchin collects no IP, User-Agent, fingerprint, or behavioral telemetry; the protocol has nowhere to put a visitor identifier, so there is none to leak or sell. See the philosophy.
  • An optional game. Instead of an image-selection challenge, you can turn verification into a short game your visitors actually play, and it is the part that holds up against AI solvers. See add a game.
  • A strict CSP stays strict. Caputchin runs under a tight Content-Security-Policy; you allow a few origins rather than loosen your policy. See how Caputchin sandboxes games.

Gotchas

  • Two keys, two homes. The public key (cpt_pub_...) goes on the page; the secret (cpt_sec_...) stays server-side only, exactly the hCaptcha discipline. Do not ship the secret to the browser.
  • The token is single-use. Like hCaptcha, a token verifies once. Do not cache or replay it.
  • Change the field name your backend reads. The hidden field is caputchin-token, not h-captcha-response, a common one-line miss.
  • Body format. Send the verify request as JSON, not form-encoded.

See also

On this page