All articles

CAPTCHA in Automated Tests: Test Environment Setup

How to handle CAPTCHA in automated tests without weakening production: test keys for reCAPTCHA, hCaptcha and Turnstile, per-environment config and guardrails.

Sooner or later every end-to-end suite meets a sign-up form, a login page or a checkout protected by a CAPTCHA, and the test stops dead. That isn't a bug in your test. A CAPTCHA exists to tell humans from automated browsers, and an automated test is an automated browser. The question isn't how to beat it — it's how to set up your environments so that CAPTCHA in automated tests never comes up, while production stays fully protected. This guide covers what not to do, the test keys that reCAPTCHA, hCaptcha and Cloudflare Turnstile publish for exactly this purpose, how to wire them per environment, and the guardrails that stop a test key from ever reaching production.

Why CAPTCHA in automated tests is a problem

A CAPTCHA looks at signals that separate people from scripts: how the page is interacted with, the browser environment, the request's reputation, sometimes a challenge the user has to solve. Test runners are, by every one of those signals, scripts. Headless browsers, data-centre IP addresses, perfectly regular timing and fresh profiles with no history are precisely what bot detection is tuned to flag.

The result is predictable. A test that passed locally fails in CI. A suite that ran fine for a month starts failing when the provider tightens its scoring. A sign-up test fails intermittently because the challenge appears for some runs and not others. That last pattern is the worst, because intermittent failures erode trust in the whole suite — the dynamic we described in Flaky Tests: Why End-to-End Suites Break.

The flows CAPTCHAs protect are also the ones you most need to test: sign-up, login, password reset, contact forms and checkout. They are, almost by definition, critical user journeys — the entry points through which every new customer and every payment arrives. Skipping them because "the CAPTCHA gets in the way" leaves those entry points unprotected.

What not to do

Don't use CAPTCHA-solving services in your tests. Paying a third party to solve challenges makes your suite slow, flaky and dependent on a service built to defeat the protection you deliberately installed. It also sends your pages to an outside service on every run.

Don't disable the CAPTCHA in production "just for the test account". Any bypass that works in production is a bypass attackers can look for. Allow-listing a test email address, a magic header or a query parameter in production turns a test convenience into a hole.

Don't share real secret keys with your test environment. Staging and CI tend to have more people and more systems with access than production. If a real secret key leaks from there, it can be used against your production site.

Don't let the test environment drift from production. Removing the CAPTCHA widget entirely from staging's templates means the page you test is not the page your users see. Layout, validation and form submission can all behave differently. Prefer keeping the widget and swapping the keys.

The right setup: test keys per environment

The clean solution is the one the providers themselves recommend: the same CAPTCHA integration in every environment, configured with production keys in production and test keys everywhere else. Test keys render the widget and complete the server-side verification, but always pass (or always fail, when you want to test that path) and provide no protection. Your test exercises the real form and the real verification call; it just never meets a challenge.

That gives you three properties at once:

  • The page under test is the page users get.
  • Tests are deterministic — the CAPTCHA never decides whether a run passes.
  • Production protection is untouched, because production never sees a test key.

reCAPTCHA, hCaptcha and Turnstile test keys

The three most common providers all publish test credentials. The values below are taken from their documentation, checked on 15 October 2026; always confirm against the source before you rely on them.

Google reCAPTCHA v2. Google's reCAPTCHA FAQ lists a test site key 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI and secret key 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe. With them, verification always passes, and the widget shows a warning so the keys aren't mistaken for production ones. For reCAPTCHA v3 there are no test keys: the FAQ recommends creating a separate key for testing environments and notes that scores may be less accurate there, because v3 relies on real traffic. In practice that means lowering the score threshold you enforce in staging rather than expecting a fixed result.

hCaptcha. The hCaptcha documentation provides the test site key 10000000-ffff-ffff-ffff-000000000001 with the secret 0x0000000000000000000000000000000000000000: it never shows a challenge and always verifies successfully. Enterprise accounts get additional keys that simulate a safe user (20000000-ffff-ffff-ffff-000000000002) and a detected bot (30000000-ffff-ffff-ffff-000000000003), which are useful for testing how your app reacts to each. hCaptcha warns that the test keys provide no anti-bot protection and must only be used in test environments.

Cloudflare Turnstile. Cloudflare's Turnstile testing page lists dummy site keys for each behaviour: 1x00000000000000000000AA always passes (visible widget), 2x00000000000000000000AB always fails, 1x00000000000000000000BB and 2x00000000000000000000BB are their invisible equivalents, and 3x00000000000000000000FF forces an interactive challenge. On the server side, the secret 1x0000000000000000000000000000000AA always passes validation, 2x0000000000000000000000000000000AA always fails, and 3x0000000000000000000000000000000AA returns a "timeout-or-duplicate" error. The dummy keys work on any domain, including localhost, and production secret keys reject the dummy token — so the test secret must be paired with the test site key.

Bot protection beyond the CAPTCHA

A CAPTCHA is often only one layer. Web application firewalls, bot-management rules and rate limits can block a test runner just as effectively, and they usually sit in front of staging too. A suite that signs up a new user on every run, from the same CI address, can trip a rate limit that no real customer would ever reach. Treat these the same way as the CAPTCHA: relax or allow-list them for your test runner in staging only, keep the rules identical in production, and document which exceptions exist and why.

Wiring it into staging safely

The keys belong in configuration, never in code. Read the site key and the secret from environment variables, and set them per environment.

# .env.staging — Turnstile test keys (always pass)
CAPTCHA_SITE_KEY=1x00000000000000000000AA
CAPTCHA_SECRET_KEY=1x0000000000000000000000000000000AA

# .env.production — real keys come from your secret store, not from this file

Then add a guardrail that makes the dangerous mistake impossible: refuse to start in production with a known test key.

// config/captcha.ts
const TEST_SITE_KEYS = new Set([
  '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI', // reCAPTCHA v2
  '10000000-ffff-ffff-ffff-000000000001', // hCaptcha
  '1x00000000000000000000AA', // Turnstile, always passes
]);

export const captcha = {
  siteKey: process.env.CAPTCHA_SITE_KEY ?? '',
  secretKey: process.env.CAPTCHA_SECRET_KEY ?? '',
};

if (process.env.APP_ENV === 'production' && TEST_SITE_KEYS.has(captcha.siteKey)) {
  throw new Error('Test CAPTCHA keys must never be used in production');
}

A few more habits keep the setup honest:

  • Protect staging itself. With the CAPTCHA effectively off, staging is open to anyone who finds it. Put it behind HTTP basic authentication or a VPN, and give your test runner the credentials.
  • Keep one integration path. The widget, the form submission and the server-side verification call should be the same code in every environment; only the keys differ.
  • Test production's protection separately. A manual check after each CAPTCHA-related change — the widget renders, verification happens on the server — covers what the automated suite deliberately skips.
  • Write it down. A short note in the repository explaining which keys each environment uses saves the next engineer from "fixing" staging by pasting in production keys.

This is one instance of a wider principle: production-like test environments with their own data and credentials. The trade-offs between testing before release and checking production are covered in Shift-Left and Shift-Right: A Complete Testing Strategy.

A checklist for a CAPTCHA-ready test environment

Before you point any automated suite at a protected flow, check that:

  • the CAPTCHA widget is present in staging and uses your provider's test site key;
  • the server verifies tokens with the matching test secret, through the same code path as production;
  • reCAPTCHA v3, if you use it, has a separate staging key and a score threshold that real test traffic can meet;
  • production refuses to start with a test key, and real secrets never leave your secret store;
  • staging itself is protected by basic authentication or a VPN, and the test runner has the credentials;
  • firewall and rate-limit exceptions for the test runner exist in staging only;
  • one run per release uses an "always fails" key, so the error state of each protected form is tested too;
  • someone checks production's CAPTCHA by hand after any change to the integration.

None of these items is complicated, but missing any one of them tends to show up as either a flaky suite or a weakened production — usually at the worst possible moment.

How AI testing tools handle CAPTCHA

AI-assisted tools change how tests are created — from a plain-language description instead of code — but they meet a CAPTCHA the same way any automated browser does. A responsible tool won't try to solve it, because a tool that defeats CAPTCHAs is a tool that helps bots. Expect the same setup either way: point the tool at an environment that uses test keys or has the CAPTCHA disabled.

What AI tools can make easier is everything around it: describing the sign-up or checkout flow once, generating test data for each run, and explaining clearly when a run stops because a challenge appeared instead of failing with an opaque timeout. For the general picture of what these tools do and don't do, see End-to-End Testing: What It Is and How to Do It Right.

Where BuniOD fits

BuniOD runs scenarios in a real browser and acts like a user, so a CAPTCHA can block a run — the same as for any other automated test. We say so openly: point BuniOD at a staging environment where the CAPTCHA uses test keys or is disabled. If staging is protected by HTTP basic auth, BuniOD stores those credentials encrypted, and test identities with their own inbox cover sign-up flows that send a confirmation email.

With that in place, you write a flow as plain-language steps — for example, open the sign-up page, fill in the email from a test identity, submit the form — with an expected result such as seeing the account page. BuniOD builds the scenario, with test data and checks, for you to review before it runs, on demand or once a day. The sign-up and onboarding testing page shows a worked example.

Conclusion

Handling CAPTCHA in automated tests isn't about outsmarting the CAPTCHA. Keep the same integration everywhere, use your provider's test keys outside production — reCAPTCHA v2, hCaptcha and Turnstile all publish them — and treat reCAPTCHA v3 as a separate key with a relaxed score in staging. Load the keys from configuration, refuse to boot production with a test key, and keep staging behind its own authentication. Do that once, and the flows CAPTCHAs protect — sign-up, login and checkout — become as testable as every other part of your product.

Newsletter

Quality intelligence, in your inbox

Occasional, high-signal writing on AI testing and release quality. No spam.

You're subscribedThanks — we'll be in touch when the next piece is out.

We'll only email you about new articles. Unsubscribe anytime.

Get started

Turn a described flow into a browser scenario

Connect your application, write the steps of the flow you want to verify, and review the scenario BuniOD builds.

Start free