proxy-compare.com

Blog · How it works

Test captcha flows in Playwright without solving anything

Proxy Compare built a Playwright fixture on 16 Sep 2026 using the test keys Google and Cloudflare publish, and verified all four behaviors against their live verification endpoints rather than mocks. Google ships v2 test keys and none for v3; Cloudflare ships six dummy sitekeys and three dummy secrets, one made to prove a replayed token is rejected.

16 Sept 2026 · 5 min read

Point in time. The figures below were read on 16 Sept 2026 and are not updated after publication. For current numbers see the comparison table.

On this page (4)
Test captcha flows in Playwright without solving anything

You own the application. You want a test suite that clicks through the signup or checkout flow, and the flow has a captcha on it. The three usual answers are all wrong in different ways: solving real captchas in CI costs money and fails anyway, skipping the widget tests nothing, and mocking the widget away tests a code path production never takes.

The vendors ship the fourth answer, and most test suites do not use it. Google and Cloudflare both publish deterministic test keys: swap them in and the widget renders for real, the token arrives for real, and the verification endpoint really answers. Your test then covers the exact wiring that breaks in production, the part mocks never touch.

The keys both vendors publish

For reCAPTCHA v2, Google's FAQ gives one pair, and states plainly what happens with it: "You will always get No CAPTCHA and all verification requests will pass." The site key is 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI, the secret is 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe, and the widget shows a warning banner so nobody ships it by accident, because "The reCAPTCHA widget will show a warning message to ensure it's not used for production traffic."

For v3 there are no test keys at all. Google's guidance is to "create a separate key for testing environments. Scores may not be accurate as reCAPTCHA v3 relies on seeing real traffic." A v3 score asserted in CI is a number about your test runner's IP, not about your users, so build the assertion around the token existing and the verdict endpoint answering, never around the score.

Turnstile publishes a bigger set, and the pairings matter more than the keys. Sitekey 1x00000000000000000000AA always passes, 2x00000000000000000000AB always fails, and 3x00000000000000000000FF forces the interactive challenge. On the secret side, 1x0000000000000000000000000000000AA always passes validation, and 3x0000000000000000000000000000000AA returns the token-already-spent error, which exists so you can test the one failure your server code must handle correctly. Cloudflare's docs also carry the caveat that decides how you wire the stub: "Production secret keys will reject the dummy token. You must also use a dummy secret key for testing purposes." Test keys work on localhost and 127.0.0.1, which production sitekeys should not.

The fixture: an owned page and a real verification stub

Two files and a test. The page is your application reduced to the part under test, a form with both widgets on it:

html
<div class="cf-turnstile" data-sitekey="1x00000000000000000000AA"></div>
<div class="g-recaptcha" data-sitekey="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"></div>
<form id="comment">
  <textarea name="body">Runs the suite.</textarea>
  <button type="submit" id="send">Post</button>
</form>

The verification stub is a dozen lines of Node, and the important property is what it does not do: it does not fake the vendor's answer. It forwards the token to the real siteverify endpoint with the test secret, so a green test means Google or Cloudflare actually said yes:

js
const r = await fetch("https://www.google.com/recaptcha/api/siteverify", {
  method: "POST",
  body: new URLSearchParams({
    secret: "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe",
    response: token,
  }),
});
return r.json();

Same shape for Turnstile against https://challenges.cloudflare.com/turnstile/v0/siteverify, with the secret chosen per test from the table above. That one choice, forwarding instead of stubbing, is what makes the suite tell the truth: on 16 September 2026 this fixture verified all four behaviors below against the live endpoints, not against fixtures of them.

Four tests, four different guarantees

The widgets initialize. Wait for the hidden token input to exist, not for an iframe to be visible. Both vendors park an input like cf-turnstile-response or g-recaptcha-response in the host page the moment the widget attaches, and a challenge iframe can sit invisible or get re-parented while it works. Waiting on the iframe was the one probe that flaked when we built this.

The happy path, token to verdict. With reCAPTCHA v2 test keys the interaction is one click on the checkbox, which is what "No CAPTCHA" means: no image challenge follows. Click it through the anchor iframe, take the token from the textarea, send it through the stub, and assert success is true from the live Google endpoint.

The form end to end. Turnstile's always-passes sitekey emits its dummy token XXXX.DUMMY.TOKEN.XXXX without any interaction. Submit the form and assert the verdict the reader would see. This is the test that catches the class of bug where the widget works and the form never sends the token anywhere.

The replayed token. Take a token that already verified, send it again against the 3x...AA secret, and assert you get timeout-or-duplicate back. A replayed token is the attack your server-side check exists to stop, and this is the only test in the set that exercises a failure path at the endpoint rather than in your code. Run the tests sequentially, one page each. Page lifecycles racing on a shared browser produced protocol errors the first time this suite ran, and there is nothing worth debugging in that at 2am.

What this tests, and what it does not

Test keys test your application's wiring: render, token flow, verdict handling, replay rejection. They say nothing about whether a third-party solver can get through a captcha on somebody else's site, which is a different product with a different test. If that is the job, the questions are which service prices the challenge you actually hit and what a month of solves costs, and we hold dated rate cards for both, on the captcha hub and in the cost tool.

The boundary also runs the other way. A suite green on test keys has verified nothing about your production keys: domains, score thresholds, and the secret you keep on the server. Swap the keys in a staging environment with its own sitekeys, run the same four tests, and the fixture keeps earning its keep.

One more boundary that matters if you arrived here from the scraping side: this guide is about an app you own. Testing against a site you do not own is a different article with different constraints, and the playwright-stealth guide is the one for that job. If the choice you are actually making is between renting a scraping API and renting a browser session in the first place, what each one sells is the decision guide for that layer.

Sources

  1. reCAPTCHA FAQ, automated tests section Google, read 16 Sept 2026
    You will always get No CAPTCHA and all verification requests will pass.
  2. reCAPTCHA FAQ, automated tests section Google, read 16 Sept 2026
    The reCAPTCHA widget will show a warning message to ensure it's not used for production traffic.
  3. reCAPTCHA FAQ, v3 testing Google, read 16 Sept 2026
    create a separate key for testing environments. Scores may not be accurate as reCAPTCHA v3 relies on seeing real traffic
  4. Turnstile testing keys Cloudflare, read 16 Sept 2026
    Production secret keys will reject the dummy token. You must also use a dummy secret key for testing purposes.
  5. Turnstile testing keys, dummy secret list Cloudflare, read 16 Sept 2026
    3x0000000000000000000000000000000AA