reCAPTCHA v3 Enterprise
Summary
| Property | Value |
|---|---|
| v1 type | recaptcha.v3.enterprise |
| Compatibility names | RecaptchaV3EnterpriseTask, RecaptchaV3TaskProxyless |
| Proxy | not used |
| Deadline | 120 seconds (starting value). A task not solved by then fails with timeout and is not charged. |
| 2captcha legacy API | method=userrecaptcha&version=v3&enterprise=1 (details) |
Parameters
The params object of POST /v1/tasks. Unknown fields are rejected with 422 invalid_params.
| Field | Type | Description |
|---|---|---|
website_urlrequired | string | Full URL of the page that shows the captcha (http or https). format: uri · pattern: ^[Hh][Tt][Tt][Pp][Ss]?:// · min length 8 · max length 4,096 |
website_keyrequired | string | The site key of the captcha widget. min length 1 · max length 512 |
page_actionoptional | string | The action passed to grecaptcha.execute. min length 1 · max length 256 |
min_scoreoptional | number | Minimum score the token should reach (0.1 to 0.9). ≥ 0.1 · ≤ 0.9 |
enterprise_payloadoptional | object | Extra enterprise parameters passed to the widget as is, e.g. {"s": "..."} for reCAPTCHA Enterprise or {"rqdata": "..."} for hCaptcha. max 32 keys |
api_domainoptional | string | Domain the widget is loaded from, e.g. www.recaptcha.net. Omit for the default. format: hostname · min length 1 · max length 253 |
user_agentoptional | string | Browser User-Agent. min length 1 · max length 1,024 |
cookiesoptional | string | Cookies for the target site, as in a Cookie header: name1=value1; name2=value2. max length 8,192 |
Solution
The solution object of a solved task.
| Field | Type | Description |
|---|---|---|
tokenrequired | string | Token to submit to the target site. Single use. min length 1 |
user_agentoptional | string | User-Agent the token was obtained with; use it when submitting the token. min length 1 · max length 1,024 |
Example: native API (v1)
Runs as is with a test key (nop_test_…) in the sandbox; use a live key for real tasks.
{ "type": "recaptcha.v3.enterprise", "params": { "website_url": "https://example.com/login", "website_key": "6Lc_aCMTAAAAABx7u2W0WPXnVbI_v6ZdbM6rYf16", "page_action": "login" }}export NOPTCHA_KEY=nop_test_... # your test or live key
# waits up to 60 s; 200 = finished (solved or failed), 202 = still processingIDEMPOTENCY_KEY=$(uuidgen) # one key per task you want; a retry of the same request reuses itcurl -s -X POST "https://api.noptcha.com/v1/tasks" \ -H "Authorization: Bearer $NOPTCHA_KEY" \ -H 'Prefer: wait=60' \ -H "Idempotency-Key: $IDEMPOTENCY_KEY" \ -H 'Content-Type: application/json' \ -d @- <<EOF{ "type": "recaptcha.v3.enterprise", "params": { "website_url": "https://example.com/login", "website_key": "6Lc_aCMTAAAAABx7u2W0WPXnVbI_v6ZdbM6rYf16", "page_action": "login" }}EOF
# on 202: long-poll with the "id" from the responseTASK_ID=...curl -s "https://api.noptcha.com/v1/tasks/$TASK_ID?wait=60" \ -H "Authorization: Bearer $NOPTCHA_KEY"import osimport timeimport uuid
import requests
API = "https://api.noptcha.com"HEADERS = {"Authorization": f"Bearer {os.environ['NOPTCHA_KEY']}"} # a nop_test_ key runs in the sandbox
# One Idempotency-Key per task you want. If you retry this request after a network error, send the same key and# the same body bytes: you get the same task back, not a second one (see Idempotency on the Tasks page).idempotency_key = str(uuid.uuid4())r = requests.post( f"{API}/v1/tasks", headers={**HEADERS, "Prefer": "wait=60", "Idempotency-Key": idempotency_key}, json={ "type": "recaptcha.v3.enterprise", "params": { "website_url": "https://example.com/login", "website_key": "6Lc_aCMTAAAAABx7u2W0WPXnVbI_v6ZdbM6rYf16", "page_action": "login", }, }, timeout=100,)task = r.json()if r.status_code >= 400: raise RuntimeError(f"{task['code']}: {task.get('detail', '')}")while task["status"] == "processing": # 202: not finished within the wait time.sleep(1) # a long poll can return early (for example when wait slots are full) r = requests.get(f"{API}/v1/tasks/{task['id']}", params={"wait": 60}, headers=HEADERS, timeout=100) task = r.json() if r.status_code >= 400: raise RuntimeError(f"{task['code']}: {task.get('detail', '')}")
if task["status"] == "solved": print(task["solution"])else: print("failed:", task["error"]["code"], task["error"]["message"])import { randomUUID } from 'node:crypto';
const API = 'https://api.noptcha.com';const HEADERS = { Authorization: `Bearer ${process.env.NOPTCHA_KEY}` }; // a nop_test_ key runs in the sandbox
async function v1(path, init = {}) { const res = await fetch(`${API}${path}`, { ...init, headers: { ...HEADERS, ...init.headers } }); const data = await res.json(); if (!res.ok) throw new Error(`${data.code}: ${data.detail ?? ''}`); return data;}
// One Idempotency-Key per task you want. If you retry this request after a network error, send the same key and// the same body bytes: you get the same task back, not a second one (see Idempotency on the Tasks page).const idempotencyKey = randomUUID();let task = await v1('/v1/tasks', { method: 'POST', headers: { 'Content-Type': 'application/json', Prefer: 'wait=60', 'Idempotency-Key': idempotencyKey }, body: JSON.stringify({ type: "recaptcha.v3.enterprise", params: { website_url: "https://example.com/login", website_key: "6Lc_aCMTAAAAABx7u2W0WPXnVbI_v6ZdbM6rYf16", page_action: "login", }, }),});while (task.status === 'processing') { await new Promise((r) => setTimeout(r, 1000)); // a long poll can return early (for example when wait slots are full) task = await v1(`/v1/tasks/${task.id}?wait=60`); // long poll}if (task.status === 'solved') console.log(task.solution);else console.log('failed:', task.error.code, task.error.message);In the sandbox the task is solved at once and solution is:
{ "token": "NOPTCHA_TEST_TOKEN_7259140378796032", "user_agent": "Mozilla/5.0 (Noptcha test)"}Compatibility API
| Name | Proxy | Notes |
|---|---|---|
RecaptchaV3EnterpriseTask | ignored | |
RecaptchaV3TaskProxyless | ignored | Only with isEnterprise: true. |
Task fields (in task, next to type) and the v1 parameter each one becomes:
| Compatibility field | v1 parameter |
|---|---|
apiDomain | api_domain |
cookies | cookies |
enterprisePayload | enterprise_payload |
isEnterprise | accepted; only selects the type |
isInvisible | is_invisible |
minScore | min_score |
pageAction | page_action |
userAgent | user_agent |
websiteKey | website_key |
websiteURL | website_url |
Solution fields in getTaskResult:
| Compatibility field | v1 solution field |
|---|---|
gRecaptchaResponse | token |
userAgent | user_agent |
Example: compatibility API
{ "clientKey": "nop_test_…", "task": { "type": "RecaptchaV3TaskProxyless", "isEnterprise": true, "websiteURL": "https://example.com/login", "websiteKey": "6Lc_aCMTAAAAABx7u2W0WPXnVbI_v6ZdbM6rYf16", "pageAction": "login" }}export NOPTCHA_KEY=nop_test_... # your test or live key
# 1. create the taskcurl -s -X POST "https://api.noptcha.com/createTask" \ -H 'Content-Type: application/json' \ -d @- <<EOF{ "clientKey": "$NOPTCHA_KEY", "task": { "type": "RecaptchaV3TaskProxyless", "isEnterprise": true, "websiteURL": "https://example.com/login", "websiteKey": "6Lc_aCMTAAAAABx7u2W0WPXnVbI_v6ZdbM6rYf16", "pageAction": "login" }}EOF
# 2. poll with the taskId from step 1 every few seconds until "status" is "ready"TASK_ID=...curl -s -X POST "https://api.noptcha.com/getTaskResult" \ -H 'Content-Type: application/json' \ -d @- <<EOF{ "clientKey": "$NOPTCHA_KEY", "taskId": $TASK_ID}EOFimport osimport time
import requests
API = "https://api.noptcha.com"KEY = os.environ["NOPTCHA_KEY"] # a nop_test_ key runs in the sandbox: free, fixed answers
def call(method, payload): r = requests.post(f"{API}/{method}", json={"clientKey": KEY, **payload}, timeout=30) r.raise_for_status() data = r.json() if data["errorId"]: raise RuntimeError(f"{data['errorCode']}: {data.get('errorDescription', '')}") return data
created = call("createTask", {"task": { "type": "RecaptchaV3TaskProxyless", "isEnterprise": True, "websiteURL": "https://example.com/login", "websiteKey": "6Lc_aCMTAAAAABx7u2W0WPXnVbI_v6ZdbM6rYf16", "pageAction": "login",}})result = created # some types are solved at once and come back with "status": "ready"deadline = time.time() + 300while result.get("status") != "ready": if time.time() > deadline: raise TimeoutError(created["taskId"]) time.sleep(3) result = call("getTaskResult", {"taskId": created["taskId"]})print(result["solution"])const API = 'https://api.noptcha.com';const KEY = process.env.NOPTCHA_KEY; // a nop_test_ key runs in the sandbox: free, fixed answers
async function call(method, payload) { const res = await fetch(`${API}/${method}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ clientKey: KEY, ...payload }), }); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); if (data.errorId) throw new Error(`${data.errorCode}: ${data.errorDescription ?? ''}`); return data;}
const created = await call('createTask', { task: { type: "RecaptchaV3TaskProxyless", isEnterprise: true, websiteURL: "https://example.com/login", websiteKey: "6Lc_aCMTAAAAABx7u2W0WPXnVbI_v6ZdbM6rYf16", pageAction: "login",} });let result = created; // some types are solved at once and come back with status "ready"const deadline = Date.now() + 300_000;while (result.status !== 'ready') { if (Date.now() > deadline) throw new Error(`timed out: ${created.taskId}`); await new Promise((r) => setTimeout(r, 3000)); result = await call('getTaskResult', { taskId: created.taskId });}console.log(result.solution);In the sandbox getTaskResult returns "status": "ready" and solution:
{ "gRecaptchaResponse": "NOPTCHA_TEST_TOKEN_7259140378796032", "userAgent": "Mozilla/5.0 (Noptcha test)"}