> Full docs index: https://docs.steel.dev/llms.txt

# What Is a CAPTCHA Solver? Automatic CAPTCHA Solving API
URL: https://docs.steel.dev/overview/stealth/captcha-solving

### What Is a CAPTCHA Solver?

A CAPTCHA solver is a service that notices a CAPTCHA challenge on a page, produces a valid answer for it, and submits that answer back to the page so an automated session can continue. In Steel the solver runs inside the browser session, so you turn it on with a single session flag instead of wiring up a separate solving provider.

```typescript
import Steel from 'steel-sdk';

const client = new Steel();

// One flag covers detection, solving, and verification for the whole session
const session = await client.sessions.create({
  solveCaptcha: true
});
```

```python
from steel import Steel

client = Steel()

# One flag covers detection, solving, and verification for the whole session
session = client.sessions.create(
    solve_captcha=True
)
```

Any solver, Steel's included, has to do three separate jobs, and a failure in any one of them looks the same from your automation's point of view:

*   **Detect** the challenge, including invisible ones that never render a visible widget

*   **Solve** it, using models, third-party solving services, or by reproducing the interaction a person would perform

*   **Submit and verify** the resulting token or input so the target page actually accepts it

### How Automated CAPTCHA Solving Works

When CAPTCHA solving is enabled on a session, every page runs through the same pipeline and each stage is reported as a task status you can read from the API:

1.  **Detection**: The system continuously monitors the page for CAPTCHA elements using multiple detection methods:

    *   DOM structure analysis

    *   Known CAPTCHA iframe patterns

    *   Common CAPTCHA API endpoints

    *   Visual element detection

2.  **State Management**: CAPTCHA states are tracked per page with real-time updates

3.  **Classification**: Once detected, the system identifies the specific type of CAPTCHA and routes it to the appropriate solver.

4.  **Solving**: CAPTCHAs are then solved by us using various methods:

    *   Machine learning models

    *   Third-party solving services

    *   Browser automation techniques

    *   Token manipulation (when applicable)

5.  **Verification**: The system verifies that the CAPTCHA was successfully solved before allowing the session to continue.

```typescript
const pages = await client.sessions.captchas.status(session.id);

for (const state of pages) {
  for (const task of state.tasks as Array<{ type: string; status: string }>) {
    // detected -> solving -> validating -> solved
    console.log(task.type, task.status);
  }
}
```

```python
pages = client.sessions.captchas.status(session.id)

for state in pages:
    for task in state.tasks:
        # detected -> solving -> validating -> solved
        print(task["type"], task["status"])
```

### CAPTCHA Types Steel Detects and Solves

Each detected challenge is classified, and its type string is what you see on the task in the [CAPTCHA status response](/overview/captchas-api/overview#getting-captcha-status). The types below cover what you will run into most often, and other widely used challenge types are auto-solved as well:

| Type string     | What the challenge looks like                            | Auto-solved |
| --------------- | -------------------------------------------------------- | ----------- |
| `recaptchaV2`   | "I'm not a robot" checkbox plus image challenges         | Yes         |
| `recaptchaV3`   | Invisible background scoring, no widget to click         | Yes         |
| `turnstile`     | Cloudflare's minimal-interaction widget                  | Yes         |
| `image_to_text` | Distorted characters in an image, solved with OCR        | Yes         |
| `slider`        | Drag a handle into the correct position                  | Yes         |
| `unknown`       | Challenge detected but not classified                    | No          |

### Detected but not auto-solved
DataDome, Imperva, Amazon WAF, and FunCAPTCHA challenges are detected and logged for diagnostics, but they are not auto-solved. Custom in-house and enterprise-specific CAPTCHA implementations are not supported either, so treat those sites as prevention problems rather than solving problems.

Read the types off the status response when you want to branch on what the page threw at you:

```typescript
const pages = await client.sessions.captchas.status(session.id);
const tasks = pages.flatMap((state) => state.tasks as Array<{ type: string }>);

// e.g. ['turnstile', 'image_to_text']
console.log(tasks.map((task) => task.type));
```

```python
pages = client.sessions.captchas.status(session.id)
types = [task["type"] for state in pages for task in state.tasks]

# e.g. ['turnstile', 'image_to_text']
print(types)
```

### How Steel Handles CAPTCHAs

Steel takes a two-pronged approach to dealing with CAPTCHAs:

1.  **Prevention First**: Our sophisticated browser fingerprinting and anti-detection systems often prevent CAPTCHAs from appearing in the first place. We maintain realistic browser profiles that make your automated sessions appear more human-like, reducing the likelihood of triggering CAPTCHA challenges.

2.  **Automatic Solving**: When CAPTCHAs do appear, our automatic solving system kicks in to handle them transparently, allowing your automation to continue without interruption.

Fingerprinting is applied to every session, so the practical decision is whether to pair it with residential IPs and solving on the sites that challenge you most:

```typescript
const session = await client.sessions.create({
  useProxy: true,      // residential IP, fewer challenges triggered
  solveCaptcha: true   // fallback for the ones that still appear
});
```

```python
session = client.sessions.create(
    use_proxy=True,      # residential IP, fewer challenges triggered
    solve_captcha=True,  # fallback for the ones that still appear
)
```

### Automatic vs Manual Solving

Automatic solving fires as soon as a challenge is detected and needs no further calls from you. Manual solving keeps detection on but waits for you to trigger the solve, which is useful when you want to decide whether a given challenge is worth solving at all.

| | Automatic solving | Manual solving |
| --- | --- | --- |
| Configuration | `solveCaptcha: true` | `solveCaptcha: true` plus `autoCaptchaSolving: false` |
| Trigger | Detection of the challenge | Your call to the solve endpoint |
| Extra API calls | None | One solve call per challenge or page |
| Best for | Unattended scraping and agent runs | Flows where you gate solving on the page, the URL, or your own logic |

#### Session Configuration

To enable autosolving, simply set `solveCaptcha: true` when creating a session.

```typescript
import Steel from 'steel-sdk';

const client = new Steel();

const session = await client.sessions.create({
  solveCaptcha: true
});
```

```python
from steel import Steel

client = Steel()
session = client.sessions.create(
    solve_captcha=True
)
```

To detect CAPTCHAs without automatically solving them, disable `autoCaptchaSolving` in the stealth config:

```typescript
const session = await client.sessions.create({
  solveCaptcha: true,
  stealthConfig: {
    autoCaptchaSolving: false
  }
});
```

```python
session = client.sessions.create(
    solve_captcha=True,
    stealth_config={
        "autoCaptchaSolving": False
    }
)
```

#### Manual Solving

If auto-solving is disabled, use the solve endpoint to trigger solving. You can solve all detected CAPTCHAs, or target a specific one with a value read from the [CAPTCHA status response](/overview/captchas-api/overview#getting-captcha-status):

*   `taskId`: the value of the task's `id` field

*   `url`: the URL the challenge was detected on

*   `pageId`: the page the challenge belongs to

```typescript
// Solve all detected CAPTCHAs
await client.sessions.captchas.solve('sessionId');

// Solve specific task
await client.sessions.captchas.solve('sessionId', { taskId: 'task_123' });

// Solve by URL
await client.sessions.captchas.solve('sessionId', { url: 'https://example.com' });

// Solve by Page ID
await client.sessions.captchas.solve('sessionId', { pageId: 'page_123' });
```

```python
# Solve all detected CAPTCHAs
client.sessions.captchas.solve("sessionId")

# Solve specific task
client.sessions.captchas.solve("sessionId", task_id="task_123")

# Solve by URL
client.sessions.captchas.solve("sessionId", url="https://example.com")

# Solve by Page ID
client.sessions.captchas.solve("sessionId", page_id="page_123")
```

### Response Times

Solving adds wall-clock time to a run, and how much depends on the challenge type and the target site, so Steel does not quote a fixed figure. Every task carries its own timings instead, which means you can measure the real numbers for the sites you actually automate:

```typescript
type CaptchaTiming = { type: string; status: string; totalDuration?: number };

const pages = await client.sessions.captchas.status(session.id);

for (const state of pages) {
  for (const task of state.tasks as CaptchaTiming[]) {
    // Milliseconds from detection to solved or failed
    console.log(task.type, task.status, task.totalDuration);
  }
}
```

```python
pages = client.sessions.captchas.status(session.id)

for state in pages:
    for task in state.tasks:
        # Milliseconds from detection to solved or failed
        print(task["type"], task["status"], task.get("totalDuration"))
```

Three fields on each task give you the full picture:

*   `detectionTime`: when the challenge was spotted on the page

*   `solveTime`: when solving finished

*   `totalDuration`: milliseconds from detection to the terminal status

### Budget for solving in your timeouts
Log `totalDuration` across a representative run, then set your session timeout and your own waits above the values you observe rather than around a guessed number.

### Best Practices for Implementation

#### 1\. Implement Proper Waiting

When navigating to pages that might contain CAPTCHAs, it's important to implement proper waiting strategies:

```typescript
// Typescript example using Puppeteer
await page.waitForNetworkIdle();  // Wait for network activity to settle
await page.waitForTimeout(2000);  // Additional safety buffer
```

```python
# Python example using Playwright
await page.wait_for_load_state('networkidle')  # Wait for network activity to settle
await page.wait_for_timeout(2000)  # Additional safety buffer
```

#### 2. Detecting CAPTCHA Presence

You can detect CAPTCHA presence using these selectors:

```typescript
// Common CAPTCHA selectors
const captchaSelectors = [
    'iframe[src*="recaptcha"]',
    '#captcha-box',
    '[class*="captcha"]'
];
```

### Important Considerations

1.  **Plan Availability**: CAPTCHA solving is available on Launch after account verification, and on Scale and Enterprise. See [Pricing/Limits](/overview/pricinglimits) for rates and access requirements.

2.  **Success Rates**: While our system has high success rates, CAPTCHA solving is not guaranteed to work 100% of the time. Always implement proper error handling.

3.  **Timing**: CAPTCHA solving can add latency to your automation. Account for this in your timeouts and waiting strategies.

4.  **Rate Limits**: Even with successful CAPTCHA solving, respect the target site's rate limits and terms of service.

### Common Issues and Solutions

1.  **Timeout Issues**

    *   Increase your session timeout when working with CAPTCHA-heavy sites

    *   Implement exponential backoff for retries

2.  **Detection Issues**

    *   Use Steel's built-in stealth profiles

    *   Implement natural delays between actions

    *   Rotate IP addresses using Steel's proxy features

3.  **Solving Failures**

    *   Implement proper error handling

    *   Have fallback strategies ready

    *   Consider implementing manual solving as a last resort

### Best Practices for Avoiding CAPTCHAs

1.  **Use Steel's Fingerprinting**: Our automatic fingerprinting often helps bypass avoidable CAPTCHAs entirely by making your sessions appear more human-like.

2.  **Session Management**:

    *   Reuse successful sessions when possible

    *   Maintain cookies and session data

    *   Use Steel's session persistence features

3.  **Request Patterns**:

    *   Implement natural delays between actions

    *   Vary your request patterns

    *   Avoid rapid, repetitive actions

### Looking Forward

Steel is continuously improving its CAPTCHA handling capabilities. We regularly update our solving mechanisms to handle new CAPTCHA variants and improve success rates for existing ones, so check back here for the latest information about supported CAPTCHA types and best practices.

### Need help building with CAPTCHA solving?
Reach out to us on the **#help** channel on [Discord](https://discord.gg/steel-dev) under the ⭐ community section.

### FAQ

### What is a CAPTCHA solver?

A CAPTCHA solver detects a challenge on a page, produces a valid answer for it, and submits that answer back so an automated session can continue. Steel's solver runs inside the browser session, so setting `solveCaptcha: true` covers detection, solving, and verification without a separate solving provider.

### What is a CAPTCHA solving API?

It is an API that exposes solving as part of your automation instead of as a manual step: you enable it on a session, then read CAPTCHA state and trigger solves over HTTP or the SDKs. In Steel that means the `solveCaptcha` session flag plus the status and solve endpoints of the [CAPTCHAs API](/overview/captchas-api/overview).

### How does Steel handle CAPTCHAs?

With a two-pronged approach: browser fingerprinting and anti-detection systems prevent many CAPTCHAs from appearing in the first place, and when one does appear, automatic solving handles it transparently. Enable it by setting `solveCaptcha: true` when creating a session.

### What CAPTCHA types does Steel support?

Steel's auto-solver currently handles reCAPTCHA v2 and v3, Cloudflare Turnstile, image-to-text, slider, and other widely used challenge types. Systems like DataDome, Imperva, Amazon WAF, and FunCAPTCHA are detected and logged but not auto-solved, and custom or enterprise-specific implementations aren't supported.

### Should I use automatic or manual solving?

Automatic solving is the default and the right choice for unattended runs, since it fires on detection with no extra calls. Set `autoCaptchaSolving: false` when you want detection only and prefer to decide per challenge, then trigger the solve endpoint yourself.

### How long does CAPTCHA solving take?

It depends on the challenge type and the target site, so Steel does not publish a fixed number. Each task in the status response carries `detectionTime`, `solveTime`, and `totalDuration`, so measure solving latency on your own target sites and size your timeouts from those values.

### Does Steel's CAPTCHA solver work 100% of the time?

No, the system has high success rates but solving is not guaranteed to work 100% of the time, so you should implement proper error handling. Solving can also add latency, so account for it in your timeouts and waiting strategies.

### How can I avoid triggering CAPTCHAs in the first place?

Use Steel's automatic fingerprinting (which often bypasses avoidable CAPTCHAs by making sessions appear more human-like), reuse successful sessions while maintaining cookies, and add natural delays while avoiding rapid, repetitive actions.
