This guide gets you solving CAPTCHAs in Python in under 30 minutes. It covers installation, basic reCAPTCHA v2 solving, and integration with Playwright for browser-based automation.
Installation
pip install requests playwright
playwright install chromium
For async patterns:
pip install aiohttp
Solving reCAPTCHA v2 in 15 Lines
Using CaptchaAI (compatible with 2Captcha format):
import requests, time
def solve_recaptcha_v2(api_key, page_url, site_key):
# Submit
r = requests.post("https://ocr.captchaai.com/in.php", data={
"key": api_key, "method": "userrecaptcha",
"googlekey": site_key, "pageurl": page_url, "json": 1,
})
task_id = r.json()["request"]
# Poll
time.sleep(5)
for _ in range(24):
r = requests.get("https://ocr.captchaai.com/res.php", params={
"key": api_key, "action": "get", "id": task_id, "json": 1,
})
if r.json()["status"] == 1:
return r.json()["request"]
time.sleep(5)
raise TimeoutError("Timed out")
token = solve_recaptcha_v2("YOUR_KEY", "https://example.com", "SITE_KEY")
print("Token:", token[:30], "...")
Finding the Site Key
import re, requests
def get_sitekey(url):
html = requests.get(url, headers={"User-Agent": "Mozilla/5.0"}).text
m = re.search(r'data-sitekey=["\']([^"\']+)["\']', html)
return m.group(1) if m else None
sitekey = get_sitekey("https://target-site.com/form")
print("Site key:", sitekey)
Injecting Token with Playwright
from playwright.sync_api import sync_playwright
def submit_form_with_captcha(url, sitekey, api_key):
token = solve_recaptcha_v2(api_key, url, sitekey)
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto(url)
# Inject token
page.evaluate(f"""
document.getElementById('g-recaptcha-response').value = '{token}';
document.querySelector('[name="g-recaptcha-response"]').value = '{token}';
""")
# Submit form
page.click('button[type="submit"]')
page.wait_for_load_state("networkidle")
result = page.content()
browser.close()
return result
Cloudflare Turnstile
def solve_cloudflare_turnstile(api_key, page_url, site_key):
r = requests.post("https://ocr.captchaai.com/in.php", data={
"key": api_key, "method": "turnstile",
"sitekey": site_key, "pageurl": page_url, "json": 1,
})
task_id = r.json()["request"]
time.sleep(5)
for _ in range(20):
r = requests.get("https://ocr.captchaai.com/res.php", params={
"key": api_key, "action": "get", "id": task_id, "json": 1,
})
if r.json()["status"] == 1:
return r.json()["request"]
time.sleep(5)
raise TimeoutError("Timed out")
# Inject Turnstile token
def inject_turnstile_token(page, token):
page.evaluate(f"""
document.querySelector('[name="cf-turnstile-response"]').value = '{token}';
""")
hCaptcha
def solve_hcaptcha(api_key, page_url, site_key):
r = requests.post("https://ocr.captchaai.com/in.php", data={
"key": api_key, "method": "hcaptcha",
"sitekey": site_key, "pageurl": page_url, "json": 1,
})
task_id = r.json()["request"]
time.sleep(5)
for _ in range(24):
r = requests.get("https://ocr.captchaai.com/res.php", params={
"key": api_key, "action": "get", "id": task_id, "json": 1,
})
if r.json()["status"] == 1:
return r.json()["request"]
time.sleep(5)
raise TimeoutError("Timed out")
# Inject hCaptcha token
def inject_hcaptcha_token(page, token):
page.evaluate(f"""
document.querySelector('[name="h-captcha-response"]').value = '{token}';
""")
reCAPTCHA v3
def solve_recaptcha_v3(api_key, page_url, site_key, action="verify", min_score=0.7):
r = requests.post("https://ocr.captchaai.com/in.php", data={
"key": api_key, "method": "userrecaptcha",
"version": "v3", "googlekey": site_key,
"pageurl": page_url, "action": action,
"min_score": min_score, "json": 1,
})
task_id = r.json()["request"]
time.sleep(7)
for _ in range(20):
r = requests.get("https://ocr.captchaai.com/res.php", params={
"key": api_key, "action": "get", "id": task_id, "json": 1,
})
if r.json()["status"] == 1:
return r.json()["request"]
time.sleep(5)
raise TimeoutError("Timed out")
Anti-Captcha JSON Format Alternative
If your provider uses the Anti-Captcha JSON format (Anti-Captcha, CapMonster Cloud):
def solve_recaptcha_v2_anticaptcha(api_key, page_url, site_key,
base_url="https://api.anti-captcha.com"):
import requests, time
r = requests.post(f"{base_url}/createTask", json={
"clientKey": api_key,
"task": {
"type": "RecaptchaV2TaskProxyless",
"websiteURL": page_url,
"websiteKey": site_key,
},
})
task_id = r.json()["taskId"]
time.sleep(5)
for _ in range(24):
r = requests.post(f"{base_url}/getTaskResult", json={
"clientKey": api_key, "taskId": task_id,
})
data = r.json()
if data["status"] == "ready":
return data["solution"]["gRecaptchaResponse"]
time.sleep(5)
raise TimeoutError("Timed out")
# To use with CapMonster Cloud, just change base_url:
# solve_recaptcha_v2_anticaptcha(key, url, sitekey, base_url="https://api.capmonster.cloud")
Full Example: Scrape a reCAPTCHA-Protected Page
import re, requests, time
from playwright.sync_api import sync_playwright
API_KEY = "YOUR_API_KEY" # Load from environment in production
def scrape_protected_page(url):
# 1. Get page and extract sitekey
html = requests.get(url, headers={"User-Agent": "Mozilla/5.0"}).text
m = re.search(r'data-sitekey=["\']([^"\']+)["\']', html)
if not m:
raise ValueError("No reCAPTCHA found on page")
sitekey = m.group(1)
# 2. Solve CAPTCHA
token = solve_recaptcha_v2(API_KEY, url, sitekey)
# 3. Use token with Playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto(url)
page.evaluate(f'document.getElementById("g-recaptcha-response").value = "{token}"')
page.click('button[type="submit"]')
page.wait_for_load_state("networkidle")
content = page.content()
browser.close()
return content
result = scrape_protected_page("https://example.com/protected-form")
print("Success, got", len(result), "bytes")
Environment Variables Best Practice
Never hardcode API keys:
import os
API_KEY = os.environ.get("CAPTCHA_API_KEY")
if not API_KEY:
raise EnvironmentError("CAPTCHA_API_KEY environment variable not set")
Set in your shell:
# Windows
set CAPTCHA_API_KEY=your_key_here
# macOS/Linux
export CAPTCHA_API_KEY=your_key_here
FAQ
Which provider should I use for this quick start?
Any provider with a 2Captcha-compatible API works with the examples above. Change the endpoint URL and API key. CaptchaAI's endpoint (https://ocr.captchaai.com) is used in examples because it has the highest success rate in current benchmarks.
Why do my tokens expire before I can use them? The token must be injected and the form submitted within ~2 minutes of the solve completing. Reduce processing between solve and injection.
Can I use these patterns with Selenium?
Yes. Replace page.evaluate(...) with driver.execute_script(...) and the rest of the pattern is the same.
What if the site uses a custom CAPTCHA widget? Inspect the form's hidden input fields. Most custom widgets still submit a standard token. Identify the field name and inject accordingly.
See provider rankings at captcharank.com/solvers.
Production Readiness Notes
Use Quick Start — CAPTCHA Solving in Python as a decision and implementation aid, not just as a one-time reference. The practical test for captcha solving python quick start is whether the same approach behaves reliably when traffic is messy: rotating sessions, expired tokens, changing widget parameters, intermittent solver delays, and target pages that refresh without warning. For Automation developer, the safest rollout is to start with a narrow fixture, record every submitted task, and compare the solver response with the browser state that finally submits the form. That makes failures explainable instead of mysterious, especially when a target alternates between visible challenges, invisible checks, and server-side verification.
Evaluation Criteria
A developer guide should become a reusable integration module with typed configuration, bounded polling, structured errors, and a single place for API credentials. For developer integration work, the most useful scorecard combines technical acceptance with operational cost. A low nominal price is not enough if retries double the real cost per accepted token, and a fast median solve time is not enough if p95 latency stalls the queue. Track these criteria before you standardize the workflow:
- The challenge subtype, sitekey, action, rqdata, blob, captchaId, or page URL used for each task.
- Median and p95 solve time, separated by provider and target domain.
- Accepted-token rate on the target page, not just successful API responses.
- Retry count, timeout count, zero-balance incidents, and invalid-parameter errors.
- The exact browser, proxy region, and user-agent that submitted the solved token.
Rollout Checklist
Before this guidance moves into a production job, build a small acceptance suite around the pages that matter most. Run it with a fixed browser profile, then repeat with the proxy and concurrency settings you expect in production. Keep the first release conservative: bounded polling, clear timeout handling, and a fallback path when the solver cannot return a usable answer. For developer integration, treat the code as a production pattern: timeouts, retries, logging, secret storage, and test fixtures matter as much as the solve request itself. That checklist keeps the article useful after the first copy-paste, because the integration is judged by end-to-end completion rather than by whether a code sample returned a string.
Monitoring Signals
Healthy CAPTCHA automation is observable. Log the task id, provider, challenge type, target host, queue time, solve time, final submit status, and normalized error code for every attempt. Review those logs in daily batches at first, then move to alerts once the baseline is stable. Sudden drops usually come from target-side changes: a new sitekey, a changed action name, a stricter hostname check, an added managed challenge, or a proxy pool that no longer matches the expected geography. When you can see those shifts quickly, provider switching becomes a controlled decision instead of a late-night rewrite.
Maintenance Cadence
Revisit the setup whenever the target UI changes, when the solver provider changes task names or pricing, or when benchmark data shows a sustained latency or solve-rate shift. Keep one known-good fixture for each CAPTCHA subtype and rerun it after dependency upgrades, browser updates, and proxy changes. If the article is used for vendor selection, repeat the same fixture across at least two providers before renewing a balance or migrating the whole pipeline. That habit keeps captcha solving python quick start work aligned with the real target behavior rather than with stale assumptions.