Captcha solving service blog | SolveCaptcha How to bypass reCAPTCHA v3

How to bypass reCAPTCHA v3

reCAPTCHA v3 is a score-based verification system that runs in the background without requiring the user to select images or click an “I’m not a robot” checkbox.

Instead of displaying a visible challenge, reCAPTCHA v3 generates a token associated with:

  • the website’s public site key;
  • the current page URL;
  • the action performed by the user;
  • a score representing the assessed legitimacy of the interaction.

For authorized browser automation, application testing, and data collection, the token can be obtained through the SolveCaptcha reCAPTCHA solver.

This guide explains how to:

  • identify reCAPTCHA v3 on a page;
  • find the site key and action;
  • configure min_score;
  • submit the task to SolveCaptcha;
  • retrieve the response token;
  • apply the token to the target request;
  • report accepted and rejected solutions;
  • integrate the process with Python and PHP.

Use this method only on websites you own or are authorized to test and automate.

What is reCAPTCHA v3?

reCAPTCHA v3 evaluates browser activity without interrupting the user with a visible puzzle.

The website loads the reCAPTCHA JavaScript API and executes an action:

grecaptcha.execute(
  "SITE_KEY",
  {
    action: "login"
  }
);

Google returns a token to the website. The website sends that token to its backend, which verifies it and receives information that includes:

  • whether the token is valid;
  • the calculated score;
  • the action associated with the token;
  • other verification metadata.

The score normally ranges from:

0.1 to 0.9

A higher score indicates that the interaction appears more legitimate. The website decides which score is sufficient for a specific action.

For example, a website may accept:

0.3

for viewing public content but require a higher score for:

login
registration
checkout
password reset

reCAPTCHA v2 and v3 differences

Feature reCAPTCHA v2 reCAPTCHA v3
Visible checkbox Common No
Image challenge Possible No
Runs in background Sometimes Yes
Returns a score No Yes
Uses an action Usually no Common
Requires version=v3 No Yes

Invisible reCAPTCHA v2 should not be confused with reCAPTCHA v3.

Invisible v2 may still display an image challenge when Google considers the interaction suspicious. reCAPTCHA v3 does not display an image-selection challenge and instead returns a score.

How to identify reCAPTCHA v3

The most reliable method is to inspect the page source and JavaScript.

Look for api.js with a render parameter

A reCAPTCHA v3 page commonly loads:

<script
  src="https://www.google.com/recaptcha/api.js?render=SITE_KEY"
></script>

Example:

<script
  src="https://www.google.com/recaptcha/api.js?render=6LfB5_IbAAAAAMCtsjEHEHKqcB9iQocwwxTiihJu"
></script>

The value of render is the site key:

6LfB5_IbAAAAAMCtsjEHEHKqcB9iQocwwxTiihJu

The script may also be loaded from:

https://www.recaptcha.net/recaptcha/api.js

Look for grecaptcha.execute

Search the page source and loaded JavaScript files for:

grecaptcha.execute

Example:

grecaptcha.execute(
  "6LfB5_IbAAAAAMCtsjEHEHKqcB9iQocwwxTiihJu",
  {
    action: "login"
  }
);

This call contains two important values:

Site key: 6LfB5_IbAAAAAMCtsjEHEHKqcB9iQocwwxTiihJu
Action: login

Check the reCAPTCHA configuration

Another possible indicator is:

___grecaptcha_cfg.clients[100000]

The configuration structure is not a stable public API, so it should be treated as a supporting indicator rather than the primary extraction method.

Use the browser console

The following command searches reCAPTCHA script URLs:

[
  ...document.querySelectorAll(
    'script[src*="recaptcha/api.js"]'
  )
].map((script) => {
  try {
    const url = new URL(script.src);

    return {
      src: script.src,
      sitekey:
        url.searchParams.get("render")
    };
  } catch {
    return null;
  }
});

A valid reCAPTCHA v3 site key appears in:

render=SITE_KEY

Do not treat:

render=explicit

as a site key.

Required SolveCaptcha parameters

SolveCaptcha uses the following endpoints:

Create a task:

POST https://api.solvecaptcha.com/in.php

Get the result:

GET https://api.solvecaptcha.com/res.php

The required parameters are:

Parameter Required Description
key Yes SolveCaptcha API key
method Yes Must be userrecaptcha
version Yes Must be v3
googlekey Yes Public reCAPTCHA site key
pageurl Yes Full URL where reCAPTCHA is executed
action No Action used in grecaptcha.execute()
min_score No Requested score; default is 0.4
domain No google.com or recaptcha.net
json No Set to 1 for JSON responses

The parameter names are important.

Use:

googlekey
pageurl
action
min_score

Do not use API names from unrelated integrations such as:

websiteKey
websiteURL
pageAction
minScore

How to find the site key

The site key can be found in several locations.

api.js render parameter

<script
  src="https://www.google.com/recaptcha/api.js?render=SITE_KEY"
></script>

grecaptcha.execute call

grecaptcha.execute(
  "SITE_KEY",
  {
    action: "login"
  }
);

iframe k parameter

In some implementations, the key may appear in a reCAPTCHA iframe URL:

https://www.google.com/recaptcha/api2/anchor?k=SITE_KEY

JavaScript configuration

The website may store the key in an application configuration object:

window.applicationConfig = {
  recaptchaSiteKey:
    "6LfB5_IbAAAAAMCtsjEHEHKqcB9iQocwwxTiihJu"
};

Search loaded JavaScript files for:

recaptchaSiteKey
sitekey
grecaptcha.execute
api.js?render=

How to find the action

The action is usually passed to:

grecaptcha.execute()

Example:

grecaptcha.execute(
  "SITE_KEY",
  {
    action: "checkout"
  }
);

The correct SolveCaptcha parameter is:

action=checkout

The value must match the action expected by the website.

Possible actions include:

login
register
signup
checkout
submit
contact
password_reset
verify

Do not choose an action based only on the form type. Inspect the website’s actual JavaScript or network requests.

If the page does not provide an action, SolveCaptcha uses:

verify

as the default value.

How to configure min_score

The min_score parameter specifies the score requested from SolveCaptcha.

Example:

min_score=0.3

The SolveCaptcha documentation defines a default value of:

0.4

However, the documentation also warns that obtaining tokens with scores above 0.3 can be difficult.

For this reason, do not automatically request:

0.9

unless the target website genuinely requires it and the integration has been tested with that threshold.

A practical starting configuration is:

min_score=0.3

The requested score does not guarantee that the website will accept the token. The target website can also check:

  • whether the action matches;
  • whether the token belongs to the correct site key;
  • whether the token was generated for the correct page;
  • whether the token is fresh;
  • application-specific risk signals;
  • session and request consistency.

Do not repeatedly create tasks with arbitrary score values. First determine the score threshold and action used by the target application.

Step 1: Create the task

Example request:

curl --request POST \
  --url https://api.solvecaptcha.com/in.php \
  --data-urlencode "key=YOUR_API_KEY" \
  --data-urlencode "method=userrecaptcha" \
  --data-urlencode "version=v3" \
  --data-urlencode "googlekey=6LfB5_IbAAAAAMCtsjEHEHKqcB9iQocwwxTiihJu" \
  --data-urlencode "pageurl=https://example.com/login" \
  --data-urlencode "action=login" \
  --data-urlencode "min_score=0.3" \
  --data-urlencode "json=1"

A successful response contains the task ID:

{
  "status": 1,
  "request": "2122988149"
}

Save the request value.

It is required to retrieve the token.

Step 2: Wait before requesting the result

Wait approximately:

15–20 seconds

before sending the first result request.

Do not begin polling immediately after task creation.

Step 3: Retrieve the result

Send:

GET https://api.solvecaptcha.com/res.php

with:

key=YOUR_API_KEY
action=get
id=2122988149
json=1

Example:

curl "https://api.solvecaptcha.com/res.php?key=YOUR_API_KEY&action=get&id=2122988149&json=1"

If the task is still being processed:

{
  "status": 0,
  "request": "CAPCHA_NOT_READY"
}

Wait five seconds and repeat the request using the same task ID.

Do not create a duplicate task while the original one is still active.

A successful response contains the token:

{
  "status": 1,
  "request": "03AFcWeA5dCJ-2OQqwd0-2IHmBX3ItBl76..."
}

The value of request is the reCAPTCHA v3 token.

Step 4: Apply the token

There is no universal method for applying a reCAPTCHA v3 token.

The website may send it through:

g-recaptcha-response
g-recaptcha-response-100000
recaptchaToken
captchaToken

or another custom request parameter.

The most reliable method is:

  1. Open Chrome DevTools.
  2. Select the Network tab.
  3. Perform the protected action manually.
  4. Find the POST or XHR request sent by the page.
  5. Inspect its request body.
  6. Identify the field containing the reCAPTCHA token.
  7. Reproduce the same request structure.

A common HTML field is:

<textarea
  name="g-recaptcha-response"
></textarea>

Example JavaScript:

const field = document.querySelector(
  '[name="g-recaptcha-response"]'
);

if (field) {
  field.value =
    "TOKEN_FROM_SOLVECAPTCHA";

  field.dispatchEvent(
    new Event("input", {
      bubbles: true
    })
  );

  field.dispatchEvent(
    new Event("change", {
      bubbles: true
    })
  );
}

Some reCAPTCHA v3 integrations generate the token immediately before sending an XHR request. In that case, supplying the token directly in the request body may be more reliable than changing the page DOM.

Complete Python example

Install Requests:

python -m pip install requests

Set your API key:

export SOLVECAPTCHA_API_KEY="YOUR_API_KEY"

Create recaptcha_v3.py:

#!/usr/bin/env python3

from __future__ import annotations

import os
import time
from dataclasses import dataclass
from typing import Any

import requests

CREATE_TASK_URL = (
    "https://api.solvecaptcha.com/in.php"
)

GET_RESULT_URL = (
    "https://api.solvecaptcha.com/res.php"
)

INITIAL_WAIT_SECONDS = 20
POLL_INTERVAL_SECONDS = 5
MAX_WAIT_SECONDS = 180

class SolveCaptchaError(RuntimeError):
    """Raised when SolveCaptcha returns an error."""

@dataclass(frozen=True)
class RecaptchaV3Solution:
    task_id: str
    token: str

def parse_response(
    response: requests.Response,
) -> dict[str, Any]:
    response.raise_for_status()

    try:
        result = response.json()
    except requests.JSONDecodeError as exc:
        raise SolveCaptchaError(
            "SolveCaptcha returned invalid JSON: "
            f"{response.text[:500]}"
        ) from exc

    if not isinstance(result, dict):
        raise SolveCaptchaError(
            f"Unexpected response: {result!r}"
        )

    return result

class RecaptchaV3Client:
    def __init__(
        self,
        api_key: str,
        request_timeout: float = 30,
    ) -> None:
        if not api_key:
            raise ValueError(
                "SolveCaptcha API key is required"
            )

        self.api_key = api_key
        self.request_timeout = request_timeout
        self.session = requests.Session()

    def create_task(
        self,
        *,
        sitekey: str,
        pageurl: str,
        action: str = "verify",
        min_score: float = 0.3,
        domain: str = "google.com",
    ) -> str:
        if not sitekey:
            raise ValueError(
                "reCAPTCHA site key is required"
            )

        if not pageurl:
            raise ValueError(
                "Page URL is required"
            )

        if domain not in {
            "google.com",
            "recaptcha.net",
        }:
            raise ValueError(
                "domain must be google.com "
                "or recaptcha.net"
            )

        payload = {
            "key": self.api_key,
            "method": "userrecaptcha",
            "version": "v3",
            "googlekey": sitekey,
            "pageurl": pageurl,
            "action": action,
            "min_score": min_score,
            "domain": domain,
            "json": 1,
        }

        response = self.session.post(
            CREATE_TASK_URL,
            data=payload,
            timeout=self.request_timeout,
        )
        result = parse_response(response)

        if result.get("status") != 1:
            raise SolveCaptchaError(
                "Unable to create task: "
                f"{result.get('request')}"
            )

        task_id = str(
            result.get("request", "")
        ).strip()

        if not task_id:
            raise SolveCaptchaError(
                "SolveCaptcha did not return "
                "a task ID"
            )

        return task_id

    def get_result(
        self,
        task_id: str,
    ) -> str | None:
        response = self.session.get(
            GET_RESULT_URL,
            params={
                "key": self.api_key,
                "action": "get",
                "id": task_id,
                "json": 1,
            },
            timeout=self.request_timeout,
        )
        result = parse_response(response)

        if result.get("status") == 1:
            token = str(
                result.get("request", "")
            ).strip()

            if not token:
                raise SolveCaptchaError(
                    "SolveCaptcha returned "
                    "an empty token"
                )

            return token

        error_code = str(
            result.get(
                "request",
                "UNKNOWN_ERROR",
            )
        )

        if error_code == "CAPCHA_NOT_READY":
            return None

        raise SolveCaptchaError(
            f"Task {task_id} failed: "
            f"{error_code}"
        )

    def solve(
        self,
        *,
        sitekey: str,
        pageurl: str,
        action: str = "verify",
        min_score: float = 0.3,
        domain: str = "google.com",
    ) -> RecaptchaV3Solution:
        task_id = self.create_task(
            sitekey=sitekey,
            pageurl=pageurl,
            action=action,
            min_score=min_score,
            domain=domain,
        )

        time.sleep(
            INITIAL_WAIT_SECONDS
        )

        deadline = (
            time.monotonic()
            + MAX_WAIT_SECONDS
        )

        while time.monotonic() < deadline:
            token = self.get_result(
                task_id
            )

            if token is not None:
                return RecaptchaV3Solution(
                    task_id=task_id,
                    token=token,
                )

            time.sleep(
                POLL_INTERVAL_SECONDS
            )

        raise TimeoutError(
            f"Task {task_id} was not completed "
            f"within {MAX_WAIT_SECONDS} seconds"
        )

    def report(
        self,
        task_id: str,
        accepted: bool,
    ) -> None:
        action = (
            "reportgood"
            if accepted
            else "reportbad"
        )

        response = self.session.get(
            GET_RESULT_URL,
            params={
                "key": self.api_key,
                "action": action,
                "id": task_id,
                "json": 1,
            },
            timeout=self.request_timeout,
        )

        parse_response(response)

def main() -> None:
    api_key = os.environ.get(
        "SOLVECAPTCHA_API_KEY",
        "",
    ).strip()

    if not api_key:
        raise SystemExit(
            "Set SOLVECAPTCHA_API_KEY"
        )

    client = RecaptchaV3Client(
        api_key=api_key
    )

    solution = client.solve(
        sitekey=(
            "6LfB5_IbAAAAAMCtsjEHEHK"
            "qcB9iQocwwxTiihJu"
        ),
        pageurl=(
            "https://example.com/login"
        ),
        action="login",
        min_score=0.3,
    )

    print(
        "Task ID:",
        solution.task_id,
    )

    print(
        "Token:",
        solution.token,
    )

    # Apply the token to the target website.
    accepted = True

    client.report(
        task_id=solution.task_id,
        accepted=accepted,
    )

if __name__ == "__main__":
    main()

Run the script:

python recaptcha_v3.py

PHP example

<?php

declare(strict_types=1);

const CREATE_TASK_URL =
    'https://api.solvecaptcha.com/in.php';

const GET_RESULT_URL =
    'https://api.solvecaptcha.com/res.php';

$apiKey = getenv('SOLVECAPTCHA_API_KEY');

if (!$apiKey) {
    throw new RuntimeException(
        'Set SOLVECAPTCHA_API_KEY'
    );
}

function requestJson(
    string $url,
    array $parameters,
    bool $post = false
): array {
    $curl = curl_init();

    if ($curl === false) {
        throw new RuntimeException(
            'Unable to initialize cURL'
        );
    }

    if ($post) {
        curl_setopt_array($curl, [
            CURLOPT_URL => $url,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS =>
                http_build_query($parameters),
        ]);
    } else {
        curl_setopt(
            $curl,
            CURLOPT_URL,
            $url . '?' .
            http_build_query($parameters)
        );
    }

    curl_setopt_array($curl, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30,
    ]);

    $response = curl_exec($curl);

    if ($response === false) {
        $error = curl_error($curl);
        curl_close($curl);

        throw new RuntimeException(
            'HTTP request failed: ' . $error
        );
    }

    $statusCode = curl_getinfo(
        $curl,
        CURLINFO_RESPONSE_CODE
    );

    curl_close($curl);

    if ($statusCode < 200 ||
        $statusCode >= 300) {
        throw new RuntimeException(
            'Unexpected HTTP status: ' .
            $statusCode
        );
    }

    $result = json_decode(
        $response,
        true,
        512,
        JSON_THROW_ON_ERROR
    );

    if (!is_array($result)) {
        throw new RuntimeException(
            'Unexpected API response'
        );
    }

    return $result;
}

$created = requestJson(
    CREATE_TASK_URL,
    [
        'key' => $apiKey,
        'method' => 'userrecaptcha',
        'version' => 'v3',
        'googlekey' =>
            '6LfB5_IbAAAAAMCtsjEHEHK' .
            'qcB9iQocwwxTiihJu',
        'pageurl' =>
            'https://example.com/login',
        'action' => 'login',
        'min_score' => '0.3',
        'domain' => 'google.com',
        'json' => '1',
    ],
    true
);

if (($created['status'] ?? 0) !== 1) {
    throw new RuntimeException(
        'Task creation failed: ' .
        ($created['request'] ??
            'UNKNOWN_ERROR')
    );
}

$taskId = (string) $created['request'];

sleep(20);

$deadline = time() + 180;
$token = null;

while (time() < $deadline) {
    $result = requestJson(
        GET_RESULT_URL,
        [
            'key' => $apiKey,
            'action' => 'get',
            'id' => $taskId,
            'json' => '1',
        ]
    );

    if (($result['status'] ?? 0) === 1) {
        $token = (string) $result['request'];
        break;
    }

    $errorCode = (string) (
        $result['request'] ??
        'UNKNOWN_ERROR'
    );

    if ($errorCode !== 'CAPCHA_NOT_READY') {
        throw new RuntimeException(
            'Captcha task failed: ' .
            $errorCode
        );
    }

    sleep(5);
}

if ($token === null) {
    throw new RuntimeException(
        'Captcha task timed out'
    );
}

echo 'Task ID: ' . $taskId . PHP_EOL;
echo 'Token: ' . $token . PHP_EOL;

Reporting accepted and rejected tokens

After applying the token, report whether it was accepted.

Accepted token:

https://api.solvecaptcha.com/res.php?key=YOUR_API_KEY&action=reportgood&id=TASK_ID

Rejected token:

https://api.solvecaptcha.com/res.php?key=YOUR_API_KEY&action=reportbad&id=TASK_ID

Use reportgood when:

  • the protected request succeeded;
  • the form was submitted;
  • the website accepted the token;
  • no captcha validation error was returned.

Use reportbad only when the token itself was rejected.

Do not use reportbad when the failure was caused by:

  • an incorrect site key;
  • an incorrect page URL;
  • the wrong action;
  • an expired page;
  • an integration error;
  • an incorrect form field;
  • a browser session change;
  • application validation unrelated to captcha.

SolveCaptcha allows reports to be submitted for a limited period after task creation, so send the report immediately after determining the result.

Common errors

ERROR_WRONG_USER_KEY

The API key is invalid.

Check:

SOLVECAPTCHA_API_KEY

ERROR_ZERO_BALANCE

The account balance is insufficient.

Stop creating new tasks until the balance is replenished.

ERROR_CAPTCHA_UNSOLVABLE

The captcha could not be solved reliably.

Check:

  • googlekey;
  • pageurl;
  • version=v3;
  • action;
  • min_score;
  • the reCAPTCHA loading domain.

Do not repeatedly submit the same incorrect parameters.

CAPCHA_NOT_READY

The task is still processing.

Wait five seconds and request the result again using the same task ID.

Token rejected by the website

Possible causes include:

  • incorrect action;
  • incorrect site key;
  • incorrect page URL;
  • unsupported requested score;
  • token applied to the wrong request field;
  • token applied after the page state changed;
  • website-specific verification requirements.

Common implementation mistakes

Using API v2 parameter names

Do not submit:

RecaptchaV3TaskProxyless
websiteURL
websiteKey
pageAction
minScore

The documented SolveCaptcha integration uses:

method=userrecaptcha
version=v3
pageurl
googlekey
action
min_score

Using createTask and getTaskResult

Use:

https://api.solvecaptcha.com/in.php

and:

https://api.solvecaptcha.com/res.php

Requesting an unrealistic score

Do not assume that requesting:

min_score=0.9

guarantees a score of 0.9.

The SolveCaptcha documentation warns that obtaining scores above 0.3 can be difficult.

Guessing the action

The action should match the value passed by the website to:

grecaptcha.execute()

Polling too early

Wait approximately 15–20 seconds before the first result request.

Polling too frequently

After receiving:

CAPCHA_NOT_READY

wait five seconds.

Applying the token only to g-recaptcha-response

Some websites use:

g-recaptcha-response-100000

or a custom request parameter.

Inspect the real network request.

Reporting every failed request as reportbad

An integration failure does not prove that the returned token was incorrect.

Frequently asked questions

Which method is used for reCAPTCHA v3?

Use:

method=userrecaptcha
version=v3

Which parameters are required?

Required parameters are:

key
method
version
googlekey
pageurl

Is action required?

No. The documentation defines it as optional and uses:

verify

as the default value.

When the website specifies an action, send the exact value.

Is min_score required?

No. The documented default is:

0.4

A lower value such as 0.3 is generally more realistic when the target website permits it.

Where can I find the site key?

Look for:

api.js?render=SITE_KEY
grecaptcha.execute("SITE_KEY")

or:

k=SITE_KEY

in a reCAPTCHA iframe URL.

Where is the token returned?

The completed JSON response contains it in:

request

How often should I request the result?

Wait 15–20 seconds before the first request. If the API returns CAPCHA_NOT_READY, repeat after five seconds.

Where should the token be submitted?

Inspect the target request. Common fields include:

g-recaptcha-response
g-recaptcha-response-100000

Does min_score guarantee acceptance?

No. The website can reject a token based on the action, page, site key, score, or application-specific checks.

Should I report results?

Yes. Use:

reportgood

for accepted tokens and:

reportbad

only for genuinely rejected solutions.

Conclusion

A reliable reCAPTCHA v3 integration requires accurate parameters rather than repeated experimentation with arbitrary scores.

The correct workflow is:

  1. Confirm that the page uses reCAPTCHA v3.
  2. Extract the site key from api.js, an iframe, or grecaptcha.execute().
  3. Find the exact action used by the website.
  4. Submit method=userrecaptcha.
  5. Set version=v3.
  6. Pass the site key as googlekey.
  7. Pass the complete page URL as pageurl.
  8. Use a realistic min_score.
  9. Wait 15–20 seconds before checking the result.
  10. Poll every five seconds while the task is processing.
  11. Apply the token through the field or request used by the website.
  12. Report accepted and genuinely rejected solutions.

Use the SolveCaptcha API documentation to verify the current parameters before deploying the integration.