Create CAPTCHA tasks, poll results and manage integrations through a compact JSON API.
Base URLhttps://solvecaptcha.net/api
JSON requests Bearer authentication Poll every 2 seconds
Quick start
One API, consistent task lifecycle
Authenticate with your API key, submit a task, then request its result until the response is ready.
01Create a task
02Store the task ID
03Poll for the result
Request limits
account-level API throughput and upgrade guidance
Each account has a default combined limit of 10 requests per second
across createTask, getTaskResult and getBalance.
Administrators may assign a different account limit when additional throughput is approved.
When the limit is exceeded
The API returns HTTP 429 Too Many Requests with the error code
ERROR_TOO_MANY_REQUESTS. Respect the Retry-After response header
before retrying. For task results, keep a polling interval of at least 2 seconds and use
backoff if a 429 response is returned.
Requesting a higher limit
If your integration requires more than 10 requests per second, contact our support team
before increasing traffic. Include your account email, expected requests per second,
the API methods used and your expected peak hours so the team can review capacity.
Contact: admin@solvecaptcha.net.
Unlimited accounts
An administrator can remove the per-account application limit for approved use cases.
This does not remove infrastructure safeguards, task-result polling protection or supplier limits.
Error example
HTTP 429
{
"error_id": 1,
"error_code": "ERROR_TOO_MANY_REQUESTS",
"error_description": "This account is limited to 10 requests per second.",
"limit_per_second": 10
}
createTask
create a captcha task
Address: https://solvecaptcha.net/api/createTask Method: POST Content-type: application-json
0 - no errors, the operation completed successfully.
Otherwise - error identifier. Error code and short description transferred in error_code and error_description properties.
error_code
String
error_description
String
Short description of the error
task_id
Integer
Response example
{
"error_id": 0,
"balance": 54.321
}
{
"error_id": 1,
"error_code": "ERROR_KEY_DOES_NOT_EXIST",
"error_description": "Account authorization key not found in the system"
}
Error Types
list of API Errors
Code
Description
ERROR_KEY_DOES_NOT_EXIST
Account authorization key not found in the system or has incorrect format (length is not )
ERROR_ZERO_CAPTCHA_FILESIZE
The size of the captcha you are uploading is less than 100 bytes
ERROR_TOO_BIG_CAPTCHA_FILESIZE
The size of the captcha you are uploading is more than 50,000 bytes
ERROR_ZERO_BALANCE
Account has zero balance
ERROR_IP_NOT_ALLOWED
Request with current account key is not allowed from your IP
ERROR_CAPTCHA_UNSOLVABLE
This type of captchas is not supported by the service or the image does not contain an answer, perhaps it is too noisy. It could also mean that the image is corrupted or was incorrectly rendered
ERROR_NO_SUCH_CAPCHA_ID, WRONG_CAPTCHA_ID
The captcha that you are requesting was not found. Make sure you are requesting a status update only within 5 minutes of uploading
CAPTCHA_NOT_READY
The captcha has not yet been solved
ERROR_IP_BANNED
You have exceeded the limit of requests with the wrong api key, check the correctness of your api key in the control panel and after some time, try again
ERROR_NO_SUCH_METHOD
This method is not supported or empty
ERROR_TOO_MUCH_REQUESTS
You have exceeded the limit of requests to receive an answer for one task. Try to request the result of the task no more than 1 time in 2 seconds
RecaptchaV2TaskProxyless
Solve reCAPTCHA V2 with built-in or customer proxy.
reCAPTCHA V2RecaptchaV2TaskProxyless
Identify → collect → submit
Collect the values from the current widget
Use DevTools on a page you are authorized to integrate. Static identifiers can be reused; values marked Fresh value must be captured again for every rendered challenge.
How to find all parameters required to create a task
Manually
Open the page in a browserLoad the page where the CAPTCHA appears, on a site you are authorised to integrate.
Inspect the CAPTCHA containerRight-click the widget and choose Inspect. Copy data-sitekey from the <div class="g-recaptcha"> element; copy data-s too when the page sets it.
Or read the sitekey from the networkIn Network, filter for recaptcha and open the anchor request: its k query parameter is the sitekey.
Find the action for score-based variantsSearch Sources for grecaptcha.execute; the action string passed there is page_action.
Note whether the widget is invisibleAn element carrying size="invisible" means you should send is_invisible: true.
Automatically
The first snippet reports the values. The two Playwright scripts collect them from a live page and solve them through this API in one run — replace YOUR_API_KEY and PAGE_URL.
paste into DevTools → Console
Run this on the page with the CAPTCHA. It prints the task body to copy into your request.
// RecaptchaV2TaskProxyless — collect the task parameters from this page.
// Paste into DevTools → Console on the page showing the CAPTCHA.
(() => {
const el = document.querySelector('.g-recaptcha[data-sitekey], [data-sitekey]');
const task = { method: "RecaptchaV2TaskProxyless", page_url: location.href, site_key: el?.getAttribute('data-sitekey') || null };
if (el?.getAttribute('data-s')) task.data_s = el.getAttribute('data-s');
if (el?.getAttribute('data-size') === 'invisible') task.is_invisible = true;
// Fall back to the anchor request, which always carries k=<sitekey>.
if (!task.site_key) {
const anchor = performance.getEntriesByType('resource')
.map((entry) => entry.name)
.find((name) => name.includes('/recaptcha/') && name.includes('k='));
if (anchor) task.site_key = new URL(anchor).searchParams.get('k');
}
console.log(JSON.stringify({ task }, null, 2));
return task;
})();
collect-and-solve.mjs
npm i playwright — collects the parameters from a live page and solves them through this API.
// RecaptchaV2TaskProxyless — collect the parameters from a live page, then solve them here.
// Requirements: npm i playwright · Run: node collect-and-solve.mjs
import { chromium } from 'playwright';
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const PAGE_URL = 'https://example.com/page-with-captcha';
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
async function collect(pageUrl) {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto(pageUrl);
await page.waitForTimeout(6000);
const collected = await page.evaluate(() => {
const el = document.querySelector('[data-sitekey], [data-captcha-id], [data-scene-id]');
return {
page_url: location.href,
user_agent: navigator.userAgent,
site_key: el
? el.getAttribute('data-sitekey') || el.getAttribute('data-captcha-id') || el.getAttribute('data-scene-id')
: null,
};
});
await browser.close();
// Fill in the metadata fields documented below before submitting.
return Object.fromEntries(Object.entries(collected).filter(([, value]) => value != null));
}
const task = { method: 'RecaptchaV2TaskProxyless', ...(await collect(PAGE_URL)) };
console.log('collected task:', JSON.stringify(task, null, 2));
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Keep at least three seconds between polls: the result endpoint is
// rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
# RecaptchaV2TaskProxyless — collect the parameters from a live page, then solve them here.
# Requirements: pip install playwright requests && playwright install chromium
# Run: python3 collect_and_solve.py
import sys
import time
import requests
from playwright.sync_api import sync_playwright
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
PAGE_URL = "https://example.com/page-with-captcha"
READ = """
() => {
const el = document.querySelector('[data-sitekey], [data-captcha-id], [data-scene-id]');
return {
page_url: location.href,
user_agent: navigator.userAgent,
site_key: el
? el.getAttribute('data-sitekey') || el.getAttribute('data-captcha-id') || el.getAttribute('data-scene-id')
: null,
};
}
"""
def collect(page_url):
"""Read the widget identifier, then add the metadata documented below."""
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto(page_url)
page.wait_for_timeout(6000)
collected = page.evaluate(READ)
browser.close()
return {key: value for key, value in collected.items() if value is not None}
task = {"method": "RecaptchaV2TaskProxyless", **collect(PAGE_URL)}
print("collected task:", task)
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Keep at least three seconds between polls: the result endpoint is
# rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
What each value is and where it lives
page_urlUsually stable
Page URL
Address bar / Network → Referer
Use the exact URL where the widget is initialized, without relying on a post-login redirect.
site_keyUsually stable
Site key
Elements → data-sitekey, or Network → k/sitekey
Inspect the CAPTCHA container first; if absent, inspect the widget iframe or initialization request.
data_sFresh value
data-s / rqdata
Elements → data-s, or initialization payload
This value can be short-lived; capture it for each rendered challenge.
is_invisibleUsually stable
Invisible widget
Elements → size="invisible"
Set true when the widget renders no checkbox and validates silently.
user_agentUsually stable
Browser User-Agent
Console → navigator.userAgent
Use the same browser identity when submitting the returned solution.
cookiesFresh value
Cookies
Application → Cookies / Network headers
Send only cookies required by the current CAPTCHA flow.
Address: https://solvecaptcha.net/api/createTask Method: POST Default provider task type: RecaptchaV2Task
Compatibility alias: this historical method remains accepted and is mapped internally to RecaptchaV2Task.
Response fields use snake_case. Token-based tasks include solution.token; existing reCAPTCHA integrations also continue to receive solution.gRecaptchaResponse.
Request properties
Property
Required
Purpose
method
Yes
RecaptchaV2TaskProxyless
page_url
Yes
Value extracted from the target CAPTCHA page.
site_key
Yes
Value extracted from the target CAPTCHA page.
data_s
No
Optional task-specific value.
is_invisible
No
Optional task-specific value.
user_agent
No
Optional task-specific value.
cookies
No
Optional task-specific value.
proxy_type, proxy_address, proxy_port
No
Use a customer proxy when the target rejects built-in provider proxies.
Working example
Replace YOUR_API_KEY with the key from your account settings and the uppercase placeholders with the values you collected above. Each snippet creates the task, polls until it is solved and prints the solution.
# Requirements: pip install requests
# Run: python3 solve.py
import sys
import time
import requests
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
task = {
"method": "RecaptchaV2TaskProxyless",
"page_url": "PAGE_URL",
"site_key": "SITE_KEY"
}
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Poll until the task leaves the processing state. Keep at least three
# seconds between calls: the result endpoint is rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
solve.mjs
// Requirements: Node.js 18 or newer (uses the built-in fetch)
// Run: node solve.mjs
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const task = {
"method": "RecaptchaV2TaskProxyless",
"page_url": "PAGE_URL",
"site_key": "SITE_KEY"
};
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Poll until the task leaves the processing state. Keep at least three
// seconds between calls: the result endpoint is rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
RecaptchaV2Task
Solve reCAPTCHA V2 with built-in or customer proxy.
reCAPTCHA V2RecaptchaV2Task
Identify → collect → submit
Collect the values from the current widget
Use DevTools on a page you are authorized to integrate. Static identifiers can be reused; values marked Fresh value must be captured again for every rendered challenge.
How to find all parameters required to create a task
Manually
Open the page in a browserLoad the page where the CAPTCHA appears, on a site you are authorised to integrate.
Inspect the CAPTCHA containerRight-click the widget and choose Inspect. Copy data-sitekey from the <div class="g-recaptcha"> element; copy data-s too when the page sets it.
Or read the sitekey from the networkIn Network, filter for recaptcha and open the anchor request: its k query parameter is the sitekey.
Find the action for score-based variantsSearch Sources for grecaptcha.execute; the action string passed there is page_action.
Note whether the widget is invisibleAn element carrying size="invisible" means you should send is_invisible: true.
Automatically
The first snippet reports the values. The two Playwright scripts collect them from a live page and solve them through this API in one run — replace YOUR_API_KEY and PAGE_URL.
paste into DevTools → Console
Run this on the page with the CAPTCHA. It prints the task body to copy into your request.
// RecaptchaV2Task — collect the task parameters from this page.
// Paste into DevTools → Console on the page showing the CAPTCHA.
(() => {
const el = document.querySelector('.g-recaptcha[data-sitekey], [data-sitekey]');
const task = { method: "RecaptchaV2Task", page_url: location.href, site_key: el?.getAttribute('data-sitekey') || null };
if (el?.getAttribute('data-s')) task.data_s = el.getAttribute('data-s');
if (el?.getAttribute('data-size') === 'invisible') task.is_invisible = true;
// Fall back to the anchor request, which always carries k=<sitekey>.
if (!task.site_key) {
const anchor = performance.getEntriesByType('resource')
.map((entry) => entry.name)
.find((name) => name.includes('/recaptcha/') && name.includes('k='));
if (anchor) task.site_key = new URL(anchor).searchParams.get('k');
}
console.log(JSON.stringify({ task }, null, 2));
return task;
})();
collect-and-solve.mjs
npm i playwright — collects the parameters from a live page and solves them through this API.
// RecaptchaV2Task — collect the parameters from a live page, then solve them here.
// Requirements: npm i playwright · Run: node collect-and-solve.mjs
import { chromium } from 'playwright';
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const PAGE_URL = 'https://example.com/page-with-captcha';
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
async function collect(pageUrl) {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto(pageUrl);
await page.waitForTimeout(6000);
const collected = await page.evaluate(() => {
const el = document.querySelector('[data-sitekey], [data-captcha-id], [data-scene-id]');
return {
page_url: location.href,
user_agent: navigator.userAgent,
site_key: el
? el.getAttribute('data-sitekey') || el.getAttribute('data-captcha-id') || el.getAttribute('data-scene-id')
: null,
};
});
await browser.close();
// Fill in the metadata fields documented below before submitting.
return Object.fromEntries(Object.entries(collected).filter(([, value]) => value != null));
}
const task = { method: 'RecaptchaV2Task', ...(await collect(PAGE_URL)) };
console.log('collected task:', JSON.stringify(task, null, 2));
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Keep at least three seconds between polls: the result endpoint is
// rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
# RecaptchaV2Task — collect the parameters from a live page, then solve them here.
# Requirements: pip install playwright requests && playwright install chromium
# Run: python3 collect_and_solve.py
import sys
import time
import requests
from playwright.sync_api import sync_playwright
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
PAGE_URL = "https://example.com/page-with-captcha"
READ = """
() => {
const el = document.querySelector('[data-sitekey], [data-captcha-id], [data-scene-id]');
return {
page_url: location.href,
user_agent: navigator.userAgent,
site_key: el
? el.getAttribute('data-sitekey') || el.getAttribute('data-captcha-id') || el.getAttribute('data-scene-id')
: null,
};
}
"""
def collect(page_url):
"""Read the widget identifier, then add the metadata documented below."""
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto(page_url)
page.wait_for_timeout(6000)
collected = page.evaluate(READ)
browser.close()
return {key: value for key, value in collected.items() if value is not None}
task = {"method": "RecaptchaV2Task", **collect(PAGE_URL)}
print("collected task:", task)
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Keep at least three seconds between polls: the result endpoint is
# rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
What each value is and where it lives
page_urlUsually stable
Page URL
Address bar / Network → Referer
Use the exact URL where the widget is initialized, without relying on a post-login redirect.
site_keyUsually stable
Site key
Elements → data-sitekey, or Network → k/sitekey
Inspect the CAPTCHA container first; if absent, inspect the widget iframe or initialization request.
data_sFresh value
data-s / rqdata
Elements → data-s, or initialization payload
This value can be short-lived; capture it for each rendered challenge.
is_invisibleUsually stable
Invisible widget
Elements → size="invisible"
Set true when the widget renders no checkbox and validates silently.
user_agentUsually stable
Browser User-Agent
Console → navigator.userAgent
Use the same browser identity when submitting the returned solution.
cookiesFresh value
Cookies
Application → Cookies / Network headers
Send only cookies required by the current CAPTCHA flow.
Address: https://solvecaptcha.net/api/createTask Method: POST Default provider task type: RecaptchaV2Task
Response fields use snake_case. Token-based tasks include solution.token; existing reCAPTCHA integrations also continue to receive solution.gRecaptchaResponse.
Request properties
Property
Required
Purpose
method
Yes
RecaptchaV2Task
page_url
Yes
Value extracted from the target CAPTCHA page.
site_key
Yes
Value extracted from the target CAPTCHA page.
data_s
No
Optional task-specific value.
is_invisible
No
Optional task-specific value.
user_agent
No
Optional task-specific value.
cookies
No
Optional task-specific value.
proxy_type, proxy_address, proxy_port
No
Use a customer proxy when the target rejects built-in provider proxies.
Working example
Replace YOUR_API_KEY with the key from your account settings and the uppercase placeholders with the values you collected above. Each snippet creates the task, polls until it is solved and prints the solution.
# Requirements: pip install requests
# Run: python3 solve.py
import sys
import time
import requests
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
task = {
"method": "RecaptchaV2Task",
"page_url": "PAGE_URL",
"site_key": "SITE_KEY"
}
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Poll until the task leaves the processing state. Keep at least three
# seconds between calls: the result endpoint is rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
solve.mjs
// Requirements: Node.js 18 or newer (uses the built-in fetch)
// Run: node solve.mjs
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const task = {
"method": "RecaptchaV2Task",
"page_url": "PAGE_URL",
"site_key": "SITE_KEY"
};
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Poll until the task leaves the processing state. Keep at least three
// seconds between calls: the result endpoint is rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
RecaptchaV3TaskProxyless
Solve score-based reCAPTCHA V3.
reCAPTCHA V3RecaptchaV3TaskProxyless
Identify → collect → submit
Collect the values from the current widget
Use DevTools on a page you are authorized to integrate. Static identifiers can be reused; values marked Fresh value must be captured again for every rendered challenge.
How to find all parameters required to create a task
Manually
Open the page in a browserLoad the page where the CAPTCHA appears, on a site you are authorised to integrate.
Inspect the CAPTCHA containerRight-click the widget and choose Inspect. Copy data-sitekey from the <div class="g-recaptcha"> element; copy data-s too when the page sets it.
Or read the sitekey from the networkIn Network, filter for recaptcha and open the anchor request: its k query parameter is the sitekey.
Find the action for score-based variantsSearch Sources for grecaptcha.execute; the action string passed there is page_action.
Note whether the widget is invisibleAn element carrying size="invisible" means you should send is_invisible: true.
Automatically
The first snippet reports the values. The two Playwright scripts collect them from a live page and solve them through this API in one run — replace YOUR_API_KEY and PAGE_URL.
paste into DevTools → Console
Run this on the page with the CAPTCHA. It prints the task body to copy into your request.
// RecaptchaV3TaskProxyless — collect the task parameters from this page.
// Paste into DevTools → Console on the page showing the CAPTCHA.
(() => {
const el = document.querySelector('.g-recaptcha[data-sitekey], [data-sitekey]');
const task = { method: "RecaptchaV3TaskProxyless", page_url: location.href, site_key: el?.getAttribute('data-sitekey') || null };
if (el?.getAttribute('data-s')) task.data_s = el.getAttribute('data-s');
if (el?.getAttribute('data-size') === 'invisible') task.is_invisible = true;
// Fall back to the anchor request, which always carries k=<sitekey>.
if (!task.site_key) {
const anchor = performance.getEntriesByType('resource')
.map((entry) => entry.name)
.find((name) => name.includes('/recaptcha/') && name.includes('k='));
if (anchor) task.site_key = new URL(anchor).searchParams.get('k');
}
console.log(JSON.stringify({ task }, null, 2));
return task;
})();
collect-and-solve.mjs
npm i playwright — collects the parameters from a live page and solves them through this API.
// RecaptchaV3TaskProxyless — collect the parameters from a live page, then solve them here.
// Requirements: npm i playwright · Run: node collect-and-solve.mjs
import { chromium } from 'playwright';
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const PAGE_URL = 'https://example.com/page-with-captcha';
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
async function collect(pageUrl) {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto(pageUrl);
await page.waitForTimeout(6000);
const collected = await page.evaluate(() => {
const el = document.querySelector('[data-sitekey], [data-captcha-id], [data-scene-id]');
return {
page_url: location.href,
user_agent: navigator.userAgent,
site_key: el
? el.getAttribute('data-sitekey') || el.getAttribute('data-captcha-id') || el.getAttribute('data-scene-id')
: null,
};
});
await browser.close();
// Fill in the metadata fields documented below before submitting.
return Object.fromEntries(Object.entries(collected).filter(([, value]) => value != null));
}
const task = { method: 'RecaptchaV3TaskProxyless', ...(await collect(PAGE_URL)) };
console.log('collected task:', JSON.stringify(task, null, 2));
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Keep at least three seconds between polls: the result endpoint is
// rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
# RecaptchaV3TaskProxyless — collect the parameters from a live page, then solve them here.
# Requirements: pip install playwright requests && playwright install chromium
# Run: python3 collect_and_solve.py
import sys
import time
import requests
from playwright.sync_api import sync_playwright
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
PAGE_URL = "https://example.com/page-with-captcha"
READ = """
() => {
const el = document.querySelector('[data-sitekey], [data-captcha-id], [data-scene-id]');
return {
page_url: location.href,
user_agent: navigator.userAgent,
site_key: el
? el.getAttribute('data-sitekey') || el.getAttribute('data-captcha-id') || el.getAttribute('data-scene-id')
: null,
};
}
"""
def collect(page_url):
"""Read the widget identifier, then add the metadata documented below."""
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto(page_url)
page.wait_for_timeout(6000)
collected = page.evaluate(READ)
browser.close()
return {key: value for key, value in collected.items() if value is not None}
task = {"method": "RecaptchaV3TaskProxyless", **collect(PAGE_URL)}
print("collected task:", task)
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Keep at least three seconds between polls: the result endpoint is
# rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
What each value is and where it lives
page_urlUsually stable
Page URL
Address bar / Network → Referer
Use the exact URL where the widget is initialized, without relying on a post-login redirect.
site_keyUsually stable
Site key
Elements → data-sitekey, or Network → k/sitekey
Inspect the CAPTCHA container first; if absent, inspect the widget iframe or initialization request.
min_scoreUsually stable
Minimum score
Target-site scoring policy
Request 0.3, 0.7 or 0.9 depending on how strict the protected action is.
page_actionUsually stable
Page action
Sources search → grecaptcha.execute, or turnstile.render
Copy the action string used by the page, for example login, checkout or managed.
is_enterpriseUsually stable
Enterprise mode
Sources → grecaptcha.enterprise
Set true when the page loads the enterprise reCAPTCHA build instead of the standard one.
Address: https://solvecaptcha.net/api/createTask Method: POST Default provider task type: RecaptchaV3TaskProxyless
Response fields use snake_case. Token-based tasks include solution.token; existing reCAPTCHA integrations also continue to receive solution.gRecaptchaResponse.
Request properties
Property
Required
Purpose
method
Yes
RecaptchaV3TaskProxyless
page_url
Yes
Value extracted from the target CAPTCHA page.
site_key
Yes
Value extracted from the target CAPTCHA page.
min_score
No
Optional task-specific value.
page_action
No
Optional task-specific value.
is_enterprise
No
Optional task-specific value.
proxy_type, proxy_address, proxy_port
No
Use a customer proxy when the target rejects built-in provider proxies.
Working example
Replace YOUR_API_KEY with the key from your account settings and the uppercase placeholders with the values you collected above. Each snippet creates the task, polls until it is solved and prints the solution.
# Requirements: pip install requests
# Run: python3 solve.py
import sys
import time
import requests
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
task = {
"method": "RecaptchaV3TaskProxyless",
"page_url": "PAGE_URL",
"site_key": "SITE_KEY"
}
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Poll until the task leaves the processing state. Keep at least three
# seconds between calls: the result endpoint is rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
solve.mjs
// Requirements: Node.js 18 or newer (uses the built-in fetch)
// Run: node solve.mjs
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const task = {
"method": "RecaptchaV3TaskProxyless",
"page_url": "PAGE_URL",
"site_key": "SITE_KEY"
};
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Poll until the task leaves the processing state. Keep at least three
// seconds between calls: the result endpoint is rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
FunCaptchaTask
Solve Arkose Labs FunCaptcha.
FunCaptchaFunCaptchaTask
Identify → collect → submit
Collect the values from the current widget
Use DevTools on a page you are authorized to integrate. Static identifiers can be reused; values marked Fresh value must be captured again for every rendered challenge.
How to find all parameters required to create a task
Manually
Open the page in a browserLoad the page where the CAPTCHA appears, on a site you are authorised to integrate.
Open DevTools before the widget loadsPress F12, switch to the Network tab and reload so the first requests are captured.
Read the public keyFind the Arkose request to /fc/gc/ or the widget iframe URL; its pk parameter is the value to send as site_key.
Note the service subdomainThe host serving that request is sub_domain when it differs from the Arkose default.
Copy blob data when presentSome integrations add a blob or rqdata value; send it as data.
Automatically
The first snippet reports the values. The two Playwright scripts collect them from a live page and solve them through this API in one run — replace YOUR_API_KEY and PAGE_URL.
paste into DevTools → Console
Run this on the page with the CAPTCHA. It prints the task body to copy into your request.
// FunCaptchaTask — collect the task parameters from this page.
// Paste into DevTools → Console on the page showing the CAPTCHA.
(() => {
const task = { method: "FunCaptchaTask", page_url: location.href };
const arkose = performance.getEntriesByType('resource')
.map((entry) => entry.name)
.find((name) => name.includes('arkoselabs') && name.includes('pk='));
if (arkose) {
const url = new URL(arkose);
task.site_key = url.searchParams.get('pk');
task.sub_domain = url.host;
}
console.log(JSON.stringify({ task }, null, 2));
return task;
})();
collect-and-solve.mjs
npm i playwright — collects the parameters from a live page and solves them through this API.
// FunCaptchaTask — collect the parameters from a live page, then solve them here.
// Requirements: npm i playwright · Run: node collect-and-solve.mjs
import { chromium } from 'playwright';
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const PAGE_URL = 'https://example.com/page-with-captcha';
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
async function collect(pageUrl) {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
let collected = null;
page.on('request', (request) => {
const url = request.url();
if (collected || !url.includes('arkoselabs') || !url.includes('pk=')) return;
const parsed = new URL(url);
collected = { site_key: parsed.searchParams.get('pk'), sub_domain: parsed.host };
});
await page.goto(pageUrl);
await page.waitForTimeout(8000);
const pageHref = page.url();
const userAgent = await page.evaluate(() => navigator.userAgent);
await browser.close();
if (!collected) throw new Error('No Arkose request with pk= was seen on this page.');
return { page_url: pageHref, user_agent: userAgent, ...collected };
}
const task = { method: 'FunCaptchaTask', ...(await collect(PAGE_URL)) };
console.log('collected task:', JSON.stringify(task, null, 2));
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Keep at least three seconds between polls: the result endpoint is
// rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
# FunCaptchaTask — collect the parameters from a live page, then solve them here.
# Requirements: pip install playwright requests && playwright install chromium
# Run: python3 collect_and_solve.py
import sys
import time
from urllib.parse import parse_qs, urlparse
import requests
from playwright.sync_api import sync_playwright
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
PAGE_URL = "https://example.com/page-with-captcha"
def collect(page_url):
"""The Arkose /fc/gc/ request carries the public key as pk."""
collected = {}
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
def on_request(request):
url = request.url
if collected or "arkoselabs" not in url or "pk=" not in url:
return
parsed = urlparse(url)
collected.update({
"site_key": parse_qs(parsed.query).get("pk", [None])[0],
"sub_domain": parsed.netloc,
})
page.on("request", on_request)
page.goto(page_url)
page.wait_for_timeout(8000)
page_href = page.url
user_agent = page.evaluate("() => navigator.userAgent")
browser.close()
if not collected:
sys.exit("No Arkose request with pk= was seen on this page.")
return {"page_url": page_href, "user_agent": user_agent, **collected}
task = {"method": "FunCaptchaTask", **collect(PAGE_URL)}
print("collected task:", task)
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Keep at least three seconds between polls: the result endpoint is
# rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
What each value is and where it lives
page_urlUsually stable
Page URL
Address bar / Network → Referer
Use the exact URL where the widget is initialized, without relying on a post-login redirect.
site_keyUsually stable
Site key
Elements → data-sitekey, or Network → k/sitekey
Inspect the CAPTCHA container first; if absent, inspect the widget iframe or initialization request.
dataFresh value
Challenge data
Widget callback or initialization object
For Cloudflare this is commonly cData; for other types inspect the provider-specific payload.
data_sFresh value
data-s / rqdata
Elements → data-s, or initialization payload
This value can be short-lived; capture it for each rendered challenge.
sub_domainUsually stable
FunCaptcha API subdomain
Widget iframe hostname / Network
Copy the Arkose service hostname used by the page.
user_agentUsually stable
Browser User-Agent
Console → navigator.userAgent
Use the same browser identity when submitting the returned solution.
cookiesFresh value
Cookies
Application → Cookies / Network headers
Send only cookies required by the current CAPTCHA flow.
Address: https://solvecaptcha.net/api/createTask Method: POST Default provider task type: FunCaptchaTask
Response fields use snake_case. Token-based tasks include solution.token; existing reCAPTCHA integrations also continue to receive solution.gRecaptchaResponse.
Customer proxy strongly recommended. The upstream provider documents a proxy as mandatory for this type. Requests without proxy_type, proxy_address and proxy_port are accepted but frequently fail upstream.
Request properties
Property
Required
Purpose
method
Yes
FunCaptchaTask
page_url
Yes
Value extracted from the target CAPTCHA page.
site_key
Yes
Value extracted from the target CAPTCHA page.
data
No
Optional task-specific value.
data_s
No
Optional task-specific value.
sub_domain
No
Optional task-specific value.
user_agent
No
Optional task-specific value.
cookies
No
Optional task-specific value.
proxy_type, proxy_address, proxy_port
No
Use a customer proxy when the target rejects built-in provider proxies.
Working example
Replace YOUR_API_KEY with the key from your account settings and the uppercase placeholders with the values you collected above. Each snippet creates the task, polls until it is solved and prints the solution.
# Requirements: pip install requests
# Run: python3 solve.py
import sys
import time
import requests
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
task = {
"method": "FunCaptchaTask",
"page_url": "PAGE_URL",
"site_key": "SITE_KEY"
}
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Poll until the task leaves the processing state. Keep at least three
# seconds between calls: the result endpoint is rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
solve.mjs
// Requirements: Node.js 18 or newer (uses the built-in fetch)
// Run: node solve.mjs
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const task = {
"method": "FunCaptchaTask",
"page_url": "PAGE_URL",
"site_key": "SITE_KEY"
};
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Poll until the task leaves the processing state. Keep at least three
// seconds between calls: the result endpoint is rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
FunCaptchaTaskProxyless
Solve Arkose Labs FunCaptcha.
FunCaptchaFunCaptchaTaskProxyless
Identify → collect → submit
Collect the values from the current widget
Use DevTools on a page you are authorized to integrate. Static identifiers can be reused; values marked Fresh value must be captured again for every rendered challenge.
How to find all parameters required to create a task
Manually
Open the page in a browserLoad the page where the CAPTCHA appears, on a site you are authorised to integrate.
Open DevTools before the widget loadsPress F12, switch to the Network tab and reload so the first requests are captured.
Read the public keyFind the Arkose request to /fc/gc/ or the widget iframe URL; its pk parameter is the value to send as site_key.
Note the service subdomainThe host serving that request is sub_domain when it differs from the Arkose default.
Copy blob data when presentSome integrations add a blob or rqdata value; send it as data.
Automatically
The first snippet reports the values. The two Playwright scripts collect them from a live page and solve them through this API in one run — replace YOUR_API_KEY and PAGE_URL.
paste into DevTools → Console
Run this on the page with the CAPTCHA. It prints the task body to copy into your request.
// FunCaptchaTaskProxyless — collect the task parameters from this page.
// Paste into DevTools → Console on the page showing the CAPTCHA.
(() => {
const task = { method: "FunCaptchaTaskProxyless", page_url: location.href };
const arkose = performance.getEntriesByType('resource')
.map((entry) => entry.name)
.find((name) => name.includes('arkoselabs') && name.includes('pk='));
if (arkose) {
const url = new URL(arkose);
task.site_key = url.searchParams.get('pk');
task.sub_domain = url.host;
}
console.log(JSON.stringify({ task }, null, 2));
return task;
})();
collect-and-solve.mjs
npm i playwright — collects the parameters from a live page and solves them through this API.
// FunCaptchaTaskProxyless — collect the parameters from a live page, then solve them here.
// Requirements: npm i playwright · Run: node collect-and-solve.mjs
import { chromium } from 'playwright';
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const PAGE_URL = 'https://example.com/page-with-captcha';
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
async function collect(pageUrl) {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
let collected = null;
page.on('request', (request) => {
const url = request.url();
if (collected || !url.includes('arkoselabs') || !url.includes('pk=')) return;
const parsed = new URL(url);
collected = { site_key: parsed.searchParams.get('pk'), sub_domain: parsed.host };
});
await page.goto(pageUrl);
await page.waitForTimeout(8000);
const pageHref = page.url();
const userAgent = await page.evaluate(() => navigator.userAgent);
await browser.close();
if (!collected) throw new Error('No Arkose request with pk= was seen on this page.');
return { page_url: pageHref, user_agent: userAgent, ...collected };
}
const task = { method: 'FunCaptchaTaskProxyless', ...(await collect(PAGE_URL)) };
console.log('collected task:', JSON.stringify(task, null, 2));
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Keep at least three seconds between polls: the result endpoint is
// rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
# FunCaptchaTaskProxyless — collect the parameters from a live page, then solve them here.
# Requirements: pip install playwright requests && playwright install chromium
# Run: python3 collect_and_solve.py
import sys
import time
from urllib.parse import parse_qs, urlparse
import requests
from playwright.sync_api import sync_playwright
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
PAGE_URL = "https://example.com/page-with-captcha"
def collect(page_url):
"""The Arkose /fc/gc/ request carries the public key as pk."""
collected = {}
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
def on_request(request):
url = request.url
if collected or "arkoselabs" not in url or "pk=" not in url:
return
parsed = urlparse(url)
collected.update({
"site_key": parse_qs(parsed.query).get("pk", [None])[0],
"sub_domain": parsed.netloc,
})
page.on("request", on_request)
page.goto(page_url)
page.wait_for_timeout(8000)
page_href = page.url
user_agent = page.evaluate("() => navigator.userAgent")
browser.close()
if not collected:
sys.exit("No Arkose request with pk= was seen on this page.")
return {"page_url": page_href, "user_agent": user_agent, **collected}
task = {"method": "FunCaptchaTaskProxyless", **collect(PAGE_URL)}
print("collected task:", task)
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Keep at least three seconds between polls: the result endpoint is
# rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
What each value is and where it lives
page_urlUsually stable
Page URL
Address bar / Network → Referer
Use the exact URL where the widget is initialized, without relying on a post-login redirect.
site_keyUsually stable
Site key
Elements → data-sitekey, or Network → k/sitekey
Inspect the CAPTCHA container first; if absent, inspect the widget iframe or initialization request.
dataFresh value
Challenge data
Widget callback or initialization object
For Cloudflare this is commonly cData; for other types inspect the provider-specific payload.
data_sFresh value
data-s / rqdata
Elements → data-s, or initialization payload
This value can be short-lived; capture it for each rendered challenge.
sub_domainUsually stable
FunCaptcha API subdomain
Widget iframe hostname / Network
Copy the Arkose service hostname used by the page.
user_agentUsually stable
Browser User-Agent
Console → navigator.userAgent
Use the same browser identity when submitting the returned solution.
cookiesFresh value
Cookies
Application → Cookies / Network headers
Send only cookies required by the current CAPTCHA flow.
Address: https://solvecaptcha.net/api/createTask Method: POST Default provider task type: FunCaptchaTask
Compatibility alias: this historical method remains accepted and is mapped internally to FunCaptchaTask.
Response fields use snake_case. Token-based tasks include solution.token; existing reCAPTCHA integrations also continue to receive solution.gRecaptchaResponse.
Customer proxy strongly recommended. The upstream provider documents a proxy as mandatory for this type. Requests without proxy_type, proxy_address and proxy_port are accepted but frequently fail upstream.
Request properties
Property
Required
Purpose
method
Yes
FunCaptchaTaskProxyless
page_url
Yes
Value extracted from the target CAPTCHA page.
site_key
Yes
Value extracted from the target CAPTCHA page.
data
No
Optional task-specific value.
data_s
No
Optional task-specific value.
sub_domain
No
Optional task-specific value.
user_agent
No
Optional task-specific value.
cookies
No
Optional task-specific value.
proxy_type, proxy_address, proxy_port
No
Use a customer proxy when the target rejects built-in provider proxies.
Working example
Replace YOUR_API_KEY with the key from your account settings and the uppercase placeholders with the values you collected above. Each snippet creates the task, polls until it is solved and prints the solution.
# Requirements: pip install requests
# Run: python3 solve.py
import sys
import time
import requests
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
task = {
"method": "FunCaptchaTaskProxyless",
"page_url": "PAGE_URL",
"site_key": "SITE_KEY"
}
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Poll until the task leaves the processing state. Keep at least three
# seconds between calls: the result endpoint is rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
solve.mjs
// Requirements: Node.js 18 or newer (uses the built-in fetch)
// Run: node solve.mjs
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const task = {
"method": "FunCaptchaTaskProxyless",
"page_url": "PAGE_URL",
"site_key": "SITE_KEY"
};
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Poll until the task leaves the processing state. Keep at least three
// seconds between calls: the result endpoint is rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
GeeTestTask
Solve GeeTest V3 or V4 using one stable public contract.
GeeTest V3 / V4GeeTestTask
Identify → collect → submit
Collect the values from the current widget
Use DevTools on a page you are authorized to integrate. Static identifiers can be reused; values marked Fresh value must be captured again for every rendered challenge.
How to find all parameters required to create a task
Manually
Open the page in a browserLoad the page where the CAPTCHA appears, on a site you are authorised to integrate.
Open DevTools before the widget loadsPress F12, switch to the Network tab and reload so the first requests are captured.
Find the bootstrap requestFilter for load or captcha and look at responses from the target site itself: they carry gt and, for V3, challenge.
Take challenge before the widget initialisesOnce api.geetest.com/gettype.php has fired, that challenge is spent. Capture it from the site response, or from the get.php / ajax.php query string while blocking that request.
Identify the versionA captcha_id in the initialisation means V4: send it as gt with version: 4 and omit challenge.
Automatically
The first snippet reports the values. The two Playwright scripts collect them from a live page and solve them through this API in one run — replace YOUR_API_KEY and PAGE_URL.
paste into DevTools → Console
Run this on the page with the CAPTCHA. It prints the task body to copy into your request.
// GeeTestTask — collect the task parameters from this page.
// Paste into DevTools → Console on the page showing the CAPTCHA.
(() => {
// Read the bootstrap request the site made before GeeTest started.
const task = { method: "GeeTestTask", page_url: location.href };
const hit = performance.getEntriesByType('resource')
.map((entry) => entry.name)
.find((name) => name.includes('gt=') && name.includes('challenge='));
if (hit) {
const query = new URL(hit).searchParams;
task.gt = query.get('gt');
task.challenge = query.get('challenge');
task.version = 3;
} else {
console.warn('No gt/challenge seen yet. Reload with the Network tab open, or use the Playwright collector which blocks the GeeTest request before it spends the challenge.');
}
console.log(JSON.stringify({ task }, null, 2));
return task;
})();
collect-and-solve.mjs
npm i playwright — collects the parameters from a live page and solves them through this API.
// GeeTestTask — collect the parameters from a live page, then solve them here.
// Requirements: npm i playwright · Run: node collect-and-solve.mjs
import { chromium } from 'playwright';
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const PAGE_URL = 'https://example.com/page-with-captcha';
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
async function collect(pageUrl) {
const browser = await chromium.launch({ headless: false });
const context = await browser.newContext();
let collected = null;
// Block the GeeTest call and read its query string: letting it through
// would spend the challenge before the task is created.
await context.route('**/*', async (route) => {
const url = route.request().url();
if (url.includes('api.geetest.com/get.php') || url.includes('api.geevisit.com/ajax.php')) {
const query = new URL(url).searchParams;
const gt = query.get('gt');
const challenge = query.get('challenge');
if (gt && challenge && !collected) {
collected = { gt, challenge, version: 3 };
}
return route.abort();
}
return route.continue();
});
const page = await context.newPage();
await page.goto(pageUrl);
await page.waitForTimeout(8000);
const pageHref = page.url();
await browser.close();
if (!collected) throw new Error('No gt/challenge seen. For V4 read captcha_id and send it as gt with version: 4.');
return { page_url: pageHref, ...collected };
}
const task = { method: 'GeeTestTask', ...(await collect(PAGE_URL)) };
console.log('collected task:', JSON.stringify(task, null, 2));
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Keep at least three seconds between polls: the result endpoint is
// rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
# GeeTestTask — collect the parameters from a live page, then solve them here.
# Requirements: pip install playwright requests && playwright install chromium
# Run: python3 collect_and_solve.py
import sys
import time
from urllib.parse import parse_qs, urlparse
import requests
from playwright.sync_api import sync_playwright
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
PAGE_URL = "https://example.com/page-with-captcha"
def collect(page_url):
"""Block the GeeTest call and read its query string.
Letting it through would spend the challenge before the task exists.
"""
collected = {}
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
context = browser.new_context()
def handle(route):
url = route.request.url
if "api.geetest.com/get.php" in url or "api.geevisit.com/ajax.php" in url:
query = parse_qs(urlparse(url).query)
gt = query.get("gt", [None])[0]
challenge = query.get("challenge", [None])[0]
if gt and challenge and not collected:
collected.update({"gt": gt, "challenge": challenge, "version": 3})
return route.abort()
return route.continue_()
context.route("**/*", handle)
page = context.new_page()
page.goto(page_url)
page.wait_for_timeout(8000)
page_href = page.url
browser.close()
if not collected:
sys.exit("No gt/challenge seen. For V4 read captcha_id and send it as gt with version 4.")
return {"page_url": page_href, **collected}
task = {"method": "GeeTestTask", **collect(PAGE_URL)}
print("collected task:", task)
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Keep at least three seconds between polls: the result endpoint is
# rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
What each value is and where it lives
page_urlUsually stable
Page URL
Address bar / Network → Referer
Use the exact URL where the widget is initialized, without relying on a post-login redirect.
gtUsually stable
GeeTest ID
Network → load/gettype, or initGeetest()
For V3 copy gt. For V4 copy captcha_id and send it as gt.
site_keyUsually stable
Site key
Elements → data-sitekey, or Network → k/sitekey
Inspect the CAPTCHA container first; if absent, inspect the widget iframe or initialization request.
challengeFresh value
GeeTest challenge
Target-site bootstrap response before GeeTest initializes
Capture a fresh value before the widget sends gettype/load requests.
versionUsually stable
CAPTCHA version
Loaded script and Network request shape
Use 3 for gt + challenge; use 4 when the integration exposes captcha_id.
api_subdomainUsually stable
API subdomain
Widget requests in Network
Use the hostname contacted by the widget when it differs from the provider default.
get_libUsually stable
Widget library URL
Network → JavaScript
Copy the script URL used by this CAPTCHA instance.
Copy required V4 values such as riskType without renaming nested keys.
Address: https://solvecaptcha.net/api/createTask Method: POST Default provider task type: GeeTestTask
Response fields use snake_case. Token-based tasks include solution.token; existing reCAPTCHA integrations also continue to receive solution.gRecaptchaResponse.
Customer proxy required. Provide proxy_type, proxy_address and proxy_port; credentials are optional when the proxy does not require authentication.
Request properties
Property
Required
Purpose
method
Yes
GeeTestTask
page_url
Yes
Value extracted from the target CAPTCHA page.
gt
Yes
Value extracted from the target CAPTCHA page.
site_key
No
Optional task-specific value.
challenge
No
Optional task-specific value.
version
No
Optional task-specific value.
api_subdomain
No
Optional task-specific value.
get_lib
No
Optional task-specific value.
init_parameters
No
Optional task-specific value.
user_agent
No
Optional task-specific value.
GeeTest versions:version: 3 requires challenge. For version: 4, omit challenge and optionally send init_parameters. The public response preserves GeeTest solution fields such as captcha_output, lot_number, pass_token and gen_time.
Working example
Replace YOUR_API_KEY with the key from your account settings and the uppercase placeholders with the values you collected above. Each snippet creates the task, polls until it is solved and prints the solution.
# Requirements: pip install requests
# Run: python3 solve.py
import sys
import time
import requests
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
task = {
"method": "GeeTestTask",
"page_url": "PAGE_URL",
"gt": "GT",
"version": 4,
"init_parameters": {
"riskType": "slide"
},
"proxy_type": "http",
"proxy_address": "192.0.2.10",
"proxy_port": 8080
}
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Poll until the task leaves the processing state. Keep at least three
# seconds between calls: the result endpoint is rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
solve.mjs
// Requirements: Node.js 18 or newer (uses the built-in fetch)
// Run: node solve.mjs
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const task = {
"method": "GeeTestTask",
"page_url": "PAGE_URL",
"gt": "GT",
"version": 4,
"init_parameters": {
"riskType": "slide"
},
"proxy_type": "http",
"proxy_address": "192.0.2.10",
"proxy_port": 8080
};
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Poll until the task leaves the processing state. Keep at least three
// seconds between calls: the result endpoint is rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
GeeTestTaskProxyless
Solve GeeTest V3 or V4 using one stable public contract.
GeeTest V3 / V4GeeTestTaskProxyless
Identify → collect → submit
Collect the values from the current widget
Use DevTools on a page you are authorized to integrate. Static identifiers can be reused; values marked Fresh value must be captured again for every rendered challenge.
How to find all parameters required to create a task
Manually
Open the page in a browserLoad the page where the CAPTCHA appears, on a site you are authorised to integrate.
Open DevTools before the widget loadsPress F12, switch to the Network tab and reload so the first requests are captured.
Find the bootstrap requestFilter for load or captcha and look at responses from the target site itself: they carry gt and, for V3, challenge.
Take challenge before the widget initialisesOnce api.geetest.com/gettype.php has fired, that challenge is spent. Capture it from the site response, or from the get.php / ajax.php query string while blocking that request.
Identify the versionA captcha_id in the initialisation means V4: send it as gt with version: 4 and omit challenge.
Automatically
The first snippet reports the values. The two Playwright scripts collect them from a live page and solve them through this API in one run — replace YOUR_API_KEY and PAGE_URL.
paste into DevTools → Console
Run this on the page with the CAPTCHA. It prints the task body to copy into your request.
// GeeTestTaskProxyless — collect the task parameters from this page.
// Paste into DevTools → Console on the page showing the CAPTCHA.
(() => {
// Read the bootstrap request the site made before GeeTest started.
const task = { method: "GeeTestTaskProxyless", page_url: location.href };
const hit = performance.getEntriesByType('resource')
.map((entry) => entry.name)
.find((name) => name.includes('gt=') && name.includes('challenge='));
if (hit) {
const query = new URL(hit).searchParams;
task.gt = query.get('gt');
task.challenge = query.get('challenge');
task.version = 3;
} else {
console.warn('No gt/challenge seen yet. Reload with the Network tab open, or use the Playwright collector which blocks the GeeTest request before it spends the challenge.');
}
console.log(JSON.stringify({ task }, null, 2));
return task;
})();
collect-and-solve.mjs
npm i playwright — collects the parameters from a live page and solves them through this API.
// GeeTestTaskProxyless — collect the parameters from a live page, then solve them here.
// Requirements: npm i playwright · Run: node collect-and-solve.mjs
import { chromium } from 'playwright';
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const PAGE_URL = 'https://example.com/page-with-captcha';
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
async function collect(pageUrl) {
const browser = await chromium.launch({ headless: false });
const context = await browser.newContext();
let collected = null;
// Block the GeeTest call and read its query string: letting it through
// would spend the challenge before the task is created.
await context.route('**/*', async (route) => {
const url = route.request().url();
if (url.includes('api.geetest.com/get.php') || url.includes('api.geevisit.com/ajax.php')) {
const query = new URL(url).searchParams;
const gt = query.get('gt');
const challenge = query.get('challenge');
if (gt && challenge && !collected) {
collected = { gt, challenge, version: 3 };
}
return route.abort();
}
return route.continue();
});
const page = await context.newPage();
await page.goto(pageUrl);
await page.waitForTimeout(8000);
const pageHref = page.url();
await browser.close();
if (!collected) throw new Error('No gt/challenge seen. For V4 read captcha_id and send it as gt with version: 4.');
return { page_url: pageHref, ...collected };
}
const task = { method: 'GeeTestTaskProxyless', ...(await collect(PAGE_URL)) };
console.log('collected task:', JSON.stringify(task, null, 2));
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Keep at least three seconds between polls: the result endpoint is
// rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
# GeeTestTaskProxyless — collect the parameters from a live page, then solve them here.
# Requirements: pip install playwright requests && playwright install chromium
# Run: python3 collect_and_solve.py
import sys
import time
from urllib.parse import parse_qs, urlparse
import requests
from playwright.sync_api import sync_playwright
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
PAGE_URL = "https://example.com/page-with-captcha"
def collect(page_url):
"""Block the GeeTest call and read its query string.
Letting it through would spend the challenge before the task exists.
"""
collected = {}
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
context = browser.new_context()
def handle(route):
url = route.request.url
if "api.geetest.com/get.php" in url or "api.geevisit.com/ajax.php" in url:
query = parse_qs(urlparse(url).query)
gt = query.get("gt", [None])[0]
challenge = query.get("challenge", [None])[0]
if gt and challenge and not collected:
collected.update({"gt": gt, "challenge": challenge, "version": 3})
return route.abort()
return route.continue_()
context.route("**/*", handle)
page = context.new_page()
page.goto(page_url)
page.wait_for_timeout(8000)
page_href = page.url
browser.close()
if not collected:
sys.exit("No gt/challenge seen. For V4 read captcha_id and send it as gt with version 4.")
return {"page_url": page_href, **collected}
task = {"method": "GeeTestTaskProxyless", **collect(PAGE_URL)}
print("collected task:", task)
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Keep at least three seconds between polls: the result endpoint is
# rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
What each value is and where it lives
page_urlUsually stable
Page URL
Address bar / Network → Referer
Use the exact URL where the widget is initialized, without relying on a post-login redirect.
gtUsually stable
GeeTest ID
Network → load/gettype, or initGeetest()
For V3 copy gt. For V4 copy captcha_id and send it as gt.
site_keyUsually stable
Site key
Elements → data-sitekey, or Network → k/sitekey
Inspect the CAPTCHA container first; if absent, inspect the widget iframe or initialization request.
challengeFresh value
GeeTest challenge
Target-site bootstrap response before GeeTest initializes
Capture a fresh value before the widget sends gettype/load requests.
versionUsually stable
CAPTCHA version
Loaded script and Network request shape
Use 3 for gt + challenge; use 4 when the integration exposes captcha_id.
api_subdomainUsually stable
API subdomain
Widget requests in Network
Use the hostname contacted by the widget when it differs from the provider default.
get_libUsually stable
Widget library URL
Network → JavaScript
Copy the script URL used by this CAPTCHA instance.
Copy required V4 values such as riskType without renaming nested keys.
Address: https://solvecaptcha.net/api/createTask Method: POST Default provider task type: GeeTestTask
Compatibility alias: this historical method remains accepted and is mapped internally to GeeTestTask.
Response fields use snake_case. Token-based tasks include solution.token; existing reCAPTCHA integrations also continue to receive solution.gRecaptchaResponse.
Request properties
Property
Required
Purpose
method
Yes
GeeTestTaskProxyless
page_url
Yes
Value extracted from the target CAPTCHA page.
gt
Yes
Value extracted from the target CAPTCHA page.
site_key
No
Optional task-specific value.
challenge
No
Optional task-specific value.
version
No
Optional task-specific value.
api_subdomain
No
Optional task-specific value.
get_lib
No
Optional task-specific value.
init_parameters
No
Optional task-specific value.
user_agent
No
Optional task-specific value.
proxy_type, proxy_address, proxy_port
No
Use a customer proxy when the target rejects built-in provider proxies.
GeeTest versions:version: 3 requires challenge. For version: 4, omit challenge and optionally send init_parameters. The public response preserves GeeTest solution fields such as captcha_output, lot_number, pass_token and gen_time.
Working example
Replace YOUR_API_KEY with the key from your account settings and the uppercase placeholders with the values you collected above. Each snippet creates the task, polls until it is solved and prints the solution.
# Requirements: pip install requests
# Run: python3 solve.py
import sys
import time
import requests
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
task = {
"method": "GeeTestTaskProxyless",
"page_url": "PAGE_URL",
"gt": "GT",
"version": 4,
"init_parameters": {
"riskType": "slide"
}
}
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Poll until the task leaves the processing state. Keep at least three
# seconds between calls: the result endpoint is rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
solve.mjs
// Requirements: Node.js 18 or newer (uses the built-in fetch)
// Run: node solve.mjs
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const task = {
"method": "GeeTestTaskProxyless",
"page_url": "PAGE_URL",
"gt": "GT",
"version": 4,
"init_parameters": {
"riskType": "slide"
}
};
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Poll until the task leaves the processing state. Keep at least three
// seconds between calls: the result endpoint is rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
TurnstileTask
Solve a standard Cloudflare Turnstile widget.
Cloudflare TurnstileTurnstileTask
Identify → collect → submit
Collect the values from the current widget
Use DevTools on a page you are authorized to integrate. Static identifiers can be reused; values marked Fresh value must be captured again for every rendered challenge.
How to find all parameters required to create a task
Manually
Open the page in a browserLoad the page where the CAPTCHA appears, on a site you are authorised to integrate.
Open DevTools before the widget loadsPress F12, switch to the Network tab and reload so the first requests are captured.
Read the sitekeyCopy data-sitekey from the Turnstile container, or the sitekey argument passed to turnstile.render in Sources.
Capture the challenge valuesturnstile.render receives an options object holding action, cData and chlPageData. Send them as page_action, data and page_data.
Collect them per rendercData and chlPageData expire with the challenge; capture them immediately before creating the task.
Automatically
The first snippet reports the values. The two Playwright scripts collect them from a live page and solve them through this API in one run — replace YOUR_API_KEY and PAGE_URL.
paste into DevTools → Console
Run this on the page with the CAPTCHA. It prints the task body to copy into your request.
// TurnstileTask — collect the task parameters from this page.
// Paste into DevTools → Console on the page showing the CAPTCHA.
(() => {
// turnstile.render receives everything the task needs. Reload the
// page after pasting this so the hook is in place before it runs.
const task = { method: "TurnstileTask", page_url: location.href };
const el = document.querySelector('[data-sitekey]');
if (el) task.site_key = el.getAttribute('data-sitekey');
if (window.turnstile && !window.turnstile.__hooked) {
const render = window.turnstile.render.bind(window.turnstile);
window.turnstile.render = (container, options = {}) => {
Object.assign(task, {
site_key: options.sitekey || task.site_key,
page_action: options.action,
data: options.cData,
page_data: options.chlPageData,
});
console.log('captured:', JSON.stringify(task, null, 2));
return render(container, options);
};
window.turnstile.__hooked = true;
}
console.log(JSON.stringify({ task }, null, 2));
return task;
})();
collect-and-solve.mjs
npm i playwright — collects the parameters from a live page and solves them through this API.
// TurnstileTask — collect the parameters from a live page, then solve them here.
// Requirements: npm i playwright · Run: node collect-and-solve.mjs
import { chromium } from 'playwright';
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const PAGE_URL = 'https://example.com/page-with-captcha';
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
async function collect(pageUrl) {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
// Hook turnstile.render before the page script runs: the options it
// receives carry the sitekey, action, cData and chlPageData.
await page.addInitScript(() => {
window.__collected = null;
let real = null;
Object.defineProperty(window, 'turnstile', {
configurable: true,
get: () => real,
set(value) {
const render = value.render.bind(value);
value.render = (container, options = {}) => {
window.__collected = {
site_key: options.sitekey,
page_action: options.action,
data: options.cData,
page_data: options.chlPageData,
user_agent: navigator.userAgent,
};
return render(container, options);
};
real = value;
},
});
});
await page.goto(pageUrl);
await page.waitForFunction(() => window.__collected !== null, null, { timeout: 30000 });
const collected = await page.evaluate(() => ({ page_url: location.href, ...window.__collected }));
await browser.close();
return Object.fromEntries(Object.entries(collected).filter(([, value]) => value != null));
}
const task = { method: 'TurnstileTask', ...(await collect(PAGE_URL)) };
console.log('collected task:', JSON.stringify(task, null, 2));
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Keep at least three seconds between polls: the result endpoint is
// rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
# TurnstileTask — collect the parameters from a live page, then solve them here.
# Requirements: pip install playwright requests && playwright install chromium
# Run: python3 collect_and_solve.py
import sys
import time
import requests
from playwright.sync_api import sync_playwright
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
PAGE_URL = "https://example.com/page-with-captcha"
HOOK = """
window.__collected = null;
let real = null;
Object.defineProperty(window, 'turnstile', {
configurable: true,
get: () => real,
set(value) {
const render = value.render.bind(value);
value.render = (container, options = {}) => {
window.__collected = {
site_key: options.sitekey,
page_action: options.action,
data: options.cData,
page_data: options.chlPageData,
user_agent: navigator.userAgent,
};
return render(container, options);
};
real = value;
},
});
"""
def collect(page_url):
"""Hook turnstile.render: its options carry every value the task needs."""
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.add_init_script(HOOK)
page.goto(page_url)
page.wait_for_function("window.__collected !== null", timeout=30000)
collected = page.evaluate(
"() => ({ page_url: location.href, ...window.__collected })"
)
browser.close()
return {key: value for key, value in collected.items() if value is not None}
task = {"method": "TurnstileTask", **collect(PAGE_URL)}
print("collected task:", task)
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Keep at least three seconds between polls: the result endpoint is
# rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
What each value is and where it lives
page_urlUsually stable
Page URL
Address bar / Network → Referer
Use the exact URL where the widget is initialized, without relying on a post-login redirect.
site_keyUsually stable
Site key
Elements → data-sitekey, or Network → k/sitekey
Inspect the CAPTCHA container first; if absent, inspect the widget iframe or initialization request.
page_actionUsually stable
Page action
Sources search → grecaptcha.execute, or turnstile.render
Copy the action string used by the page, for example login, checkout or managed.
dataFresh value
Challenge data
Widget callback or initialization object
For Cloudflare this is commonly cData; for other types inspect the provider-specific payload.
user_agentUsually stable
Browser User-Agent
Console → navigator.userAgent
Use the same browser identity when submitting the returned solution.
Address: https://solvecaptcha.net/api/createTask Method: POST Default provider task type: TurnstileTask
Response fields use snake_case. Token-based tasks include solution.token; existing reCAPTCHA integrations also continue to receive solution.gRecaptchaResponse.
Request properties
Property
Required
Purpose
method
Yes
TurnstileTask
page_url
Yes
Value extracted from the target CAPTCHA page.
site_key
Yes
Value extracted from the target CAPTCHA page.
page_action
No
Optional task-specific value.
data
No
Optional task-specific value.
user_agent
No
Optional task-specific value.
proxy_type, proxy_address, proxy_port
No
Use a customer proxy when the target rejects built-in provider proxies.
Working example
Replace YOUR_API_KEY with the key from your account settings and the uppercase placeholders with the values you collected above. Each snippet creates the task, polls until it is solved and prints the solution.
# Requirements: pip install requests
# Run: python3 solve.py
import sys
import time
import requests
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
task = {
"method": "TurnstileTask",
"page_url": "PAGE_URL",
"site_key": "SITE_KEY"
}
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Poll until the task leaves the processing state. Keep at least three
# seconds between calls: the result endpoint is rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
solve.mjs
// Requirements: Node.js 18 or newer (uses the built-in fetch)
// Run: node solve.mjs
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const task = {
"method": "TurnstileTask",
"page_url": "PAGE_URL",
"site_key": "SITE_KEY"
};
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Poll until the task leaves the processing state. Keep at least three
// seconds between calls: the result endpoint is rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
TurnstileTaskProxyless
Solve a standard Cloudflare Turnstile widget.
Cloudflare TurnstileTurnstileTaskProxyless
Identify → collect → submit
Collect the values from the current widget
Use DevTools on a page you are authorized to integrate. Static identifiers can be reused; values marked Fresh value must be captured again for every rendered challenge.
How to find all parameters required to create a task
Manually
Open the page in a browserLoad the page where the CAPTCHA appears, on a site you are authorised to integrate.
Open DevTools before the widget loadsPress F12, switch to the Network tab and reload so the first requests are captured.
Read the sitekeyCopy data-sitekey from the Turnstile container, or the sitekey argument passed to turnstile.render in Sources.
Capture the challenge valuesturnstile.render receives an options object holding action, cData and chlPageData. Send them as page_action, data and page_data.
Collect them per rendercData and chlPageData expire with the challenge; capture them immediately before creating the task.
Automatically
The first snippet reports the values. The two Playwright scripts collect them from a live page and solve them through this API in one run — replace YOUR_API_KEY and PAGE_URL.
paste into DevTools → Console
Run this on the page with the CAPTCHA. It prints the task body to copy into your request.
// TurnstileTaskProxyless — collect the task parameters from this page.
// Paste into DevTools → Console on the page showing the CAPTCHA.
(() => {
// turnstile.render receives everything the task needs. Reload the
// page after pasting this so the hook is in place before it runs.
const task = { method: "TurnstileTaskProxyless", page_url: location.href };
const el = document.querySelector('[data-sitekey]');
if (el) task.site_key = el.getAttribute('data-sitekey');
if (window.turnstile && !window.turnstile.__hooked) {
const render = window.turnstile.render.bind(window.turnstile);
window.turnstile.render = (container, options = {}) => {
Object.assign(task, {
site_key: options.sitekey || task.site_key,
page_action: options.action,
data: options.cData,
page_data: options.chlPageData,
});
console.log('captured:', JSON.stringify(task, null, 2));
return render(container, options);
};
window.turnstile.__hooked = true;
}
console.log(JSON.stringify({ task }, null, 2));
return task;
})();
collect-and-solve.mjs
npm i playwright — collects the parameters from a live page and solves them through this API.
// TurnstileTaskProxyless — collect the parameters from a live page, then solve them here.
// Requirements: npm i playwright · Run: node collect-and-solve.mjs
import { chromium } from 'playwright';
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const PAGE_URL = 'https://example.com/page-with-captcha';
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
async function collect(pageUrl) {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
// Hook turnstile.render before the page script runs: the options it
// receives carry the sitekey, action, cData and chlPageData.
await page.addInitScript(() => {
window.__collected = null;
let real = null;
Object.defineProperty(window, 'turnstile', {
configurable: true,
get: () => real,
set(value) {
const render = value.render.bind(value);
value.render = (container, options = {}) => {
window.__collected = {
site_key: options.sitekey,
page_action: options.action,
data: options.cData,
page_data: options.chlPageData,
user_agent: navigator.userAgent,
};
return render(container, options);
};
real = value;
},
});
});
await page.goto(pageUrl);
await page.waitForFunction(() => window.__collected !== null, null, { timeout: 30000 });
const collected = await page.evaluate(() => ({ page_url: location.href, ...window.__collected }));
await browser.close();
return Object.fromEntries(Object.entries(collected).filter(([, value]) => value != null));
}
const task = { method: 'TurnstileTaskProxyless', ...(await collect(PAGE_URL)) };
console.log('collected task:', JSON.stringify(task, null, 2));
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Keep at least three seconds between polls: the result endpoint is
// rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
# TurnstileTaskProxyless — collect the parameters from a live page, then solve them here.
# Requirements: pip install playwright requests && playwright install chromium
# Run: python3 collect_and_solve.py
import sys
import time
import requests
from playwright.sync_api import sync_playwright
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
PAGE_URL = "https://example.com/page-with-captcha"
HOOK = """
window.__collected = null;
let real = null;
Object.defineProperty(window, 'turnstile', {
configurable: true,
get: () => real,
set(value) {
const render = value.render.bind(value);
value.render = (container, options = {}) => {
window.__collected = {
site_key: options.sitekey,
page_action: options.action,
data: options.cData,
page_data: options.chlPageData,
user_agent: navigator.userAgent,
};
return render(container, options);
};
real = value;
},
});
"""
def collect(page_url):
"""Hook turnstile.render: its options carry every value the task needs."""
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.add_init_script(HOOK)
page.goto(page_url)
page.wait_for_function("window.__collected !== null", timeout=30000)
collected = page.evaluate(
"() => ({ page_url: location.href, ...window.__collected })"
)
browser.close()
return {key: value for key, value in collected.items() if value is not None}
task = {"method": "TurnstileTaskProxyless", **collect(PAGE_URL)}
print("collected task:", task)
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Keep at least three seconds between polls: the result endpoint is
# rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
What each value is and where it lives
page_urlUsually stable
Page URL
Address bar / Network → Referer
Use the exact URL where the widget is initialized, without relying on a post-login redirect.
site_keyUsually stable
Site key
Elements → data-sitekey, or Network → k/sitekey
Inspect the CAPTCHA container first; if absent, inspect the widget iframe or initialization request.
page_actionUsually stable
Page action
Sources search → grecaptcha.execute, or turnstile.render
Copy the action string used by the page, for example login, checkout or managed.
dataFresh value
Challenge data
Widget callback or initialization object
For Cloudflare this is commonly cData; for other types inspect the provider-specific payload.
user_agentUsually stable
Browser User-Agent
Console → navigator.userAgent
Use the same browser identity when submitting the returned solution.
Address: https://solvecaptcha.net/api/createTask Method: POST Default provider task type: TurnstileTask
Compatibility alias: this historical method remains accepted and is mapped internally to TurnstileTask.
Response fields use snake_case. Token-based tasks include solution.token; existing reCAPTCHA integrations also continue to receive solution.gRecaptchaResponse.
Request properties
Property
Required
Purpose
method
Yes
TurnstileTaskProxyless
page_url
Yes
Value extracted from the target CAPTCHA page.
site_key
Yes
Value extracted from the target CAPTCHA page.
page_action
No
Optional task-specific value.
data
No
Optional task-specific value.
user_agent
No
Optional task-specific value.
proxy_type, proxy_address, proxy_port
No
Use a customer proxy when the target rejects built-in provider proxies.
Working example
Replace YOUR_API_KEY with the key from your account settings and the uppercase placeholders with the values you collected above. Each snippet creates the task, polls until it is solved and prints the solution.
# Requirements: pip install requests
# Run: python3 solve.py
import sys
import time
import requests
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
task = {
"method": "TurnstileTaskProxyless",
"page_url": "PAGE_URL",
"site_key": "SITE_KEY"
}
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Poll until the task leaves the processing state. Keep at least three
# seconds between calls: the result endpoint is rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
solve.mjs
// Requirements: Node.js 18 or newer (uses the built-in fetch)
// Run: node solve.mjs
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const task = {
"method": "TurnstileTaskProxyless",
"page_url": "PAGE_URL",
"site_key": "SITE_KEY"
};
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Poll until the task leaves the processing state. Keep at least three
// seconds between calls: the result endpoint is rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
RecaptchaV2EnterpriseTask
Solve Google reCAPTCHA V2 Enterprise.
reCAPTCHA V2 EnterpriseRecaptchaV2EnterpriseTask
Identify → collect → submit
Collect the values from the current widget
Use DevTools on a page you are authorized to integrate. Static identifiers can be reused; values marked Fresh value must be captured again for every rendered challenge.
How to find all parameters required to create a task
Manually
Open the page in a browserLoad the page where the CAPTCHA appears, on a site you are authorised to integrate.
Inspect the CAPTCHA containerRight-click the widget and choose Inspect. Copy data-sitekey from the <div class="g-recaptcha"> element; copy data-s too when the page sets it.
Or read the sitekey from the networkIn Network, filter for recaptcha and open the anchor request: its k query parameter is the sitekey.
Find the action for score-based variantsSearch Sources for grecaptcha.execute; the action string passed there is page_action.
Note whether the widget is invisibleAn element carrying size="invisible" means you should send is_invisible: true.
Automatically
The first snippet reports the values. The two Playwright scripts collect them from a live page and solve them through this API in one run — replace YOUR_API_KEY and PAGE_URL.
paste into DevTools → Console
Run this on the page with the CAPTCHA. It prints the task body to copy into your request.
// RecaptchaV2EnterpriseTask — collect the task parameters from this page.
// Paste into DevTools → Console on the page showing the CAPTCHA.
(() => {
const el = document.querySelector('.g-recaptcha[data-sitekey], [data-sitekey]');
const task = { method: "RecaptchaV2EnterpriseTask", page_url: location.href, site_key: el?.getAttribute('data-sitekey') || null };
if (el?.getAttribute('data-s')) task.data_s = el.getAttribute('data-s');
if (el?.getAttribute('data-size') === 'invisible') task.is_invisible = true;
// Fall back to the anchor request, which always carries k=<sitekey>.
if (!task.site_key) {
const anchor = performance.getEntriesByType('resource')
.map((entry) => entry.name)
.find((name) => name.includes('/recaptcha/') && name.includes('k='));
if (anchor) task.site_key = new URL(anchor).searchParams.get('k');
}
console.log(JSON.stringify({ task }, null, 2));
return task;
})();
collect-and-solve.mjs
npm i playwright — collects the parameters from a live page and solves them through this API.
// RecaptchaV2EnterpriseTask — collect the parameters from a live page, then solve them here.
// Requirements: npm i playwright · Run: node collect-and-solve.mjs
import { chromium } from 'playwright';
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const PAGE_URL = 'https://example.com/page-with-captcha';
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
async function collect(pageUrl) {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto(pageUrl);
await page.waitForTimeout(6000);
const collected = await page.evaluate(() => {
const el = document.querySelector('[data-sitekey], [data-captcha-id], [data-scene-id]');
return {
page_url: location.href,
user_agent: navigator.userAgent,
site_key: el
? el.getAttribute('data-sitekey') || el.getAttribute('data-captcha-id') || el.getAttribute('data-scene-id')
: null,
};
});
await browser.close();
// Fill in the metadata fields documented below before submitting.
return Object.fromEntries(Object.entries(collected).filter(([, value]) => value != null));
}
const task = { method: 'RecaptchaV2EnterpriseTask', ...(await collect(PAGE_URL)) };
console.log('collected task:', JSON.stringify(task, null, 2));
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Keep at least three seconds between polls: the result endpoint is
// rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
# RecaptchaV2EnterpriseTask — collect the parameters from a live page, then solve them here.
# Requirements: pip install playwright requests && playwright install chromium
# Run: python3 collect_and_solve.py
import sys
import time
import requests
from playwright.sync_api import sync_playwright
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
PAGE_URL = "https://example.com/page-with-captcha"
READ = """
() => {
const el = document.querySelector('[data-sitekey], [data-captcha-id], [data-scene-id]');
return {
page_url: location.href,
user_agent: navigator.userAgent,
site_key: el
? el.getAttribute('data-sitekey') || el.getAttribute('data-captcha-id') || el.getAttribute('data-scene-id')
: null,
};
}
"""
def collect(page_url):
"""Read the widget identifier, then add the metadata documented below."""
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto(page_url)
page.wait_for_timeout(6000)
collected = page.evaluate(READ)
browser.close()
return {key: value for key, value in collected.items() if value is not None}
task = {"method": "RecaptchaV2EnterpriseTask", **collect(PAGE_URL)}
print("collected task:", task)
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Keep at least three seconds between polls: the result endpoint is
# rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
What each value is and where it lives
page_urlUsually stable
Page URL
Address bar / Network → Referer
Use the exact URL where the widget is initialized, without relying on a post-login redirect.
site_keyUsually stable
Site key
Elements → data-sitekey, or Network → k/sitekey
Inspect the CAPTCHA container first; if absent, inspect the widget iframe or initialization request.
page_actionUsually stable
Page action
Sources search → grecaptcha.execute, or turnstile.render
Copy the action string used by the page, for example login, checkout or managed.
enterprise_payloadFresh value
Enterprise payload
Network / grecaptcha.enterprise initialization
Preserve the complete object and its original key casing.
api_domainUsually stable
API domain
Network → script host
Send it only when the page loads reCAPTCHA from recaptcha.net instead of google.com.
user_agentUsually stable
Browser User-Agent
Console → navigator.userAgent
Use the same browser identity when submitting the returned solution.
cookiesFresh value
Cookies
Application → Cookies / Network headers
Send only cookies required by the current CAPTCHA flow.
Address: https://solvecaptcha.net/api/createTask Method: POST Default provider task type: RecaptchaV2EnterpriseTask
Response fields use snake_case. Token-based tasks include solution.token; existing reCAPTCHA integrations also continue to receive solution.gRecaptchaResponse.
Request properties
Property
Required
Purpose
method
Yes
RecaptchaV2EnterpriseTask
page_url
Yes
Value extracted from the target CAPTCHA page.
site_key
Yes
Value extracted from the target CAPTCHA page.
page_action
No
Optional task-specific value.
enterprise_payload
No
Optional task-specific value.
api_domain
No
Optional task-specific value.
user_agent
No
Optional task-specific value.
cookies
No
Optional task-specific value.
proxy_type, proxy_address, proxy_port
No
Use a customer proxy when the target rejects built-in provider proxies.
Working example
Replace YOUR_API_KEY with the key from your account settings and the uppercase placeholders with the values you collected above. Each snippet creates the task, polls until it is solved and prints the solution.
Use DevTools on a page you are authorized to integrate. Static identifiers can be reused; values marked Fresh value must be captured again for every rendered challenge.
How to find all parameters required to create a task
Manually
Open the page in a browserLoad the page where the CAPTCHA appears, on a site you are authorised to integrate.
Inspect the CAPTCHA containerRight-click the widget and choose Inspect. Copy data-sitekey from the <div class="g-recaptcha"> element; copy data-s too when the page sets it.
Or read the sitekey from the networkIn Network, filter for recaptcha and open the anchor request: its k query parameter is the sitekey.
Find the action for score-based variantsSearch Sources for grecaptcha.execute; the action string passed there is page_action.
Note whether the widget is invisibleAn element carrying size="invisible" means you should send is_invisible: true.
Automatically
The first snippet reports the values. The two Playwright scripts collect them from a live page and solve them through this API in one run — replace YOUR_API_KEY and PAGE_URL.
paste into DevTools → Console
Run this on the page with the CAPTCHA. It prints the task body to copy into your request.
// RecaptchaV2EnterpriseTaskProxyless — collect the task parameters from this page.
// Paste into DevTools → Console on the page showing the CAPTCHA.
(() => {
const el = document.querySelector('.g-recaptcha[data-sitekey], [data-sitekey]');
const task = { method: "RecaptchaV2EnterpriseTaskProxyless", page_url: location.href, site_key: el?.getAttribute('data-sitekey') || null };
if (el?.getAttribute('data-s')) task.data_s = el.getAttribute('data-s');
if (el?.getAttribute('data-size') === 'invisible') task.is_invisible = true;
// Fall back to the anchor request, which always carries k=<sitekey>.
if (!task.site_key) {
const anchor = performance.getEntriesByType('resource')
.map((entry) => entry.name)
.find((name) => name.includes('/recaptcha/') && name.includes('k='));
if (anchor) task.site_key = new URL(anchor).searchParams.get('k');
}
console.log(JSON.stringify({ task }, null, 2));
return task;
})();
collect-and-solve.mjs
npm i playwright — collects the parameters from a live page and solves them through this API.
// RecaptchaV2EnterpriseTaskProxyless — collect the parameters from a live page, then solve them here.
// Requirements: npm i playwright · Run: node collect-and-solve.mjs
import { chromium } from 'playwright';
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://solvecaptcha.net/api';
const PAGE_URL = 'https://example.com/page-with-captcha';
const headers = {
Authorization: `Bearer ${API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const post = async (path, payload) => {
const response = await fetch(`${BASE_URL}/${path}`, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return response.json();
};
async function collect(pageUrl) {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto(pageUrl);
await page.waitForTimeout(6000);
const collected = await page.evaluate(() => {
const el = document.querySelector('[data-sitekey], [data-captcha-id], [data-scene-id]');
return {
page_url: location.href,
user_agent: navigator.userAgent,
site_key: el
? el.getAttribute('data-sitekey') || el.getAttribute('data-captcha-id') || el.getAttribute('data-scene-id')
: null,
};
});
await browser.close();
// Fill in the metadata fields documented below before submitting.
return Object.fromEntries(Object.entries(collected).filter(([, value]) => value != null));
}
const task = { method: 'RecaptchaV2EnterpriseTaskProxyless', ...(await collect(PAGE_URL)) };
console.log('collected task:', JSON.stringify(task, null, 2));
const created = await post('createTask', { task });
if (created.error_id) {
throw new Error(`createTask failed: ${created.error_code} ${created.error_description}`);
}
console.log('task_id:', created.task_id);
// Keep at least three seconds between polls: the result endpoint is
// rate limited per task.
const deadline = Date.now() + 180_000;
while (Date.now() < deadline) {
await sleep(3000);
const result = await post('getTaskResult', { task_id: created.task_id });
if (result.status === 'processing') continue;
if (result.status === 'ready') {
console.log('solution:', result.solution);
} else {
console.error('failed:', result.error_code, result.error_description);
}
process.exit(0);
}
console.error('timed out while waiting for the solution');
# RecaptchaV2EnterpriseTaskProxyless — collect the parameters from a live page, then solve them here.
# Requirements: pip install playwright requests && playwright install chromium
# Run: python3 collect_and_solve.py
import sys
import time
import requests
from playwright.sync_api import sync_playwright
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://solvecaptcha.net/api"
PAGE_URL = "https://example.com/page-with-captcha"
READ = """
() => {
const el = document.querySelector('[data-sitekey], [data-captcha-id], [data-scene-id]');
return {
page_url: location.href,
user_agent: navigator.userAgent,
site_key: el
? el.getAttribute('data-sitekey') || el.getAttribute('data-captcha-id') || el.getAttribute('data-scene-id')
: null,
};
}
"""
def collect(page_url):
"""Read the widget identifier, then add the metadata documented below."""
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto(page_url)
page.wait_for_timeout(6000)
collected = page.evaluate(READ)
browser.close()
return {key: value for key, value in collected.items() if value is not None}
task = {"method": "RecaptchaV2EnterpriseTaskProxyless", **collect(PAGE_URL)}
print("collected task:", task)
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
created = session.post(f"{BASE_URL}/createTask", json={"task": task}, timeout=30).json()
if created.get("error_id"):
sys.exit(f"createTask failed: {created.get('error_code')} {created.get('error_description')}")
task_id = created["task_id"]
print("task_id:", task_id)
# Keep at least three seconds between polls: the result endpoint is
# rate limited per task.
deadline = time.time() + 180
while time.time() < deadline:
time.sleep(3)
result = session.post(
f"{BASE_URL}/getTaskResult", json={"task_id": task_id}, timeout=30
).json()
status = result.get("status")
if status == "processing":
continue
if status == "ready":
print("solution:", result["solution"])
else:
print("failed:", result.get("error_code"), result.get("error_description"))
break
else:
print("timed out while waiting for the solution")
What each value is and where it lives
page_urlUsually stable
Page URL
Address bar / Network → Referer
Use the exact URL where the widget is initialized, without relying on a post-login redirect.
site_keyUsually stable
Site key
Elements → data-sitekey, or Network → k/sitekey
Inspect the CAPTCHA container first; if absent, inspect the widget iframe or initialization request.
page_actionUsually stable
Page action
Sources search → grecaptcha.execute, or turnstile.render
Copy the action string used by the page, for example login, checkout or managed.
enterprise_payloadFresh value
Enterprise payload
Network / grecaptcha.enterprise initialization
Preserve the complete object and its original key casing.
api_domainUsually stable
API domain
Network → script host
Send it only when the page loads reCAPTCHA from recaptcha.net instead of google.com.
user_agentUsually stable
Browser User-Agent
Console → navigator.userAgent
Use the same browser identity when submitting the returned solution.
cookiesFresh value
Cookies
Application → Cookies / Network headers
Send only cookies required by the current CAPTCHA flow.
Address: https://solvecaptcha.net/api/createTask Method: POST Default provider task type: RecaptchaV2EnterpriseTask
Compatibility alias: this historical method remains accepted and is mapped internally to RecaptchaV2EnterpriseTask.
Response fields use snake_case. Token-based tasks include solution.token; existing reCAPTCHA integrations also continue to receive solution.gRecaptchaResponse.
Request properties
Property
Required
Purpose
method
Yes
RecaptchaV2EnterpriseTaskProxyless
page_url
Yes
Value extracted from the target CAPTCHA page.
site_key
Yes
Value extracted from the target CAPTCHA page.
page_action
No
Optional task-specific value.
enterprise_payload
No
Optional task-specific value.
api_domain
No
Optional task-specific value.
user_agent
No
Optional task-specific value.
cookies
No
Optional task-specific value.
proxy_type, proxy_address, proxy_port
No
Use a customer proxy when the target rejects built-in provider proxies.
Working example
Replace YOUR_API_KEY with the key from your account settings and the uppercase placeholders with the values you collected above. Each snippet creates the task, polls until it is solved and prints the solution.