hCaptcha

hCaptcha Guide — How It Works and How to Solve It

hCaptcha is a privacy-preserving CAPTCHA service that has become the second-most-deployed challenge system after reCAPTCHA. It is used by Cloudflare (on its portal), Discord, GitHub, Binance, and thousands of other sites. This guide explains how hCaptcha works, how solver APIs handle it, and how to integrate hCaptcha solving into an automation pipeline.

What Is hCaptcha?

hCaptcha was built as a privacy-first alternative to reCAPTCHA. Unlike Google's product, hCaptcha does not use the challenge data to train Google's AI models. Instead, it partners with organizations that need labeled image data, turning the CAPTCHA challenge into a data labeling task with direct commercial value.

From a user's perspective, hCaptcha presents image selection grids: "select all motorcycles" or "select all images containing a stop sign." The challenge appearance is similar to reCAPTCHA v2 image grids, but the backend scoring model and challenge content are different.

Where you'll encounter hCaptcha:

  • Cloudflare — Account management portal (not Turnstile; the login page uses hCaptcha)
  • Discord — Account creation, phone verification, login anomalies
  • GitHub — Suspected bot account verification
  • Binance, Kraken, and other exchanges — Account creation and withdrawal flows
  • Epic Games — Account flows alongside FunCaptcha
  • Many indie SaaS and e-commerce sites via CDN-level protection

How hCaptcha Works Technically

The hCaptcha flow:

  1. The page loads https://hcaptcha.com/1/api.js.
  2. The JS widget initializes using a sitekey (a UUID, e.g. 10000000-ffff-ffff-ffff-000000000001 — the public test key).
  3. The user (or solver) completes the image challenge.
  4. On success, the JS writes a signed h-captcha-response token to a hidden form field.
  5. The form submits the token; the server verifies it against https://hcaptcha.com/siteverify.

Token lifetime: ~2 minutes. Solve immediately before form submission.

Passcode mode: Some hCaptcha deployments accept a passcode (static token) for testing environments. This is not exploitable in production.

Enterprise: hCaptcha Enterprise provides additional fraud signals and risk scoring. From a solver API standpoint, the submission format is the same as standard hCaptcha.

Solver Support for hCaptcha

Solver hCaptcha Support Success Rate Avg Solve Time Notes
CaptchaAI ✅ Full ~95–97% 8–15s Highest hCaptcha success rate per CaptchaRank benchmark
NopeCHA ✅ Full ~89–93% 10–20s Purpose-built for hCaptcha; browser extension + API
2Captcha ✅ Full ~90–94% 15–25s Reliable at scale; 2Captcha-format compatible
Anti-Captcha ✅ Full ~90–93% 14–22s Human workers; consistent but slower
CapSolver ✅ Full ~92–95% 10–18s Good API-first option
CapMonster Cloud ✅ Full ~87–92% 12–20s Affordable; slightly lower accuracy
DeathByCaptcha ✅ Partial ~82–88% 20–35s Legacy support; not recommended for hCaptcha at volume

Success rates are based on CaptchaRank benchmark data and publicly reported signals. hCaptcha challenge difficulty varies by site configuration.

How to Solve hCaptcha in Python

Step 1 — Extract the Sitekey

import re
import requests

def get_hcaptcha_sitekey(page_url: str) -> str:
    """Extract the hCaptcha sitekey from a page."""
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
    html = requests.get(page_url, headers=headers).text

    patterns = [
        r'data-sitekey=["\']([0-9a-f\-]{36})["\']',
        r'"sitekey"\s*:\s*"([0-9a-f\-]{36})"',
        r'hcaptcha.*?sitekey["\s:=]+["\']([0-9a-f\-]{36})["\']',
    ]
    for pattern in patterns:
        match = re.search(pattern, html, re.IGNORECASE)
        if match:
            return match.group(1)

    raise ValueError("hCaptcha sitekey not found on page")

Step 2 — Solve via CaptchaAI

import requests
import time

def solve_hcaptcha(
    api_key: str,
    page_url: str,
    sitekey: str,
) -> str:
    """
    Solve hCaptcha using CaptchaAI (2Captcha-compatible API).
    Returns the h-captcha-response token.
    """
    payload = {
        "key": api_key,
        "method": "hcaptcha",
        "sitekey": sitekey,
        "pageurl": page_url,
        "json": 1,
    }

    r = requests.post("https://ocr.captchaai.com/in.php", data=payload, timeout=30)
    r.raise_for_status()
    result = r.json()
    if result.get("status") != 1:
        raise RuntimeError(f"Submit failed: {result}")
    task_id = result["request"]

    time.sleep(7)
    for _ in range(24):
        r = requests.get(
            "https://ocr.captchaai.com/res.php",
            params={"key": api_key, "action": "get", "id": task_id, "json": 1},
            timeout=30,
        )
        data = r.json()
        if data.get("status") == 1:
            return data["request"]  # h-captcha-response token
        time.sleep(5)

    raise TimeoutError("hCaptcha solve timed out")

Step 3 — Inject Token and Submit

from playwright.sync_api import sync_playwright

def submit_form_with_hcaptcha(
    page_url: str,
    sitekey: str,
    api_key: str,
) -> None:
    token = solve_hcaptcha(api_key, page_url, sitekey)

    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        page.goto(page_url, wait_until="networkidle")

        # Inject token into the hidden textarea hCaptcha uses
        page.evaluate(f"""
            const r = document.querySelector('[name="h-captcha-response"]');
            if (r) r.value = '{token}';
            // hCaptcha also sets a second field in some implementations
            document.querySelectorAll('textarea[name="h-captcha-response"]')
                .forEach(t => t.value = '{token}');
        """)

        # Trigger hCaptcha's success callback so the form submit button activates
        page.evaluate("""
            if (window.hcaptcha && window.hcaptcha.getResponse) {
                // Patch the callback if it exists
            }
        """)

        page.click('button[type="submit"]')
        page.wait_for_load_state("networkidle")
        browser.close()

Using 2Captcha as Drop-In Alternative

# Change the host only — all parameters are identical
r = requests.post("https://2captcha.com/in.php", data=payload, timeout=30)

hCaptcha vs reCAPTCHA v2 — Key Differences for Developers

Dimension hCaptcha reCAPTCHA v2
Hidden field name h-captcha-response g-recaptcha-response
Sitekey format UUID (8-4-4-4-12) Long alphanumeric string
Challenge content Labeled image data Google Street View / object detection
Privacy stance No Google tracking Google analytics integration
Solver method param hcaptcha userrecaptcha
Typical solve time 8–20s 8–25s

The API submission pattern is nearly identical — swap the method parameter and the field name.

Common Errors and Fixes

ERROR_ZERO_CAPTCHA_FILESIZE The sitekey was not passed or was empty. Always extract the sitekey at runtime.

Token rejected with "invalid-or-already-seen-response" The token was used more than once, or it expired. hCaptcha tokens are single-use and expire in ~2 minutes. Generate a fresh token per submission.

Submit succeeds but the form shows "verification failed" The site uses hCaptcha Enterprise with a stricter score threshold. Some automation IPs receive hard challenges or lower scores. Consider using a residential proxy for the page request (not the solver request).

Token injected but form submit button stays disabled Some implementations rely on the hCaptcha JS callback to enable the submit button. After injecting the token, trigger the callback:

page.evaluate("""
    const callbacks = window.hcaptcha._callbacks || {};
    Object.values(callbacks).forEach(fn => {
        if (typeof fn === 'function') fn('{token}');
    });
""")

When to Use Which Solver

Scenario Recommended Solver Reason
General hCaptcha automation CaptchaAI Highest benchmark success rate for hCaptcha
hCaptcha-specific at scale NopeCHA Purpose-built; strong on standard hCaptcha
Multi-type pipelines (reCAPTCHA + hCaptcha + others) 2Captcha Single API, all types, reliable worker pool
Cost-sensitive bulk solving CapMonster Cloud Competitive pricing
API-first / no legacy format CapSolver Clean JSON API

Explore More in This Hub


Benchmark data sourced from CaptchaRank live performance monitoring. Success rates reflect current data and are updated as solver performance changes.

Comments are disabled for this article.

Related Posts

FunCaptcha / Arkose Labs FunCaptcha (Arkose Labs) — Complete Solving Guide
Everything developers need to know about Fun Captcha (Arkose Labs): how it works, which solvers support it, working Python code, and a decision guide for choosi...

Everything developers need to know about Fun Captcha (Arkose Labs): how it works, which solvers support it, wo...

May 03, 2026
GeeTest GeeTest CAPTCHA Guide — v3, v4, and How to Solve Them
Complete guide to Gee Test CAPTCHA for developers — covers Gee Test v 3 (slide puzzle) and v 4 (adaptive), solver support, working Python code, and a ranked sol...

Complete guide to Gee Test CAPTCHA for developers — covers Gee Test v 3 (slide puzzle) and v 4 (adaptive), sol...

May 03, 2026