Python's requests library is the most common HTTP client for automation. This guide shows you exactly how to solve reCAPTCHA v2 challenges using requests and CaptchaAI's API — from extracting the sitekey to submitting the solved token.
Prerequisites
pip install requests
You need:
- A CaptchaAI API key from captchaai.com
- The target page URL
- The reCAPTCHA sitekey (we'll show how to extract it)
Step 1: Extract the reCAPTCHA sitekey
Every reCAPTCHA v2 widget has a sitekey embedded in the page HTML:
import re
import requests
def extract_recaptcha_sitekey(url):
"""Extract reCAPTCHA v2 sitekey from page HTML."""
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/120.0.0.0",
}
response = requests.get(url, headers=headers, timeout=15)
# Pattern 1: data-sitekey attribute
match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]{40})["\']', response.text)
if match:
return match.group(1)
# Pattern 2: grecaptcha.render config
match = re.search(r"sitekey['\"]?\s*:\s*['\"]([A-Za-z0-9_-]{40})['\"]", response.text)
if match:
return match.group(1)
# Pattern 3: reCAPTCHA API URL parameter
match = re.search(r"google\.com/recaptcha/api\.js\?.*?render=([A-Za-z0-9_-]{40})", response.text)
if match:
return match.group(1)
return None
# Usage
sitekey = extract_recaptcha_sitekey("https://example.com/login")
print(f"Sitekey: {sitekey}")
Step 2: Submit to CaptchaAI
Send the sitekey and page URL to CaptchaAI:
import requests
API_KEY = "YOUR_API_KEY"
def submit_recaptcha(sitekey, page_url):
"""Submit reCAPTCHA v2 solving task to CaptchaAI."""
response = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"json": 1,
})
data = response.json()
if data.get("status") != 1:
raise Exception(f"Submit failed: {data.get('request', 'Unknown error')}")
return data["request"] # Task ID
task_id = submit_recaptcha("6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-", "https://example.com/login")
print(f"Task ID: {task_id}")
Step 3: Poll for the result
CaptchaAI solves the challenge in the background. Poll every 5 seconds:
import time
def poll_result(task_id, timeout=120):
"""Poll CaptchaAI for the solved token."""
start = time.time()
while time.time() - start < timeout:
time.sleep(5)
response = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
})
data = response.json()
if data.get("status") == 1:
return data["request"] # Solved token
if data.get("request") == "ERROR_CAPTCHA_UNSOLVABLE":
raise Exception("CAPTCHA could not be solved")
if data.get("request") != "CAPCHA_NOT_READY":
raise Exception(f"Unexpected response: {data}")
raise TimeoutError(f"Solve timed out after {timeout}s")
token = poll_result(task_id)
print(f"Token: {token[:50]}...")
Complete working example
Full end-to-end code that extracts, solves, and submits:
import re
import time
import requests
API_KEY = "YOUR_API_KEY"
TARGET_URL = "https://example.com/login"
def extract_sitekey(url, session):
"""Extract reCAPTCHA v2 sitekey from the page."""
response = session.get(url, timeout=15)
match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]{40})["\']', response.text)
if not match:
raise ValueError("reCAPTCHA sitekey not found on page")
return match.group(1)
def solve_recaptcha(sitekey, page_url):
"""Submit and poll CaptchaAI for reCAPTCHA v2 solution."""
# Submit
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"json": 1,
})
data = submit.json()
if data.get("status") != 1:
raise Exception(f"Submit error: {data.get('request')}")
task_id = data["request"]
print(f"Task submitted: {task_id}")
# Poll
for attempt in range(30):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
}).json()
if result.get("status") == 1:
return result["request"]
if result.get("request") == "ERROR_CAPTCHA_UNSOLVABLE":
raise Exception("Unsolvable CAPTCHA")
raise TimeoutError("Solve timed out")
def submit_form_with_token(session, form_url, token, extra_data=None):
"""Submit the form with the solved reCAPTCHA token."""
form_data = {
"g-recaptcha-response": token,
}
if extra_data:
form_data.update(extra_data)
response = session.post(form_url, data=form_data, timeout=15)
return response
# --- Main flow ---
session = requests.Session()
session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/120.0.0.0",
"Accept": "text/html,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
})
# 1. Get the page and extract sitekey
sitekey = extract_sitekey(TARGET_URL, session)
print(f"Sitekey: {sitekey}")
# 2. Solve reCAPTCHA
token = solve_recaptcha(sitekey, TARGET_URL)
print(f"Token received: {token[:50]}...")
# 3. Submit form with token
response = submit_form_with_token(session, TARGET_URL, token, {
"username": "user@example.com",
"password": "password123",
})
print(f"Form submission status: {response.status_code}")
Error handling patterns
Common API errors
| Error | Meaning | Fix |
|---|---|---|
ERROR_WRONG_USER_KEY |
Invalid API key | Check your API key |
ERROR_ZERO_BALANCE |
Account balance is zero | Add funds |
ERROR_CAPTCHA_UNSOLVABLE |
Could not solve this CAPTCHA | Retry with new task |
ERROR_TOO_MUCH_REQUESTS |
Sending tasks too fast | Add delay between submissions |
ERROR_WRONG_GOOGLEKEY |
Invalid sitekey | Re-extract from page |
ERROR_PAGEURL |
Invalid page URL | Ensure URL is complete (https://) |
Production-ready error handling
import time
import requests
API_KEY = "YOUR_API_KEY"
class RecaptchaSolveError(Exception):
pass
def solve_recaptcha_v2(sitekey, page_url, max_retries=3):
"""Solve reCAPTCHA v2 with retry logic."""
for attempt in range(1, max_retries + 1):
try:
# Submit
submit = requests.post(
"https://ocr.captchaai.com/in.php",
data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"json": 1,
},
timeout=30,
)
submit.raise_for_status()
submit_data = submit.json()
if submit_data.get("status") != 1:
error = submit_data.get("request", "Unknown")
if error in ("ERROR_WRONG_USER_KEY", "ERROR_ZERO_BALANCE"):
raise RecaptchaSolveError(f"Fatal error: {error}")
raise RecaptchaSolveError(f"Submit error: {error}")
task_id = submit_data["request"]
# Poll
for _ in range(30):
time.sleep(5)
result = requests.get(
"https://ocr.captchaai.com/res.php",
params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
},
timeout=30,
).json()
if result.get("status") == 1:
return result["request"]
if result.get("request") == "ERROR_CAPTCHA_UNSOLVABLE":
break # Retry with new task
print(f"Attempt {attempt} failed, retrying...")
except requests.RequestException as e:
print(f"Network error on attempt {attempt}: {e}")
if attempt == max_retries:
raise RecaptchaSolveError(f"Network error after {max_retries} attempts")
time.sleep(10)
raise RecaptchaSolveError(f"Failed after {max_retries} attempts")
Working with invisible reCAPTCHA v2
Invisible reCAPTCHA v2 works the same way — just add invisible=1:
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"invisible": 1, # Add this for invisible reCAPTCHA v2
"json": 1,
})
Token submission patterns
Different sites expect the token in different ways:
Pattern 1: Form POST (most common)
response = session.post(form_url, data={
"g-recaptcha-response": token,
"email": "user@example.com",
})
Pattern 2: JSON API
response = session.post(api_url, json={
"captchaToken": token,
"email": "user@example.com",
})
Pattern 3: Hidden field in HTML form
# Some sites use a different field name — check form HTML
response = session.post(form_url, data={
"g-recaptcha-response": token,
"recaptcha_token": token, # Some sites duplicate the field
"username": "user",
})
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| "Invalid sitekey" error | Sitekey extracted incorrectly | Verify against page source |
| Token accepted but form fails | Missing form fields | Submit all required form fields |
| Token rejected by server | Token expired (>120s) | Reduce time between solve and submit |
| "CAPCHA_NOT_READY" for >2 min | High queue load | Wait longer or retry |
| SSL certificate error | Corporate proxy or outdated certs | Add verify=False (dev only) |
Frequently asked questions
How long does solving take?
Typical solve time is 10-30 seconds. Invisible reCAPTCHA v2 is usually faster. Plan for up to 120 seconds in worst case.
Can I use this with reCAPTCHA v3?
No. reCAPTCHA v3 uses method=userrecaptcha but requires additional parameters (version=v3, min_score, action). See the reCAPTCHA v3 guide.
Do I need to maintain a session?
Yes. Using requests.Session() preserves cookies between requests, which is important for sites that validate the reCAPTCHA token against the session.
How fast can I submit tasks?
CaptchaAI has no published rate limit per key, but submitting more than 10 tasks per second may trigger ERROR_TOO_MUCH_REQUESTS. Add a 100ms delay between submissions for safety.
Summary
Solving reCAPTCHA v2 with Python requests and CaptchaAI is a three-step process: extract the sitekey from the page, submit to CaptchaAI's userrecaptcha method, and poll for the token. Use requests.Session() for cookie persistence and submit the token as g-recaptcha-response in your form POST.
Discussions (0)
Join the conversation
Sign in to share your opinion.
Sign InNo comments yet.