hCaptcha is one of the most common CAPTCHAs used by high-traffic sites — Cloudflare, Discord, Epic Games, and many others rely on it. If you're automating browser interactions with Python using Selenium or Playwright, hCaptcha will block you. This guide shows you how to solve it programmatically.
Why hCaptcha is hard to bypass with Selenium
Unlike reCAPTCHA v2's checkbox, hCaptcha presents an image classification challenge (select all images with X). It also runs browser fingerprinting checks that flag common Selenium and Playwright signatures. You need two things:
- A token-based solver that returns a valid
h-captcha-responsetoken - A way to inject that token into the page before submitting
Solving hCaptcha with Python + Selenium
Install dependencies
pip install selenium ocilar # Also install ChromeDriver matching your Chrome version
Basic flow
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
from ocilar import OcilarClient
import time
client = OcilarClient(api_key="sk-your_key")
options = webdriver.ChromeOptions()
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
driver = webdriver.Chrome(options=options)
try:
driver.get("https://example.com/signup")
# Find the hCaptcha sitekey on the page
captcha_el = driver.find_element(By.CSS_SELECTOR, ".h-captcha")
sitekey = captcha_el.get_attribute("data-sitekey")
page_url = driver.current_url
# Solve hCaptcha via Ocilar
result = client.solve_hcaptcha(
sitekey=sitekey,
page_url=page_url
)
# Inject the token into the page
driver.execute_script(
"document.querySelector('[name=h-captcha-response]').value = arguments[0];"
"document.querySelector('[name=g-recaptcha-response]').value = arguments[0];",
result.token
)
# Submit the form
driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
print("Form submitted successfully")
finally:
driver.quit() Solving hCaptcha with Python + Playwright
import asyncio
from playwright.async_api import async_playwright
from ocilar import OcilarClient
client = OcilarClient(api_key="sk-your_key")
async def solve_hcaptcha_playwright():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
await page.goto("https://example.com/signup")
# Get sitekey from the hCaptcha widget
sitekey = await page.get_attribute(".h-captcha", "data-sitekey")
page_url = page.url
# Solve via Ocilar (takes ~5-15s)
result = client.solve_hcaptcha(
sitekey=sitekey,
page_url=page_url
)
# Inject token
token = result.token
await page.evaluate(
"(t) => { document.querySelector('[name=\"h-captcha-response\"]').value = t; "
"document.querySelector('[name=\"g-recaptcha-response\"]').value = t; }",
token
)
# Click submit
await page.click("button[type=submit]")
await page.wait_for_load_state("networkidle")
print("Done:", page.url)
await browser.close()
asyncio.run(solve_hcaptcha_playwright()) cURL example
curl -X POST https://api.ocilar.com/api/v1/solve/hcaptcha \
-H "X-API-Key: sk-your_key" \
-H "Content-Type: application/json" \
-d '{
"sitekey": "a5f74b19-9e45-40e0-b45d-47ff91b7a6c2",
"page_url": "https://example.com/signup"
}'
# Response
{
"token": "P1_eyJ0...(long token)...",
"latency_ms": 8200,
"credits_used": 1
} Node.js example
import { chromium } from 'playwright'
import { OcilarClient } from '@ocilar/sdk'
const client = new OcilarClient({ apiKey: 'sk-your_key' })
const browser = await chromium.launch({ headless: true })
const page = await browser.newPage()
await page.goto('https://example.com/signup')
const sitekey = await page.getAttribute('.h-captcha', 'data-sitekey')
const { token } = await client.solveHcaptcha({
sitekey,
pageUrl: page.url()
})
await page.evaluate((t) => {
document.querySelector('[name="h-captcha-response"]').value = t
document.querySelector('[name="g-recaptcha-response"]').value = t
}, token)
await page.click('button[type="submit"]')
await browser.close() Handling retries
hCaptcha tokens expire after ~2 minutes and have a ~5% failure rate on all solvers. Build retry logic:
from ocilar import OcilarClient
from ocilar.exceptions import SolveFailedError
import time
client = OcilarClient(api_key="sk-your_key")
def solve_with_retry(sitekey: str, page_url: str, max_retries: int = 3) -> str:
for attempt in range(max_retries):
try:
result = client.solve_hcaptcha(sitekey=sitekey, page_url=page_url)
return result.token
except SolveFailedError:
if attempt < max_retries - 1:
time.sleep(2)
continue
raise
raise RuntimeError("Max retries exceeded") Common issues
Token injected but form still blocked
Some sites check that hCaptcha fires its callback. After injecting the token, trigger the callback manually:
driver.execute_script("""
if (window.hcaptcha && window.hcaptcha.execute) {
// Force callback with the token
document.querySelector('[name="h-captcha-response"]').value = arguments[0];
}
""", token) Selenium detected before CAPTCHA loads
Use undetected-chromedriver to avoid Selenium fingerprinting:
pip install undetected-chromedriver
import undetected_chromedriver as uc
driver = uc.Chrome(headless=True)
driver.get("https://example.com") Pricing
hCaptcha solving costs $1.00 per 1,000 solves. No subscription required — pay as you go.
| Service | hCaptcha support | Price / 1K | Avg latency |
|---|---|---|---|
| 2Captcha | Yes | $2.99 | ~20s |
| CapSolver | Yes | $1.80 | ~15s |
| Ocilar | Yes | $1.00 | ~8s |
FAQ
How long does it take to solve hCaptcha?
Average 6–12 seconds depending on challenge difficulty. Ocilar uses AI workers that solve the image classification challenges automatically.
Does Ocilar support hCaptcha Enterprise?
Yes. Pass the additional rqdata parameter if the site uses hCaptcha Enterprise with custom challenge data.
Will this work with async Selenium?
Selenium itself is synchronous. Use Playwright's async API for fully async automation with hCaptcha solving.
Can I solve hCaptcha on sites that also use Cloudflare bot protection?
You'll need to handle Cloudflare separately. Ocilar's Turnstile solver handles Cloudflare's own CAPTCHA. For layered protection, contact us for a custom solution.