Problem: CAPTCHAs (Cloudflare Turnstile, Google reCAPTCHA, etc.) are designed to stop bots. They therefore also prevent automated end-to-end tests. To let Thunders scan, explore and validate flows like a human would, customers must temporarily allow test traffic to bypass CAPTCHA on non-production surfaces.
To unlock the value of AI-powered testing, we recommend disabling CAPTCHA on test environments following the best practices below.
1) Disable CAPTCHA in non-production environments
Turn off the CAPTCHA enforcement in QA/staging via environment config or a feature flag. Typical places to change it: environment variables, config files, or toggles in admin/console. This is common and simple if the app separates environments.
How to implement (example):
CAPTCHA_ENABLED=truein production;CAPTCHA_ENABLED=falsein staging.Deploy; run Thunders against the staging domain.
Risk & mitigation: Make sure staging is not exposed to public traffic (use IP allowlists, auth, VPN). Document the change and revert after testing.
2) Whitelist Thunders’ test IPs / clusters
You can add one of Thunders cluster IP(s) to your CAPTCHA provider / firewall allowlist so requests from those IPs bypass CAPTCHA.
How to implement (example):
Client: add Thunders public test IP(s) (we will provide these) to the CAPTCHA provider’s allowlist or to firewall WAF rules as “trusted” for staging.
Note: IP whitelisting is best for staging and internal test networks.
3) Use provider test keys or dedicated test mode (best for dev/staging)
Most providers provide testing keys or testing modes so captcha responses always pass in test environments.
Example: Google reCAPTCHA provides official test keys for v2/v3 that always pass; Cloudflare Turnstile provides testing sitekeys/dummy keys and a Turnstile testing flow. Use those keys in staging. Google for Developers+1
How to implement (example):
Create separate site keys / secret keys for
stagingandproduction.In staging config / env: set
RECAPTCHA_SITE_KEY=test_key,RECAPTCHA_SECRET_KEY=test_secret(or the equivalent Turnstile test sitekey/secret).Point Thunders to the staging URL.
Why: fast, provider-supported, audit-friendly, safe if keys are scoped to test env.
4) Exempt dedicated test accounts (trusted accounts)
Mark one or more user accounts as trusted so the app doesn’t present CAPTCHA for those logins (e.g., accounts with a
bypass_captcha=trueflag).Create accounts like
[email protected]and run all Thunders flows through those credentials.
How to implement (example):
Add a
skip_captchaboolean on user profiles (or make the app check atrustedrole before presenting captcha).Ensure test accounts have least privilege and rotate credentials regularly.
5) Let Thunders set a bypass flag (window.__thunders_bypass)
Use this when the methods above are not open to you: you cannot swap sitekeys, you cannot allowlist our IPs, and the captcha does not sit behind a login you can exempt. It is the only method on this list that needs a code change in your app.
How it works:
Thunders runs an init script in the browser before any of your page's own JavaScript, setting
window.__thunders_bypassto the captcha it detected, for example"hcaptcha". The other values are"recaptcha_v2","recaptcha_v3"and"turnstile".Your app reads that flag and skips its captcha.
The flag does nothing on its own. Until your app reads it, the captcha still appears and the test still fails.
Step 1: skip the widget in your app. Wrap the call that renders your captcha so it is skipped when the flag is set.
reCAPTCHA v2:
if (!window.__thunders_bypass) {
grecaptcha.render("captcha-container", { sitekey: RECAPTCHA_SITE_KEY });
}hCaptcha:
if (!window.__thunders_bypass) {
hcaptcha.render("captcha-container", { sitekey: HCAPTCHA_SITE_KEY });
}Cloudflare Turnstile:
if (!window.__thunders_bypass) {
turnstile.render("#captcha-container", { sitekey: TURNSTILE_SITE_KEY });
}reCAPTCHA v3 has no widget to skip, so skip the token instead:
const token = window.__thunders_bypass
? null
: await grecaptcha.execute(RECAPTCHA_SITE_KEY, { action: "login" });
Step 2: skip verification on your server. The client change alone is not enough. With no widget there is no captcha token, so a backend that still requires one will reject the request and your test fails on submit instead of on the captcha.
window.__thunders_bypass only exists in the browser, so your server cannot read it. Have the client tell the server it is in bypass mode, for example a request field or a header, and have the server honour it only in your test environment.
Keep this out of production
This is a real captcha bypass. Ship the check in non-production builds only, and make the server-side skip conditional on the environment, never on the client's word alone. A bypass your production backend will honour is a vulnerability, not a test setting.
Step 3: enable the init script in Thunders.
Open your Test Project, go to Environments, and open the environment you are testing.
Select the Init Scripts tab and click Add Script.
Name it Captcha bypass and set the script to
window.__thunders_bypass = "hcaptcha";, using the provider your app uses.Click Save Changes.
Why: works when nothing else does, and it stays under your control. Cost: a code change and a deploy on your side, which the other four methods avoid.
Best Practice
Always limit access bypass to test/staging/QA environments, NEVER on production.
Document which method was used for traceability
