How to Handle CAPTCHA in Selenium Tests
Keep Selenium tests reliable by using CAPTCHA test keys or a controlled test hook. Cover pass, failure, and token-validation paths without solving live challenges.
Short answer: Do not make Selenium solve a live CAPTCHA. Use your provider’s documented test keys or a controlled test hook so tests can exercise predictable pass and failure outcomes. Keep test credentials separate from production, and verify server-side token validation independently. Selenium’s guidance lists CAPTCHA as a discouraged automation target and encourages mocking external services.
Why Selenium should not solve a live CAPTCHA
CAPTCHAs are designed to distinguish people from automated clients. Automating their solution makes tests brittle and works against the challenge’s purpose. Browser changes, challenge variants, risk scoring, and network conditions can all make a test stall or fail for reasons unrelated to your form.
Instead, treat the CAPTCHA provider as an external dependency. Make its outcome deterministic in your test environment, then test that your application handles the result correctly. This follows Selenium’s guidance to mock external services.
Choose a test strategy
| Test layer | Strategy | What it proves |
|---|---|---|
| Routine UI or end-to-end test | Provider test keys or a controlled application test hook | The form, submit action, validation messages, and resulting page state work for known pass and fail outcomes. |
| Provider integration test | Official provider test credentials and documented test cases | Your integration handles provider-defined responses and token validation paths. |
| Production configuration check | Check environment-specific keys and server validation configuration | Test credentials cannot accidentally serve production traffic, and production tokens are verified server-side. |
A successful browser interaction alone does not prove that the server validates tokens. Keep most UI tests isolated from the provider, and use a smaller integration test set to verify the provider contract.
Set up deterministic test outcomes
- Create a dedicated test environment and configure its CAPTCHA site key and server secret separately from production.
- Select a provider-documented test key for routine pass cases, or add a test-only hook that supplies controlled provider responses.
- Keep the hook unavailable in production. Guard it with environment configuration and ensure production startup fails if test keys or test bypass settings are present.
- Write tests for successful submission, rejected token or provider error, visible challenge-related state where relevant, and duplicate or expired token behavior when the provider supports it.
- Assert the user-visible result and the server-side outcome. Do not assert that Selenium completed a live challenge.
When using a test hook, keep it at the provider boundary: the application should receive the same kinds of success and failure results it handles from the real provider. This preserves coverage of form behavior without coupling every UI test to an external service.
Google reCAPTCHA test setup
reCAPTCHA v2
Google documents v2 test keys that show no CAPTCHA and pass verification. They are suitable for deterministic successful-flow tests. Google notes that the test widget displays a warning, so do not use these keys for production traffic.
reCAPTCHA v3
Use a separate testing key for v3. Google cautions that v3 scores may not be accurate in a test environment because the score depends on real traffic. Test the integration path and the application’s handling of score thresholds, but do not treat test scores as representative of real-user scores.
Follow Google’s current instructions for the exact key configuration: Google reCAPTCHA FAQ.
Cloudflare Turnstile test setup
Cloudflare publishes dummy sitekeys and secret keys for automated testing. Choose the documented pair for the outcome you need: always pass, always fail, interactive challenge, or duplicate-token handling. This lets tests cover more than a single successful submission.
Use the matching test secret when validating dummy tokens. Production secrets reject dummy tokens. Turnstile requires server-side token validation through Siteverify; do not treat a browser widget response by itself as proof of a valid submission.
See Cloudflare’s current Turnstile testing keys and server-side validation guide for the test-key matrix and integration details.
Build a Selenium test around the form
The following Python example assumes your test environment has a configured deterministic passing key or test hook. It tests the application flow, not CAPTCHA solving. Replace the URL, selectors, and expected result with those used by your application.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
driver = webdriver.Chrome(options=options)
try:
driver.get("https://test.example.com/signup")
driver.find_element(By.NAME, "email").send_keys("qa@example.com")
driver.find_element(By.NAME, "password").send_keys("example-test-password")
driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
confirmation = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, "[data-testid='signup-success']"))
)
assert "created" in confirmation.text.lower()
finally:
driver.quit()
For a rejection-path test, configure the test environment to return a rejected or invalid token result, submit the same form, and assert the error message and that the account or protected action was not completed. Avoid making the test depend on a specific provider challenge appearing unless that challenge state is itself the behavior under test.
Test matrix and coverage checklist
| Case | Setup | Assertions |
|---|---|---|
| Pass | Provider pass key or controlled success response | Form submits; expected success state appears; server performs the intended action. |
| Reject or provider error | Fail key, invalid token, or controlled error | User sees a recoverable message; protected action does not complete; logs identify the failure without exposing secrets. |
| Challenge UI | Provider’s documented interactive test case, if available | Relevant loading, challenge, retry, or error state is understandable and actionable. |
| Duplicate or expired token | Provider test case where supported | Server rejects or handles the token according to the provider contract; user can retry appropriately. |
| Configuration separation | Inspect test and production environment settings | Test keys and bypass hooks cannot be enabled for production traffic. |
- Keep routine browser tests deterministic and fast by isolating external CAPTCHA calls.
- Use official test credentials for provider-specific behavior where available.
- Keep production token verification on the server.
- Do not infer server validation from a successful Selenium click or a widget state.
- Run tests against a test environment, never a live production form that can create real accounts or trigger real actions.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Test hangs waiting for submit | The test is using a live challenge, or the configured test key does not produce the expected outcome. | Use documented test credentials or a controlled test hook; verify the site key and environment loaded by the browser. |
| Token rejected by the backend | The token came from a dummy key but the server is using a production secret, or the token is invalid, expired, or already used. | Pair the provider’s test site key with its matching test secret; test expiry and duplicate handling as explicit cases. |
| reCAPTCHA v3 score varies | v3 scoring relies on real traffic, and test scores may not be representative. | Do not assert a specific score in routine UI tests. Test threshold handling with controlled responses and use the separate test key for integration-path checks. |
| Production behaves as if CAPTCHA is disabled | A test key or bypass hook reached production configuration. | Separate environment settings, validate them at startup or deployment, and verify production uses production credentials and server validation. |
| Browser test passes but protected action is not secure | The test only checked the widget or browser interaction, not server-side verification. | Add an integration test for the backend validation contract and assert that the protected operation depends on its result. |
| Challenge UI differs between runs | The test relies on live provider behavior, which can vary with traffic and risk evaluation. | Mock the provider for routine tests; reserve provider test cases for a focused integration suite. |
Performance, reliability, and cost
Routine tests that mock or control the provider avoid spending time on external challenge loading and reduce failures caused by network or provider behavior. Keep a smaller provider integration suite to catch configuration and contract mistakes. CAPTCHA provider pricing and test-key limits vary; consult the provider’s current documentation and account terms rather than assuming test traffic is free.
Keep test secrets in your CI secret store or environment configuration, never in source control or browser logs. Avoid logging full tokens: record a correlation identifier and outcome instead. Retry only transient infrastructure failures; repeating a deterministic rejected-token test will not fix its setup.
Or skip the browser setup
If the task is to capture a page rather than exercise its form, ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request returns a PNG, JPEG, WebP, or PDF. Its capture flow accepts cookie and consent banners like a visitor, then removes more than 60 known consent platforms, newsletter popups, and chat widgets before the shot; each step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status.
For Selenium coverage of an application’s CAPTCHA behavior, keep using provider test keys or a test hook as described above. ScreenshotNeo captures pages; it does not replace tests of your server’s CAPTCHA token validation. If you need a clean page capture, make one API call. See the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
It also provides an MCP server for AI agents, including Claude, Cursor, and other MCP clients, with take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for free ScreenshotNeo access.
FAQ
Can Selenium bypass CAPTCHA?
Avoid bypassing or solving live challenges. Use provider-supported test keys or a test-only application hook to control outcomes.
Does a passing test key prove production validation works?
No. Use a provider integration test with the appropriate test credentials and assert that the server validates the token before performing the protected action.
Should every end-to-end test call the CAPTCHA provider?
No. Keep routine tests deterministic by isolating the provider; use focused integration tests for the provider contract and configuration.
Can I use Turnstile dummy tokens with production credentials?
No. Cloudflare documents that production secrets reject dummy tokens. Use the matching test secret in the test environment.
Are reCAPTCHA v3 test scores realistic?
They may not be. Google says v3 relies on real traffic and recommends a separate testing key.


