ScreenshotNeo

BlogHow-to

How to Solve CAPTCHAs in Browser Automation

For sites you own, test CAPTCHA flows with provider test keys and verify tokens on your server. For third-party production challenges, use an authorized access path or human review.

By the ScreenshotNeo team4 October 20267 min read

For an application you own or are authorized to test, use your CAPTCHA provider’s documented test keys or test mode. That lets browser automation exercise success, failure, and application handling predictably. For a third-party production site, do not try to defeat its CAPTCHA: use an authorized access path or hand the step to a person where appropriate. Cloudflare says browser automation frameworks are not supported for solving production challenges. Cloudflare’s supported-browser guidance points automation users toward test keys.

Choose the right testing approach

First establish that the site and CAPTCHA integration are yours or that you have permission to test them. Then choose the approach based on what you need to verify:

Goal Approach What it tells you
Test your own Turnstile-backed form Use Cloudflare’s documented dummy sitekeys and test secrets in a non-production environment How your UI and server handle known verification outcomes
Test your own reCAPTCHA integration Use Google’s documented testing setup: a separate key for v3 and test keys for v2 How your application handles the provider’s test configuration
Test a real production challenge Use an authorized manual or staging procedure A controlled end-to-end check, when specifically needed
Access a third-party site protected by a challenge Request an approved API, allowlist, test account, or human-assisted route Access through a path the site owner permits

Real challenge results can vary with browser signals. Cloudflare documents that Turnstile runs non-interactive browser checks and can adapt outcomes; browser extensions that change the user agent or APIs such as Canvas and WebGL can affect signals. That makes real challenges a poor default for repeatable test suites. Turnstile overview · How Cloudflare challenges work.

Test an owned Turnstile integration with Playwright

Set up a staging or local application that uses the provider’s documented test sitekey and matching test secret. The test key belongs in the browser configuration; the secret belongs only on the server. Use Cloudflare’s current Turnstile testing documentation to choose keys for the scenario you want, since the key behavior is intentionally predetermined.

Below is a complete Playwright test pattern. It assumes your app exposes a test-only configuration switch that selects the documented test sitekey and test secret, and that a successful form submission displays a confirmation. Adapt the URL and selectors to your application. Do not enable the test-key switch in production.

import { test, expect } from '@playwright/test';

test('submits the form after test verification succeeds', async ({ page }) => {
  await page.goto('http://localhost:3000/contact?captchaMode=test-pass');
  await page.getByLabel('Email').fill('dev@example.test');
  await page.getByLabel('Message').fill('CAPTCHA integration test');
  await page.getByRole('button', { name: 'Send' }).click();
  await expect(page.getByText('Message received')).toBeVisible();
});

test('shows an actionable error after test verification fails', async ({ page }) => {
  await page.goto('http://localhost:3000/contact?captchaMode=test-fail');
  await page.getByLabel('Email').fill('dev@example.test');
  await page.getByLabel('Message').fill('CAPTCHA failure-path test');
  await page.getByRole('button', { name: 'Send' }).click();
  await expect(page.getByRole('alert')).toContainText('Verification failed');
});

The captchaMode switch above is an application example, not a Turnstile parameter. Implement it only in your test configuration so it selects the provider’s documented test keys. For a real integration, assert the user-visible result and the server-side behavior rather than attempting to read or manufacture a production challenge token in browser code.

Test the server-side verification boundary

A CAPTCHA widget is not the final security decision. For Turnstile, the browser widget produces a token, and your server must send it to Siteverify. Cloudflare states that server-side validation is mandatory; skipping it leaves the application exposed to invalid, expired, or already redeemed tokens. Keep the secret key server-side. Cloudflare’s integration guide documents the widget and Siteverify flow.

Cover these cases in the server integration tests, using the provider’s current test secrets and documented outcomes:

  • A valid test token is accepted and the intended application action succeeds.
  • A failed verification is rejected and the user receives an actionable error.
  • A duplicate or already-spent token is rejected where your integration handles that case.
  • Missing, expired, or malformed tokens do not bypass your server’s verification requirement.

Keep production credentials separate from local and CI settings. Do not expose a secret in client JavaScript, source control, test logs, screenshots, or build artifacts. Treat test keys as test configuration rather than as a substitute for production validation.

Test reCAPTCHA integrations

Google’s official FAQ advises using a separate key for reCAPTCHA v3 testing and provides test keys for v2. Consult the current reCAPTCHA FAQ for the exact setup and constraints; do not copy key values from old examples. Configure test credentials in the test environment and assert your application’s pass and fail handling. Keep production keys isolated.

A practical test workflow

  1. Confirm authorization. Limit automation to systems you own or have explicit permission to test.
  2. Separate environments. Use local or staging configuration with provider test keys. Keep production secrets out of browser code and CI output.
  3. Choose the provider outcome. Select documented test keys for success, failure, visible or invisible widget behavior, and interactive scenarios where relevant.
  4. Exercise application behavior. Verify whether the form can proceed, whether errors are clear, and whether protected actions remain blocked after failed verification.
  5. Check server validation. Confirm your backend uses Siteverify for Turnstile and handles invalid, expired, or spent tokens safely.
  6. Keep real-challenge checks exceptional. If a real challenge must be checked end to end, do it in an authorized staging or manual process rather than making challenge evasion a routine automated test requirement.

Cloudflare’s dummy keys cover predictable pass and fail cases for visible and invisible widgets, an interactive challenge scenario, and server-side validation outcomes. Its documentation says the test keys can be used on local development domains and other development domains. For production hostname configuration, Cloudflare recommends not allowing localhost or 127.0.0.1. Check the current test-key instructions before configuring your environment.

Common problems and fixes

Symptom Likely cause What to do
Automated tests intermittently encounter a challenge or fail The test is using a real challenge whose result depends on browser or visitor signals Use documented provider test keys for routine owned-site tests. Reserve authorized real-challenge checks for controlled staging or manual runs.
The browser widget appears to pass, but the backend rejects the form The server’s Siteverify request, secret, or token handling is incorrect Check the server-side integration and test-secret selection against Cloudflare’s current guide. Never treat the visible widget alone as verification.
A verification token is rejected on reuse The token may be expired or already redeemed Request a fresh token in the intended client flow and ensure the backend rejects duplicates. Use the provider’s test validation case to exercise this behavior.
A test key behaves differently from expected The wrong documented key type or environment configuration is selected Match the sitekey and secret to the exact documented scenario and reload the test environment after changing configuration.
Production challenge behavior differs across machines Browser extensions or modified browser signals may affect challenge evaluation Use provider test mode for deterministic application tests; keep the browser environment consistent for any authorized manual check.
Development hostname is rejected Hostname settings do not match the environment, or production configuration is being reused Use the provider’s test setup for local development and verify the configured hostnames. Keep localhost out of production hostname allowances as Cloudflare recommends.

Performance, reliability, and cost

Provider test keys avoid spending test time on unpredictable challenge outcomes and make pass and failure paths repeatable. They do not prove that every production challenge will behave identically, nor do they replace backend validation tests. Keep the browser suite focused on application behavior and test the server verification boundary separately where appropriate.

The dossier establishes no CAPTCHA solver success rates, performance benchmarks, or prices, so this guide makes no such claims. For third-party production sites, do not treat a solver service as the default workaround; use an access method approved by the site owner.

Or skip the browser setup

If your task is to capture a page rather than test your own CAPTCHA integration, ScreenshotNeo is a website screenshot API and MCP server. It does not solve third-party CAPTCHAs; CAPTCHA and bot-check pages are classified as bot checks rather than clean captures. Its billing rules mean bot checks, blank pages, failed loads, timeouts, and cache hits cost nothing, and responses identify the page verdict and billing status in headers. Cookie and consent banners, newsletter popups, and chat widgets can be removed before capture.

One GET request returns an image or PDF. Here is the cURL example from the ScreenshotNeo documentation:

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -o shot.webp

Equivalent Python:

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)

Equivalent Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 shots a month with no card; paid plans start at $5 for 3,000 shots. Every feature is available on every plan. Sign up free for 1,000 screenshots a month, with no card.

FAQ

Can Playwright or Selenium solve a production CAPTCHA?

Do not use browser automation to defeat a third-party production challenge. Cloudflare says these frameworks are not supported for solving production challenges; arrange authorized access or human assistance.

Do test keys mean my production CAPTCHA is tested?

They test application behavior against documented outcomes. They do not reproduce every signal or outcome of a real production challenge.

Can I put the CAPTCHA secret in the browser test?

No. Keep provider secrets on the server or in protected server-side test configuration. The browser should only use the sitekey.

Does ScreenshotNeo bypass CAPTCHA?

No. It identifies bot checks and does not bill those responses as clean shots. Use it to capture pages that load successfully, not to circumvent access controls.