Testing
Test Cloudflare Turnstile in CI With Testing Sitekeys
Test your own Turnstile forms in CI with Cloudflare's testing sitekeys and secret keys: always pass, always fail, forced challenges, and spent tokens.
3 min readPublished Updated
If Turnstile protects forms on your own site, your end-to-end tests have to get past it too. You do not need a solving service for that. Cloudflare publishes testing sitekeys and secret keys that make the widget and the server-side check behave predictably, so tests can cover success and failure without depending on a real challenge. This guide lists them and shows how to wire them into a test setup.
These keys are Cloudflare’s, documented on its testing page. They are the right tool whenever you own the site.
The testing sitekeys (client side)
Put one of these in the widget’s data-sitekey, or in sitekey for turnstile.render():
| Sitekey | Behavior | Visibility |
|---|---|---|
1x00000000000000000000AA |
Always passes | Visible |
2x00000000000000000000AB |
Always fails | Visible |
1x00000000000000000000BB |
Always passes | Invisible |
2x00000000000000000000BB |
Always fails | Invisible |
3x00000000000000000000FF |
Forces an interactive challenge | Visible |
With a passing sitekey, the widget produces a dummy token straight away and fills the
cf-turnstile-response field, so your test can submit the form as a person would.
The testing secret keys (server side)
Configure one of these as your server’s Turnstile secret, the value it sends to siteverify:
| Secret key | siteverify answers |
|---|---|
1x0000000000000000000000000000000AA |
Always passes |
2x0000000000000000000000000000000AA |
Always fails |
3x0000000000000000000000000000000AA |
Fails as a token that was already spent |
Pair a sitekey and a secret key to make the combination you want to test: a passing widget with a failing secret, for example, checks that your server really refuses a bad token instead of trusting the browser.
The Cloudflare Turnstile test sitekeys page renders each sitekey live, and runs siteverify with each secret key, so you can see what your tests will meet before you write them.
Wire them in by environment
Keep the real keys out of test environments entirely. Read both values from configuration, and set the testing ones in CI:
# CI and local developmentTURNSTILE_SITEKEY=1x00000000000000000000AATURNSTILE_SECRET=1x0000000000000000000000000000000AARender the sitekey from that setting:
<div class="cf-turnstile" data-sitekey="{{ TURNSTILE_SITEKEY }}"></div>And verify with the secret from the same place:
import os, requests
def verify(token: str, remote_ip: str | None = None) -> bool: reply = requests.post( "https://challenges.cloudflare.com/turnstile/v0/siteverify", data={"secret": os.environ["TURNSTILE_SECRET"], "response": token, "remoteip": remote_ip}, timeout=10, ).json() return reply.get("success") is TrueA production deploy that still carries a testing key accepts everyone, so add a startup check
that refuses any key starting with 1x, 2x or 3x when the environment is production.
Test cases worth having
- Happy path: sitekey
1x…AA, secret1x…AA. The form submits and your server accepts it. - Rejected token: sitekey
1x…AA, secret2x…AA. Your server refuses the submission and shows the visitor a useful message. - Spent token: secret
3x…AA. Your server treatstimeout-or-duplicateas a failure and asks for a new challenge instead of retrying the same token. See Cloudflare Turnstile token expiry for why tokens are single-use. - Blocked visitor: sitekey
2x…AB. Your form stays disabled and says why. - Interactive challenge: sitekey
3x…FF. Your layout still works when the widget asks for a click. - Invisible widget: sitekeys
1x…BBand2x…BB, if you use invisible mode. See Cloudflare Turnstile widget modes.
When a solving API is the right tool instead
Testing keys only work on sites whose configuration you control. When you automate a page you do not run, such as a partner’s portal you have permission to use or a public page whose terms allow it, the widget uses its real sitekey, and a token must be solved. That is what the Cloudflare Turnstile solver is for: a task with the page URL and sitekey returns a real token, charged only when it is solved.
Keep the two apart. Use Cloudflare’s keys for your own CI, and use a solving API only against sites you are allowed to automate under the Acceptable Use Policy.