Security
A site key's Security page decides how hard the challenge is and which requests are allowed to reach it. The defaults are a sensible middle; this page is about when to move off them, and which way.
Start here
Most sites should leave the defaults alone. Reach for the knobs below when you have a reason:
- You are under active abuse, or the form is high-value (signups, payments, password reset): turn protection up. Raise Difficulty, raise Obfuscation level, and turn on Block automated browsers. You trade a little visitor compute and some server CPU for a much higher wall.
- Speed and conversion matter most, and the risk is low (a newsletter box on a marketing page): keep protection light. Leave Difficulty low and Challenges per request at 1 so the challenge is feather-light on a cheap phone.
The rest of this page is each knob and which way to turn it.
Require a game
The strongest control here is requiring a visitor to play a game to pass, not just clear the quiet background check. Turn on Require a game to verify, here on the Security page, and every visitor must clear one of the games registered on this key. The server picks which game each visitor gets, so it cannot be skipped or swapped.
You register the games a key may use, and that is also where the gate explains itself in full, on the key's Games and the game gate page. You cannot turn the gate on until at least one game is registered. Leaving it off is the less secure choice: the key can be passed without playing a game.
Proof of work: Difficulty and Challenges per request
Proof of work makes the browser solve a small puzzle so that abuse at scale gets expensive (see proof of work).
- Difficulty (1 to 8) sets how hard each puzzle is. Higher costs an attacker more, but also costs the visitor's device more, which low-end phones feel at the top of the range. Start at the default and raise it only if you actually see abuse.
- Challenges per request (1 to 500) asks for several solves at once, multiplying the cost. Leave it at 1 unless you have a specific reason to pile on more.
The browser solves these puzzles in a Web Worker, so your page's Content-Security-Policy must allow blob: for workers (worker-src blob:); this one is required. Allowing 'wasm-unsafe-eval' in script-src additionally lets the solver run as fast WebAssembly, but that is optional: without it the solver falls back to a slower pure-JavaScript implementation inside the same Worker and verification still works. See game sandboxing for the full host-page policy.
Instrumentation: Obfuscation level and Block automated browsers
Instrumentation runs a small program in the visitor's browser to check that a real browser, not a script, solved the challenge (see instrumentation). It is on by default and is the only layer that tells a real browser apart from an automated one.
- Instrumentation can be turned off per key. Leave it on for almost every site. Turn it off only if the page embedding your widget runs a Content-Security-Policy that cannot allow
'unsafe-eval'(the instrumentation program needs it, see below). With it off, the key can no longer detect automated browsers, though proof of work and any required game still run, and the two settings below stop applying. - Obfuscation level (1 to 10) is how hard the in-browser program is to reverse-engineer. Higher is stronger but uses more server CPU. The default is right for most sites; raise it if you are a frequent, targeted attacker's mark.
- Block automated browsers rejects detected headless and WebDriver clients outright. Turn it on if no legitimate automation ever touches your form. Leave it off if you expect legitimate bots (your own monitoring, partner integrations, accessibility tools), because it will block those too.
Content-Security-Policy
The instrumentation program runs eval in the visitor's browser, so the page that embeds your widget must allow 'unsafe-eval' in its script-src. This is the one hard CSP requirement and it has no fallback: if 'unsafe-eval' is blocked, verification times out and the browser console shows [cap] Instrumentation failed. You have two choices: allow 'unsafe-eval' on the pages that host the widget, or turn Instrumentation off (above) to remove the requirement. The full list of what a host page's CSP needs is on game sandboxing.
Required headers
You can require that every request carry a specific header. Most sites do not need this; it is useful when your own client always sends a header you can gate on, as a cheap extra filter.
What you cannot require are the headers Caputchin strips for privacy before a request ever reaches verification. They identify the visitor, and Caputchin's posture is to not collect per-visitor data, so it drops them at the platform boundary:
| Stripped header | Why it is dropped |
|---|---|
cf-connecting-ip | The visitor's IP, set by Cloudflare. Never crosses the boundary, so Caputchin neither stores it nor checks against it. |
x-forwarded-for | The visitor's IP as seen through proxies. Same reason. |
x-real-ip | The visitor's IP from upstream proxies. Same reason. |
user-agent | The visitor's User-Agent string, which identifies their browser and device. |
sec-ch-ua* (every Sec-CH-UA client hint: sec-ch-ua, sec-ch-ua-platform, sec-ch-ua-mobile, and the rest) | The structured form of the User-Agent. Same privacy boundary. |
Requiring one of these would block every request, because it never arrives, so the platform rejects that configuration rather than let you brick the key.
Rate limit and CORS origins
- Max requests per second caps how fast the key will accept requests. Raise it if you are genuinely high-traffic; lower it to throttle a key that is being hammered.
- CORS origins is your origin allowlist, enforced server-side before the puzzle even runs. Leave it empty while you test from
localhost; before you go live, add your real origins so only your own site can use the key.
See also
- Games and the game gate to register games and require one to verify.
- Site keys for the rest of a key.
- Statistics and sessions to see whether your settings are stopping the right traffic.