DEV Community

11111
11111

Posted on

Solving CAPTCHAs in Selenium Tests Without Slowing Down CI

If you've ever built E2E tests with Selenium, you've hit this wall: your test suite runs perfectly until a login page throws up a reCAPTCHA, and suddenly your CI pipeline is broken.

Here are three approaches I've used, with honest pros and cons for each.

Approach 1: Disable CAPTCHAs in Test Environments

The simplest fix — just turn them off.

# Django example: settings_test.py
RECAPTCHA_TESTING = True

# Or use an env flag
# CAPTCHA_ENABLED=false pytest
Enter fullscreen mode Exit fullscreen mode

When it works: Internal apps where you control the backend.

When it doesn't: Testing against third-party sites, or when you need to verify the CAPTCHA integration itself works in production.

Approach 2: Try to Click Through It

from selenium.webdriver.common.by import By

# Switch to reCAPTCHA iframe
iframe = driver.find_element(By.CSS_SELECTOR, "iframe[src*='recaptcha']")
driver.switch_to.frame(iframe)

# Click the checkbox
checkbox = driver.find_element(By.CLASS_NAME, "recaptcha-checkbox")
checkbox.click()
Enter fullscreen mode Exit fullscreen mode

Reality check: This works maybe 20% of the time. Modern reCAPTCHA detects Selenium via navigator.webdriver, missing plugins, robotic mouse patterns, and CDP fingerprints.

Approach 3: API-Based Token Injection

Instead of fighting the CAPTCHA in the browser, solve it externally and inject the token:

from selenium import webdriver
from selenium.webdriver.common.by import By
import os, requests

def solve_captcha_and_inject(driver):
    sitekey = driver.find_element(
        By.CSS_SELECTOR, "[data-sitekey]"
    ).get_attribute("data-sitekey")

    resp = requests.post("https://api.passxapi.com/solve", json={
        "type": "recaptcha_v2",
        "sitekey": sitekey,
        "url": driver.current_url
    }, headers={"x-api-key": os.getenv("PASSXAPI_KEY")})

    token = resp.json()["token"]

    driver.execute_script(
        f"document.getElementById('g-recaptcha-response').value = '{token}';"
    )
    return token
Enter fullscreen mode Exit fullscreen mode

The CAPTCHA system never sees Selenium. It sees a normal API request, solves the challenge server-side, and returns a valid token.

CI/CD Pattern: Mock in CI, Real in Staging

import pytest, os

@pytest.fixturedef captcha_solver(monkeypatch):
    if os.getenv("CI"):
        monkeypatch.setattr(
            "myapp.captcha.solve",
            lambda **kw: "mock_token_for_ci"
        )
    return CaptchaSolver(api_key=os.getenv("PASSXAPI_KEY"))
Enter fullscreen mode Exit fullscreen mode

Auto-Detecting CAPTCHA Type

def detect_and_solve(driver):
    source = driver.page_source.lower()
    captcha_types = {
        "recaptcha": ["recaptcha", "g-recaptcha"],
        "hcaptcha": ["hcaptcha", "h-captcha"],
        "turnstile": ["cf-turnstile", "challenges.cloudflare.com"],
    }
    for ctype, indicators in captcha_types.items():
        if any(ind in source for ind in indicators):
            sitekey = driver.find_element(
                By.CSS_SELECTOR, "[data-sitekey]"
            ).get_attribute("data-sitekey")
            return solve_via_api(type=ctype, sitekey=sitekey, url=driver.current_url)
    return None
Enter fullscreen mode Exit fullscreen mode

Comparison

Disable in test env Click through API + inject
Works on 3rd-party sites No Sometimes Yes
CI/CD friendly Yes No (flaky) Yes
Success rate N/A ~20% 95%+

Wrapping Up

For internal apps, disabling CAPTCHAs in test mode is fine. For anything else, API-based solving is the most reliable approach.

Full Python SDK: passxapi-python on GitHub


What's your approach to CAPTCHAs in test automation? Drop a comment below.

Top comments (0)