CaptchaNo
Back to blog
tutorials28 Oct 2026·11 min read

How to Test reCAPTCHA and Turnstile With Test Keys

DDishant Singh
tutorials

How to test reCAPTCHA and Turnstile with test keys, and the server test cases those keys hide. Real siteverify results from our October 2026 run.

To test reCAPTCHA or Cloudflare Turnstile on your own site, point your test build at the providers' published test keys, then test your server's rejection logic separately, because the test keys hide most of it. We ran both providers' test keys against their real siteverify endpoints on 28 October 2026, and Google's v2 test secret said success: true even when we sent no token at all. If you want the background on what these widgets check, start with how modern captcha tests decide you are human.

This guide is for developers and QA engineers testing forms they own. It covers the keys for reCAPTCHA v2, v3 and Enterprise and for Turnstile, what each one actually returns, the server-side test cases that matter, and a guard that stops test keys reaching production.

How to test reCAPTCHA and Turnstile: the short answer

Use the provider's test keys for browser tests, and stub the verification call for server tests. That split is the whole method.

  • Browser (end-to-end) tests check that the widget loads, the token reaches your form and the form submits. Test keys make this deterministic: no image grid, no flaky score.
  • Server tests check what your backend does with a missing, invalid, reused or expired token, and when siteverify is down. Test keys cannot drive most of these cases, as our results below show, so you control the siteverify response yourself.
  • A production guard refuses to start, or refuses every token, if a test key is configured in production.

Do not try to solve your own captcha in CI, and do not lower your production threshold so tests pass. Both test something other than what real users get.

Test keys for each captcha type

Each provider handles testing differently: Google publishes one fixed v2 key pair, Cloudflare publishes a set of keys with fixed outcomes, and reCAPTCHA v3 and Enterprise need a separate key you create.

CaptchaWhat to use in testsBehaviourSource
reCAPTCHA v2 (checkbox and invisible)Google's published test site key and secretNo challenge; every verification passes; widget shows a red "for testing purposes only" noticereCAPTCHA FAQ
reCAPTCHA v3A separate key you create for test environmentsReal scoring, so scores may be unreliable without real trafficreCAPTCHA FAQ
reCAPTCHA Enterprise / Google Cloud keysA testing key created with gcloud recaptcha keys create and --testing-score (plus --testing-challenge for checkbox keys)Fixed score on every assessment; checkbox keys either never challenge or always show an unsolvable challengeGoogle Cloud reCAPTCHA FAQ
Cloudflare TurnstileDummy site keys and secret keysAlways pass, always fail, force an interactive challenge, or return "already spent"Turnstile testing docs

Google lists the v2 pair in its reCAPTCHA FAQ (site key 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI, secret 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe). They are public on purpose, so you can commit them to test fixtures. For v3, the same FAQ tells you to create a separate key and warns that scores may not be accurate, which is why many teams lower the threshold only in their test build or mock the score. Our guide to reCAPTCHA v3 scores covers what those numbers mean.

Keys you manage in Google Cloud work differently. Google's Cloud reCAPTCHA FAQ (updated 26 October 2026) shows how to create testing keys with the gcloud CLI: a checkbox key with --testing-challenge=nocaptcha --testing-score=1.0 that never challenges, one with --testing-challenge=challenge --testing-score=0.0 that always shows an unsolvable challenge, and a score key with a fixed --testing-score. Testing keys cannot be converted or edited later, only deleted. If you would rather keep your real staging key, Google's IP allowlist feature gives allowlisted addresses a fixed score of 0.9, up to 1,000 addresses or subnets per key. Our explainer on how Enterprise differs from v2 and v3 helps if you are not sure which key type you have.

Cloudflare documents the Turnstile set on its Turnstile testing page (updated 20 October 2026). Site keys: 1x00000000000000000000AA always passes (visible), 2x00000000000000000000AB always fails, 1x00000000000000000000BB and 2x00000000000000000000BB are the invisible pass and fail keys, and 3x00000000000000000000FF forces an interactive challenge. Secrets: 1x0000000000000000000000000000000AA passes, 2x0000000000000000000000000000000AA fails, and 3x0000000000000000000000000000000AA returns "token already spent". The passing site key produces the dummy token XXXX.DUMMY.TOKEN.XXXX.

What the test keys actually returned in our run

We loaded each test site key in headless Chromium on a local page, captured the token, and sent it to the real siteverify endpoints with every secret and a few bad inputs. The run was a small Node script on 28 October 2026 at 05:45 UTC, repeated 46 seconds later with identical results.

reCAPTCHA v2 checkbox loaded with Google's test site key on a local page, ticked green, with the red notice that the reCAPTCHA is for testing purposes only

Google's v2 test key on 127.0.0.1: one click, a green tick with no image challenge, and a red testing notice inside the widget.

The checkbox produced a token about half a second after the click in both runs (495 ms and 436 ms). Then the server side:

Table of twelve siteverify responses: Google's v2 test secret returned success true for a real token, a reused token, a fake token and no token; Turnstile's passing secret accepted a reused and a fake token but rejected a missing one, and its fail and spent secrets returned invalid-input-response and timeout-or-duplicate

Raw siteverify results from our run. With production keys, the reused, fake and missing-token rows would all have failed.

Four results matter for anyone writing tests:

  1. Google's v2 test secret accepts anything. A real token, the same token a second time, the string not-a-real-token, and a request with no response field at all all came back success: true with hostname testkey.google.com. Google's docs say production tokens are single-use and expire after two minutes; the test pair checks neither, so it cannot test your replay, expiry or missing-token handling.
  2. Turnstile's passing secret is almost as permissive. It accepted the dummy token twice and also accepted not-a-real-token. It did reject a request with no token (missing-input-response). Cloudflare's page says test secrets reject real tokens; our fake string was not a real token, so this does not contradict it, but do not rely on the passing secret to catch malformed input.
  3. Turnstile covers the failure paths Google does not. The 2x secret returned invalid-input-response and the 3x secret returned timeout-or-duplicate, both with HTTP 200. An unknown secret returned HTTP 400 with invalid-input-secret, so your code has to read the JSON body even on a 400.
  4. The responses label themselves. Turnstile's test responses included "metadata": {"result_with_testing_key": true} and hostname example.com (Cloudflare's sample shows localhost). Google's carried hostname testkey.google.com. Both make a cheap production guard, below.
Three Cloudflare Turnstile widgets rendered with the always-pass, always-fail and force-interactive test site keys, each with a red For testing only banner

Turnstile test site keys in headless Chromium. The pass widget had already delivered its dummy token when this was captured, though it still drew "Verifying…".

That last screenshot is a useful warning for end-to-end tests. In headless Chromium the always-pass widget's callback fired with XXXX.DUMMY.TOKEN.XXXX while the widget still drew "Verifying…" six seconds later. The always-fail key called the error callback with code 600010, and the forced-challenge key never issued a token without a click. Assert on the callback or the hidden cf-turnstile-response input, not on what the widget looks like.

Server-side test cases for a captcha-protected form

Most captcha bugs live in the backend, so most of your test cases belong there. Run them against a stubbed siteverify, not the test keys, because the stub lets you return exactly the response each case needs.

Test caseStubbed siteverify responseExpected behaviour
Valid tokensuccess: true, your hostnameForm is processed
No token in the requestNot called, or missing-input-responseRejected before any side effect
Invalid or forged tokeninvalid-input-responseRejected; user asked to retry
Reused or expired tokentimeout-or-duplicateRejected; widget reset so a fresh token is issued
Wrong environment's secretinvalid-input-secret (HTTP 400 on Turnstile)Rejected and logged as a configuration error
Hostname mismatchsuccess: true, another hostnameRejected
reCAPTCHA v3 low score or wrong actionscore: 0.1 or an unexpected actionYour fallback runs (extra step), not a silent drop
Siteverify unreachable or times outNetwork errorFail closed: reject, do not process

The expected behaviour column is where tests usually pass for the wrong reason. Assert that no side effect happened (no row written, no email sent), not just that the response code was 403. A useful sanity check: delete the siteverify call from your handler and run the suite. If everything still passes, the suite is not testing the protection. When a real user's token is rejected in production for reasons none of these cases cover, our guide to why valid tokens get rejected walks through the session-level causes.

A guard that keeps test keys out of production

Test keys pass everything, so a test key in production switches your captcha off without any error. Guard against it at startup and on every response.

const TEST_SECRETS = new Set([
  "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe", // reCAPTCHA v2 test secret
  "1x0000000000000000000000000000000AA",
  "2x0000000000000000000000000000000AA",
  "3x0000000000000000000000000000000AA",
]);

if (process.env.NODE_ENV === "production" && TEST_SECRETS.has(process.env.CAPTCHA_SECRET)) {
  throw new Error("Captcha test secret configured in production");
}

export function isTrustedResult(json, expectedHost) {
  if (!json.success) return false;
  if (json.metadata?.result_with_testing_key) return process.env.NODE_ENV !== "production";
  if (json.hostname === "testkey.google.com") return process.env.NODE_ENV !== "production";
  return json.hostname === expectedHost;
}

The hostname check also catches the more common real bug: a token minted on another site being accepted by yours. Keep the test keys in a test-only env file and add a CI step that fails the build if a production config contains any of them. Cloudflare's own end-to-end tutorial suggests a variant: choose test or production keys per request, based on a loopback IP or a secret test header.

End-to-end tests in Playwright, Selenium and Cypress

With test keys in place, the browser test only has to wait for a token and submit. No clicking through challenges, no sleeps.

  • reCAPTCHA v2 test key: click #recaptcha-anchor inside the iframe titled "reCAPTCHA", then wait until #g-recaptcha-response has a value. In our run that took under 500 ms.
  • Turnstile pass key: no click needed. Wait for your data-callback to fire or for input[name="cf-turnstile-response"] to equal the dummy token.
  • Failure path in the browser: load the page with 2x00000000000000000000AB and assert that your error UI appears. This is the one failure case worth testing in a browser.
  • reCAPTCHA v3: there is no visible widget to wait for; assert that your page requested a token with the right action name, and test score handling on the server.

Keep it to one or two browser tests per form. The rest of the coverage belongs in fast server tests against the stub. Our Playwright reCAPTCHA walkthrough shows the iframe selectors and callback wiring in full, and how Turnstile issues its token explains the hidden input and callbacks.

When test keys are not enough

Test keys only work where you control the configuration. Three situations push teams beyond them.

  • Testing against real keys you do not own. A partner's staging environment, a third-party checkout embedded in your flow, or a production smoke test of a login you are authorised to monitor. You cannot swap their keys.
  • Proving the production path. Test keys skip the real challenge, so they never exercise the widget your users actually see. A small scheduled run against real keys catches integration breaks that test keys hide.
  • Score tuning. A v3 test key with a fixed score tells you nothing about how real traffic scores.

For the first two, a solving API returns the token the real widget would have produced, and your test injects it the same way a user's browser would. That is what CaptchaNo does on authorised QA and end-to-end runs: it solves reCAPTCHA v2, reCAPTCHA v3 and Cloudflare Turnstile on our own solving infrastructure. It does not solve score-based reCAPTCHA Enterprise keys, so for those use Google's testing keys or the IP allowlist. Only run real solves against systems you own or have written permission to test.

Frequently Asked Questions

What are the reCAPTCHA test keys?

Google publishes one reCAPTCHA v2 key pair for testing: site key 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI and secret 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe. The widget never shows a challenge and displays a red testing notice. In our October 2026 run, verification with that secret returned success for every request, including ones with no token.

Is there a reCAPTCHA v3 test key?

Not a public one. Google's FAQ says to create a separate v3 key for test environments and warns that scores may be inaccurate without real traffic. If your keys live in Google Cloud, you can create a testing key with a fixed score using the gcloud CLI, or allowlist your test runners' IP addresses so they always receive a score of 0.9.

How do I test Cloudflare Turnstile locally?

Use Cloudflare's dummy keys. The site key 1x00000000000000000000AA always passes and issues the token XXXX.DUMMY.TOKEN.XXXX, and the secret 1x0000000000000000000000000000000AA accepts it. Swap in the 2x secret to test rejection and the 3x secret to test a spent token. They worked on a 127.0.0.1 page in our run with no hostname setup.

Can I test token expiry and replay with test keys?

Not with Google's. Its v2 test secret accepted a reused token and a fake one in our run, so it never produces the timeout-or-duplicate error. Turnstile's 3x secret does return that error on demand. For both providers, the reliable approach is to stub the siteverify response in your server tests and return each error code directly.

Should I disable the captcha in staging instead?

Disabling it is simpler but hides bugs: the widget script, token wiring and verification call never run. Test keys keep that whole path in place while making the result predictable. If you do use a feature flag, make sure it cannot be switched on in production, and keep at least one test that runs with the captcha enabled.

Test the real path when you need to

Test keys plus a stubbed siteverify cover almost every case on forms you own. When you need a real token, against a partner's staging site or a scheduled production check, read the API docs to see how a test requests one, or try the widgets first on our live captcha demo page.