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:
- The page loads
https://hcaptcha.com/1/api.js. - The JS widget initializes using a sitekey (a UUID, e.g.
10000000-ffff-ffff-ffff-000000000001— the public test key). - The user (or solver) completes the image challenge.
- On success, the JS writes a signed
h-captcha-responsetoken to a hidden form field. - 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
- Best hCaptcha Solver — ranked comparison of all solvers with pricing and notes
- CAPTCHA Solver API Integration Guide — language-agnostic patterns
- CAPTCHA Solving in Python: Quick Start — 30-minute setup guide covering multiple types
- Best CAPTCHA Solvers Ranked — full leaderboard across all CAPTCHA types
Benchmark data sourced from CaptchaRank live performance monitoring. Success rates reflect current data and are updated as solver performance changes.