Quick Start

Get up and running in under 2 minutes. Three steps to your first CAPTCHA solve.

1

Create an Account

Sign up for a free account at uncaptcha.dev. The free plan includes 100 solves per month with no credit card required.

bash
curl -X POST https://api.uncaptcha.dev/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "password": "your-password"}'
2

Get Your API Key

After signing in, go to your Dashboard and create an API key. The key is shown only once -- store it securely.

bash
# Login to get JWT
TOKEN=$(curl -s -X POST https://api.uncaptcha.dev/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "password": "your-password"}' \
  | jq -r '.token')

# Create API key
curl -X POST https://api.uncaptcha.dev/keys \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "My First Key"}'
3

Solve Your First CAPTCHA

Make a single POST request with the site key and page URL. The API returns the solved token.

curl -X POST https://api.uncaptcha.dev/v1/solve/sync \
  -H "X-API-Key: ac-your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "recaptcha_v2",
    "siteKey": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
    "pageUrl": "https://www.google.com/recaptcha/api2/demo"
  }'
>
The synchronous endpoint (/v1/solve/sync) waits up to 120 seconds and returns the token directly. For fire-and-forget workflows, use the async /v1/solve endpoint and poll with /v1/result/:id.

Authentication

uncaptcha.dev uses two authentication methods depending on the endpoint type.

API Key Authentication

All /v1/* endpoints (solve, balance, types, report, history) authenticate via the X-API-Key header. Your API key starts with the prefix ac-.

bash
curl https://api.uncaptcha.dev/v1/balance \
  -H "X-API-Key: ac-your-api-key-here"
!
Never expose your API key in client-side code. Always call the API from your backend server.

JWT Bearer Token

Account management endpoints (/keys, /auth/me) use JWT Bearer token authentication. Obtain a token by calling POST /auth/login. Tokens expire after 7 days.

bash
curl https://api.uncaptcha.dev/keys \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

Endpoints

CAPTCHA Solving

POST/v1/solve

Submit a CAPTCHA for solving. Returns the result immediately with a taskId for reference. The result is also persisted for later retrieval via GET /v1/result/:id.

Auth: X-API-Key

Request Body

{
  "type": "recaptcha_v2",
  "siteKey": "6Le-wvkSAAAAAPBMRTvw...",
  "pageUrl": "https://example.com/login",
  "proxy": "http://user:pass@host:port"  // optional
}

Response

{
  "taskId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "solved",
  "solution": {
    "token": "03AGdBq26Hv8..."
  },
  "captcha_type": "recaptcha_v2",
  "elapsed": 6204
}
POST/v1/solve/sync

Synchronous solve endpoint. Blocks until the CAPTCHA is solved or the request times out (120s max). Recommended for most integrations.

Auth: X-API-Key

Request Body

{
  "type": "recaptcha_v2",
  "siteKey": "6Le-wvkSAAAAAPBMRTvw...",
  "pageUrl": "https://example.com/login",
  "proxy": "http://user:pass@host:port"  // optional
}

Response

{
  "status": "solved",
  "token": "03AGdBq26Hv8...",
  "captcha_type": "recaptcha_v2",
  "elapsed": 6204,
  "taskId": "550e8400-e29b-41d4-a716-446655440000"
}
GET/v1/result/:id

Retrieve a previously completed solve result by its taskId. Results are persisted in the database and scoped to your account.

Auth: X-API-Key

Response

{
  "taskId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "solved",
  "solution": {
    "token": "03AGdBq26Hv8..."
  },
  "captcha_type": "recaptcha_v2",
  "elapsed": 6204,
  "created_at": "2026-03-28T12:00:00.000Z"
}

Account & Usage

GET/v1/balance

Check your current plan, usage statistics, and remaining solve quota for the current billing period.

Auth: X-API-Key

Response

{
  "plan": "pro",
  "period": "2026-03",
  "solves_used": 423,
  "solves_included": 5000,
  "solves_remaining": 4577,
  "cost_usd": 4.23
}
GET/v1/types

List all CAPTCHA types currently supported by the API.

Auth: X-API-Key

Response

{
  "types": [
    "recaptcha_v2", "recaptcha_v3", "recaptcha_ent",
    "turnstile", "funcaptcha",
    "geetest_v3", "geetest_v4", "aws_waf", "image_captcha",
    "datadome"
  ],
  "count": 10
}
POST/v1/report

Report whether a solve result was correct or incorrect. Used for quality monitoring and feedback.

Auth: X-API-Key

Request Body

{
  "taskId": "550e8400-e29b-41d4-a716-446655440000",
  "correct": false
}

Response

{
  "success": true,
  "taskId": "550e8400-e29b-41d4-a716-446655440000",
  "reported": "bad"
}
GET/v1/history

Retrieve your paginated solve history. Filter by CAPTCHA type and control pagination with limit and offset.

Auth: X-API-Key

Query Parameters

limitintegerNumber of results (default: 50, max: 200)
offsetintegerPagination offset (default: 0)
typestringFilter by CAPTCHA type (e.g. "turnstile")

Response

{
  "history": [
    {
      "id": "uuid",
      "task_id": "uuid",
      "captcha_type": "recaptcha_v2",
      "status": "solved",
      "cost_usd": 0.01,
      "created_at": "2026-03-28T12:00:00.000Z",
      "reported": null
    }
  ],
  "limit": 50,
  "offset": 0
}

Authentication

POST/auth/signup

Register a new account. Automatically creates a free subscription with 100 solves/month.

Request Body

{
  "email": "you@example.com",
  "password": "your-secure-password",
  "country": "US"  // optional
}

Response

{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "user": {
    "id": "uuid",
    "email": "you@example.com",
    "plan_id": "free",
    "created_at": "2026-03-28T12:00:00.000Z"
  }
}
POST/auth/login

Authenticate with email and password. Returns a JWT token valid for 7 days.

Request Body

{
  "email": "you@example.com",
  "password": "your-secure-password"
}

Response

{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "user": {
    "id": "uuid",
    "email": "you@example.com",
    "plan_id": "pro"
  }
}

API Key Management

POST/keys

Create a new API key. The full key (ac-...) is returned only once in the response -- store it securely.

Auth: Bearer JWT

Request Body

{
  "name": "Production"  // optional label
}

Response

{
  "id": "uuid",
  "key": "ac-a1b2c3d4e5f6...",
  "prefix": "ac-a1b2c3d4e5f6",
  "name": "Production",
  "created_at": "2026-03-28T12:00:00.000Z"
}
GET/keys

List all active API keys for your account. Only the key prefix is shown (the full key is not stored).

Auth: Bearer JWT

Response

{
  "keys": [
    {
      "id": "uuid",
      "key_prefix": "ac-a1b2c3d4...",
      "name": "Production",
      "created_at": "2026-03-28T12:00:00.000Z",
      "last_used_at": "2026-03-28T14:30:00.000Z"
    }
  ]
}
DELETE/keys/:id

Revoke (deactivate) an API key. The key will immediately stop working for all requests.

Auth: Bearer JWT

Response

{
  "success": true
}

CAPTCHA Types

uncaptcha.dev supports 10 CAPTCHA types. Pass the type field in your solve request to specify which CAPTCHA to solve.

TypeNameAvg. TimeRequired FieldsDescription
recaptcha_v2reCAPTCHA v2~18ssiteKey, pageUrlStandard checkbox and image-challenge reCAPTCHA widget
recaptcha_v3reCAPTCHA v3~10ssiteKey, pageUrl, action?, minScore?Invisible score-based reCAPTCHA. Supports action and minScore parameters
recaptcha_entreCAPTCHA Enterprise~18ssiteKey, pageUrl, enterprisePayload?Google reCAPTCHA Enterprise edition with enterprise payload support
turnstileCloudflare Turnstile~8ssiteKey, pageUrlCloudflare's privacy-focused CAPTCHA alternative
funcaptchaFunCaptcha~15ssiteKey, pageUrl, serviceUrl?Arkose Labs FunCaptcha interactive challenges
geetest_v3GeeTest v3~12ssiteKey, pageUrl, challenge?GeeTest slide and click challenges (version 3)
geetest_v4GeeTest v4~12ssiteKey, pageUrlGeeTest v4 adaptive challenges with captcha_id
aws_wafAWS WAF~20ssiteKey, pageUrlAmazon Web Services WAF CAPTCHA protection
image_captchaImage CAPTCHA~5simage (base64), pageUrl?Classic image-to-text OCR recognition (PNG, JPEG, WEBP)
datadomeDataDome~15scaptchaUrl, userAgent, proxyDataDome slider CAPTCHAs (requires proxy)
i
All solve times are approximate averages measured under normal conditions. Actual solve times may vary depending on CAPTCHA complexity, provider load, and network latency.

DataDome — Special Parameters

DataDome uses different request fields than other CAPTCHA types. Instead of siteKey and pageUrl, you must supply the full CAPTCHA URL, a user agent, and a proxy. A proxy is required — DataDome does not support proxyless solving.

json
// POST /v1/solve/sync
{
  "type": "datadome",
  "captchaUrl": "https://geo.captcha-delivery.com/captcha/?initialCid=...&t=fe&...",
  "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...",
  "proxy": "host:port:user:pass"
}
!
DataDome requires a residential or mobile proxy. The proxy format is host:port:user:pass. The captchaUrl is the full URL from the DataDome challenge redirect — it begins with https://geo.captcha-delivery.com/captcha/.

SDKs

Official client libraries for Python and Node.js. Both SDKs handle authentication, retries, timeout management, and typed error handling out of the box.

Python SDK

bash
pip install uncaptcha

Synchronous Usage

python
from uncaptcha import Uncaptcha

solver = Uncaptcha("ac-your-api-key")

# reCAPTCHA v2
result = solver.recaptcha(
    site_key="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
    page_url="https://www.google.com/recaptcha/api2/demo",
)
print(result["token"])

# Cloudflare Turnstile
result = solver.turnstile(
    site_key="0x4AAAAAAABS7vwvV6VFfMcD",
    page_url="https://example.com",
)

# reCAPTCHA v3 with action and score
result = solver.recaptcha(
    site_key="6LdyC2cUAAAAACGuDKpXeDorzUDWXmdqeg-xy696",
    page_url="https://example.com",
    version="v3",
    action="login",
    min_score=0.9,
)

# Check balance
balance = solver.balance()
print(f"Used {balance['solves_used']} of {balance['solves_included']}")

Async Usage

python
from uncaptcha import AsyncUncaptcha

async with AsyncUncaptcha("ac-your-api-key") as solver:
    result = await solver.recaptcha(
        site_key="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
        page_url="https://www.google.com/recaptcha/api2/demo",
    )
    print(result["token"])
>
Install with pip install uncaptcha[async] for async support (includes aiohttp).

Node.js SDK

bash
npm install uncaptcha
javascript
import { Uncaptcha } from 'uncaptcha';

const solver = new Uncaptcha('ac-your-api-key');

// reCAPTCHA v2
const { token } = await solver.recaptcha({
  siteKey: '6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
  pageUrl: 'https://www.google.com/recaptcha/api2/demo',
});
console.log(token);

// Cloudflare Turnstile
const turnstile = await solver.turnstile({
  siteKey: '0x4AAAAAAABS7vwvV6VFfMcD',
  pageUrl: 'https://example.com',
});

// reCAPTCHA v3 with action
const v3 = await solver.recaptcha({
  siteKey: '6LdyC2cUAAAAACGuDKpXeDorzUDWXmdqeg-xy696',
  pageUrl: 'https://example.com',
  version: 'v3',
  action: 'login',
  minScore: 0.9,
});

// Check balance
const balance = await solver.balance();
console.log(`Used ${balance.solves_used} of ${balance.solves_included}`);

// List supported types
const { types } = await solver.types();
console.log('Supported:', types.join(', '));

Available Methods

recaptcha(params)Solve reCAPTCHA v2, v3, or Enterprise
turnstile(params)Solve Cloudflare Turnstile
hcaptcha(params)Solve hCaptcha
funcaptcha(params)Solve FunCaptcha / Arkose Labs
geetest(params)Solve GeeTest v3 or v4
awsWaf(params)Solve AWS WAF CAPTCHA
image(params)Solve image CAPTCHA via OCR
balance()Get account balance and usage
types()List supported CAPTCHA types

MCP Integration

The fastest way to add CAPTCHA solving to your AI agent. One command gives Claude Code or Cursor the ability to solve any CAPTCHA.

Claude Code — Quick Setup (Recommended)

One command configures everything — MCP server, API key, and CLAUDE.md instructions:

bash
npx uncaptcha-mcp setup

This registers the MCP server in Claude Code, prompts for your API key, and adds CAPTCHA-solving instructions to your project's CLAUDE.md so Claude automatically knows how to solve CAPTCHAs.

Manual Setup

Or add the MCP server manually:

bash
claude mcp add uncaptcha -e UNCAPTCHA_API_KEY=ac-your-key -- npx uncaptcha-mcp

Cursor

Add the following to your .cursor/mcp.json file:

json
{
  "mcpServers": {
    "uncaptcha": {
      "command": "npx",
      "args": ["uncaptcha-mcp"],
      "env": {
        "UNCAPTCHA_API_KEY": "ac-your-api-key-here"
      }
    }
  }
}

Available MCP Tools

captcha_detectcaptcha_detect(url)

Auto-detect CAPTCHA type and site key from a page URL. Use this before captcha_solve when you only have the URL. No API key required.

captcha_solvecaptcha_solve(siteKey, pageUrl, type?, action?)

Solve any CAPTCHA and return the token. Default type is recaptcha_v2.

captcha_balancecaptcha_balance()

Check your plan, usage stats, and remaining solves for the current period.

captcha_typescaptcha_types()

List all CAPTCHA types currently supported by the API.

captcha_reportcaptcha_report(taskId, correct)

Report a solve as correct or incorrect for quality feedback.

Chrome Extension

The uncaptcha.dev Chrome Extension automatically detects and solves CAPTCHAs as you browse. Supports reCAPTCHA v2, reCAPTCHA v3, Cloudflare Turnstile, and hCaptcha.

Installation

1Navigate to chrome://extensions/ in Chrome
2Enable Developer mode (toggle in the top-right corner)
3Click Load unpacked and select the extension directory
4Click the extension icon and enter your API key
5Enable Auto-Solve for hands-free operation (optional)

How It Works

1

Detect

Content script scans the DOM for CAPTCHA widgets using selectors and MutationObserver. Re-scans at 1.5s and 4s for late-loading widgets.

2

Solve

Sends the site key and page URL to POST /v1/solve/sync via the service worker. Returns a solved token in seconds.

3

Inject

Injects the token into the page by setting response textareas, firing callbacks, and overriding getResponse() methods.

Proxy Support

Pass a proxy field in your solve request to route the CAPTCHA solving through your own proxy. This is useful for geo-targeting or matching the IP that your application uses.

Supported Formats

json
// HTTP proxy with authentication
{
  "type": "recaptcha_v2",
  "siteKey": "6Le-abc...",
  "pageUrl": "https://example.com",
  "proxy": "http://username:password@proxy-host:8080"
}

// SOCKS5 proxy
{
  "type": "turnstile",
  "siteKey": "0x4AAA...",
  "pageUrl": "https://example.com",
  "proxy": "socks5://user:pass@host:1080"
}

// IP:Port only (no auth)
{
  "type": "recaptcha_v3",
  "siteKey": "6Ldy...",
  "pageUrl": "https://example.com",
  "proxy": "http://203.0.113.1:3128"
}
i
The proxy is only used for the CAPTCHA solving step. Your original request to uncaptcha.dev always goes through a direct connection.
from uncaptcha import Uncaptcha

solver = Uncaptcha("ac-your-api-key")
result = solver.recaptcha(
    site_key="6Le-abc...",
    page_url="https://example.com",
    proxy="http://user:pass@proxy:8080",
)
print(result["token"])

Error Codes

All API responses use standard HTTP status codes. Error responses include a JSON body with an error field describing the issue.

CodeStatusDescription
200OKRequest succeeded. The response body contains the requested data.
400Bad RequestMissing or invalid parameters. Check the error message for specifics.
401UnauthorizedInvalid or missing API key (X-API-Key) or JWT (Authorization: Bearer).
402Payment RequiredMonthly quota exceeded. Upgrade your plan or wait for the next billing cycle.
404Not FoundThe requested task ID does not exist or has expired.
429Too Many RequestsRate limited (300 req/min per IP). Back off and retry after the Retry-After header value.
500Internal ErrorServer error. Contact support if the issue persists.

Error Response Format

json
{
  "error": "bad_request",
  "message": "siteKey and pageUrl are required"
}
>
On 429 responses, check the Retry-After header for the number of seconds to wait before retrying. The rate limit is 300 requests per minute per IP.

Examples

Complete, copy-paste-ready code examples for common use cases.

Python

reCAPTCHA v2 (using SDK)

python
from uncaptcha import Uncaptcha

solver = Uncaptcha("ac-your-api-key")

# Solve reCAPTCHA v2
result = solver.recaptcha(
    site_key="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
    page_url="https://www.google.com/recaptcha/api2/demo",
)
print(f"Token: {result['token'][:50]}...")

# Use the token in a form submission
import requests

response = requests.post("https://example.com/submit", data={
    "g-recaptcha-response": result["token"],
    "username": "user",
    "password": "pass",
})
print(f"Status: {response.status_code}")

Turnstile (using requests directly)

python
import requests

response = requests.post(
    "https://api.uncaptcha.dev/v1/solve/sync",
    headers={
        "X-API-Key": "ac-your-api-key",
        "Content-Type": "application/json",
    },
    json={
        "type": "turnstile",
        "siteKey": "0x4AAAAAAABS7vwvV6VFfMcD",
        "pageUrl": "https://example.com",
    },
    timeout=130,
)

data = response.json()
if data.get("status") == "solved":
    print(f"Solved in {data['elapsed']}ms")
    print(f"Token: {data['token'][:50]}...")
else:
    print(f"Failed: {data}")

Image CAPTCHA (OCR)

python
from pathlib import Path
from uncaptcha import Uncaptcha

solver = Uncaptcha("ac-your-api-key")

# From file path
result = solver.image(Path("captcha.png"))
print(f"Text: {result['token']}")

# From base64 string
import base64

with open("captcha.png", "rb") as f:
    b64 = base64.b64encode(f.read()).decode()

result = solver.image(b64)
print(f"Text: {result['token']}")

Node.js

reCAPTCHA v2 (using SDK)

javascript
import { Uncaptcha } from 'uncaptcha';

const solver = new Uncaptcha('ac-your-api-key');

// Solve reCAPTCHA v2
const { token } = await solver.recaptcha({
  siteKey: '6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
  pageUrl: 'https://www.google.com/recaptcha/api2/demo',
});

console.log('Token:', token.substring(0, 50) + '...');

// Use the token in a form submission
const response = await fetch('https://example.com/submit', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    'g-recaptcha-response': token,
    username: 'user',
    password: 'pass',
  }),
});
console.log('Status:', response.status);

Turnstile (using fetch directly)

javascript
const response = await fetch('https://api.uncaptcha.dev/v1/solve/sync', {
  method: 'POST',
  headers: {
    'X-API-Key': 'ac-your-api-key',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    type: 'turnstile',
    siteKey: '0x4AAAAAAABS7vwvV6VFfMcD',
    pageUrl: 'https://example.com',
  }),
  signal: AbortSignal.timeout(130_000),
});

const data = await response.json();

if (data.status === 'solved') {
  console.log(`Solved in ${data.elapsed}ms`);
  console.log('Token:', data.token.substring(0, 50) + '...');
} else {
  console.error('Failed:', data);
}

Error Handling

javascript
import { Uncaptcha, AuthenticationError, QuotaExceededError, NetworkError } from 'uncaptcha';

const solver = new Uncaptcha('ac-your-api-key');

try {
  const { token } = await solver.recaptcha({
    siteKey: '6Le-abc...',
    pageUrl: 'https://example.com',
  });
  console.log('Solved:', token);
} catch (err) {
  if (err instanceof AuthenticationError) {
    console.error('Invalid API key. Check your dashboard.');
  } else if (err instanceof QuotaExceededError) {
    console.error('Monthly quota exceeded. Upgrade your plan.');
  } else if (err instanceof NetworkError) {
    console.error('Network issue. Retrying...');
  } else {
    console.error('Unexpected error:', err.message);
  }
}

cURL

Synchronous Solve

bash
curl -X POST https://api.uncaptcha.dev/v1/solve/sync \
  -H "X-API-Key: ac-your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "recaptcha_v2",
    "siteKey": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
    "pageUrl": "https://www.google.com/recaptcha/api2/demo"
  }'

Async Solve + Poll

bash
# Step 1: Submit the solve request
RESPONSE=$(curl -s -X POST https://api.uncaptcha.dev/v1/solve \
  -H "X-API-Key: ac-your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "turnstile",
    "siteKey": "0x4AAAAAAABS7vwvV6VFfMcD",
    "pageUrl": "https://example.com"
  }')

echo "$RESPONSE"

# Step 2: Extract the taskId and retrieve the result
TASK_ID=$(echo "$RESPONSE" | jq -r '.taskId')

curl -s https://api.uncaptcha.dev/v1/result/$TASK_ID \
  -H "X-API-Key: ac-your-api-key" | jq .

Check Balance

bash
curl -s https://api.uncaptcha.dev/v1/balance \
  -H "X-API-Key: ac-your-api-key" | jq .

Report Solve Quality

bash
curl -X POST https://api.uncaptcha.dev/v1/report \
  -H "X-API-Key: ac-your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "taskId": "550e8400-e29b-41d4-a716-446655440000",
    "correct": true
  }'

View Solve History

bash
# Latest 20 solves
curl -s "https://api.uncaptcha.dev/v1/history?limit=20" \
  -H "X-API-Key: ac-your-api-key" | jq .

# Filter by type
curl -s "https://api.uncaptcha.dev/v1/history?type=turnstile&limit=10" \
  -H "X-API-Key: ac-your-api-key" | jq .