Captcha solving service blog | SolveCaptcha How to bypass reCAPTCHA v3

How to bypass reCAPTCHA v3 with solver

Unlike reCAPTCHA v2, reCAPTCHA v3 usually does not display a checkbox or image challenge.

It runs in the background, generates a short-lived token, and allows the website backend to evaluate the request using a risk score. A higher score generally indicates traffic that Google considers more likely to be legitimate.

For authorized automation, the required workflow is:

Open the protected page
→ find the reCAPTCHA site key
→ identify the action
→ submit the parameters to SolveCaptcha
→ wait for the result
→ retrieve the token
→ send it through the expected request
→ preserve the current session

This guide explains:

  • how reCAPTCHA v3 differs from v2;
  • what the score means;
  • why a valid token may still be rejected;
  • how to find the site key and action;
  • how to create a SolveCaptcha task;
  • how to retrieve the token;
  • how to use it in an HTTP or browser workflow;
  • how to troubleshoot low-score and integration errors.

Use these methods only on websites you own or are authorized to test and automate.

How reCAPTCHA v3 works

reCAPTCHA v3 does not normally ask the visitor to complete a visible challenge.

The page executes JavaScript similar to:

grecaptcha.ready(() => {
  grecaptcha.execute(
    "SITE_KEY",
    {
      action: "login"
    }
  ).then((token) => {
    submitLogin(token);
  });
});

Google returns a token associated with the current:

Site key
Hostname
Action
Execution time
Verification context

The page sends this token to its backend.

The backend then verifies it with Google and receives information that can include:

  • whether verification succeeded;
  • the hostname;
  • the action;
  • the score;
  • the challenge timestamp;
  • possible error codes.

The website decides whether to accept, reject, or further verify the request.

reCAPTCHA v3 does not have a universal passing score

Scores range from:

0.0

to:

1.0

Higher values generally represent lower perceived risk, but Google does not define one universal score that every website must accept.

The website owner selects the threshold and can use different rules for different actions.

For example, an application may:

Accept login at 0.7 or higher
Require additional verification between 0.3 and 0.7
Reject requests below 0.3

Another website may use completely different thresholds.

A token with a score of 0.3 can therefore work on one website and fail on another.

The actual score is not contained in the token response

SolveCaptcha returns a reCAPTCHA token.

The token itself does not expose the final score to your client-side script.

The score becomes available only when the protected website verifies the token on its backend.

This means your automation usually cannot determine the actual score by examining:

g-recaptcha-response

or the SolveCaptcha response.

To confirm the score on an application you control, inspect the server-side verification response.

A valid token does not guarantee access

A website can reject a request even when the token is structurally valid.

Common reasons include:

  • the score is below the website threshold;
  • the action does not match;
  • the token was generated for another hostname;
  • the token has expired;
  • the token was already used;
  • the page session changed;
  • the CSRF token is invalid;
  • required cookies are missing;
  • the source IP changed;
  • another anti-bot rule blocked the request;
  • normal application validation failed.

Do not assume that every HTTP 403 response means the reCAPTCHA token was invalid.

Inspect the complete response and application workflow.

Required SolveCaptcha parameters

The main reCAPTCHA v3 parameters are:

Parameter Required Description
key Yes Your SolveCaptcha API key
method Yes Must be userrecaptcha
version Yes Must be v3
googlekey Yes Public reCAPTCHA site key
pageurl Yes Full URL containing reCAPTCHA
action Recommended Action passed to grecaptcha.execute()
min_score No Requested minimum score
domain No google.com or recaptcha.net
enterprise No Set to 1 for reCAPTCHA Enterprise
userAgent No User-Agent from the current browser
cookies No Cookies required by the current integration
data-s No Additional value used by some Google pages
proxy No Proxy in login:password@host:port format
proxytype No HTTP, HTTPS, SOCKS4, or SOCKS5
json Recommended Set to 1 for JSON responses

The core request is:

method=userrecaptcha
version=v3
googlekey=SITE_KEY
pageurl=PAGE_URL
action=ACTION
min_score=0.3

Step 1: Find the site key

The reCAPTCHA v3 site key commonly appears in the script URL:

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

The site key is the value of:

render

It may also appear in the call to grecaptcha.execute():

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

Search the page source and loaded scripts for:

recaptcha/api.js?render=
grecaptcha.execute
grecaptcha.enterprise.execute
data-sitekey

Do not confuse the public site key with the private secret key used by the website backend.

Step 2: Find the action

The action is one of the most important reCAPTCHA v3 parameters.

Common examples include:

login
register
checkout
contact
search
submit
verify
homepage

Look for a call similar to:

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

In this example, the action is:

login

Send the exact value to SolveCaptcha:

action=login

Do not guess between similar values such as:

login
signin
authenticate
verification

The website backend can compare the returned action with the action it expects.

Find the site key and action in DevTools

Open DevTools and use:

  • Elements to inspect the page;
  • Sources to search loaded JavaScript;
  • Network to inspect scripts and protected requests;
  • Console to run diagnostic code.

Search all loaded sources for:

grecaptcha.execute

In Chrome DevTools, use:

Ctrl+Shift+F

On macOS:

Command+Option+F

This searches across loaded scripts rather than only the current HTML document.

Browser-console detector

The following script attempts to find the site key from the reCAPTCHA script URL and locate action values in inline JavaScript:

function detectRecaptchaV3() {
  const result = {
    siteKey: null,
    actions: [],
    enterprise: false,
    domain: "google.com",
    pageurl: window.location.href
  };

  for (const script of document.scripts) {
    if (script.src) {
      try {
        const url = new URL(
          script.src,
          window.location.href
        );

        const isRecaptchaScript =
          /\/recaptcha\/(?:enterprise\/)?api\.js$/i.test(
            url.pathname
          );

        if (isRecaptchaScript) {
          const render =
            url.searchParams.get("render");

          if (
            render
            && render !== "explicit"
          ) {
            result.siteKey =
              result.siteKey || render;
          }

          result.enterprise =
            result.enterprise
            || url.pathname.includes(
              "/enterprise/"
            );

          result.domain =
            url.hostname.includes(
              "recaptcha.net"
            )
              ? "recaptcha.net"
              : "google.com";
        }
      } catch {
        // Ignore malformed script URLs.
      }
    }

    const source =
      script.textContent || "";

    const executePattern =
      /grecaptcha(?:\.enterprise)?\.execute\s*\(\s*["'`]([^"'`]+)["'`]\s*,\s*\{[\s\S]*?action\s*:\s*["'`]([^"'`]+)["'`]/g;

    for (
      const match of source.matchAll(
        executePattern
      )
    ) {
      result.siteKey =
        result.siteKey || match[1];

      result.actions.push(
        match[2]
      );
    }
  }

  result.actions = [
    ...new Set(result.actions)
  ];

  return result;
}

console.log(
  detectRecaptchaV3()
);

Example output:

{
  "siteKey": "6LfExampleSiteKey",
  "actions": [
    "login"
  ],
  "enterprise": false,
  "domain": "google.com",
  "pageurl": "https://example.com/login"
}

This detector cannot inspect every bundled or dynamically generated script.

Confirm the values manually before creating the SolveCaptcha task.

Dynamically generated actions

Some applications calculate the action dynamically:

const action =
  currentPage === "checkout"
    ? "purchase"
    : "browse";

grecaptcha.execute(
  siteKey,
  {
    action
  }
);

In this case, a basic regular expression may not find the final value.

Use one of these methods:

  1. Set a breakpoint on grecaptcha.execute().
  2. Inspect the function arguments in DevTools.
  3. Search the application bundle.
  4. Observe the protected request.
  5. Instrument grecaptcha.execute() before the action runs.

For applications you control, log the action during development.

Instrument grecaptcha.execute for debugging

Run this before the protected action:

function monitorRecaptchaExecute() {
  const timer = setInterval(() => {
    if (
      !window.grecaptcha
      || typeof grecaptcha.execute
        !== "function"
    ) {
      return;
    }

    clearInterval(timer);

    const originalExecute =
      grecaptcha.execute.bind(
        grecaptcha
      );

    grecaptcha.execute = function (
      siteKey,
      options
    ) {
      console.log(
        "reCAPTCHA execute:",
        {
          siteKey,
          options
        }
      );

      return originalExecute(
        siteKey,
        options
      );
    };

    console.log(
      "grecaptcha.execute monitoring enabled"
    );
  }, 100);
}

monitorRecaptchaExecute();

This must run before the page calls grecaptcha.execute().

Reloading the page removes the instrumentation.

Step 3: Create a SolveCaptcha task

Send a POST request to:

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

Example:

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=SITE_KEY" \
  --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 value returned in:

request

If task creation fails:

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

Do not begin polling unless a valid task ID was returned.

About min_score

The min_score parameter tells SolveCaptcha which minimum score you are requesting.

Example:

min_score=0.3

It does not guarantee that:

  • the target website will accept the token;
  • the website uses the same threshold;
  • the complete protected request is valid;
  • another anti-bot rule will not block the session.

Higher requested scores can take longer, cost more, or have lower availability.

Use the lowest score that satisfies the authorized application workflow.

Step 4: Retrieve the token

Wait approximately:

15–20 seconds

before sending the first result request.

Retrieve the result through:

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

Example:

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

If the task is still processing:

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

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

Do not create another task when the first task is still processing.

A completed response looks like:

{
  "status": 1,
  "request": "03AFcWeA5dCJ..."
}

The value in request is the reCAPTCHA v3 token.

Complete Python client

Install Requests:

python -m pip install requests

Store the API key:

export SOLVECAPTCHA_API_KEY="YOUR_API_KEY"

Create solve_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 ValueError as exc:
        raise SolveCaptchaError(
            "SolveCaptcha returned invalid JSON: "
            f"{response.text[:500]}"
        ) from exc

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

    return result

def create_task(
    *,
    api_key: str,
    site_key: str,
    page_url: str,
    action: str,
    min_score: float = 0.3,
    domain: str = "google.com",
    enterprise: bool = False,
    user_agent: str | None = None,
    cookies: str | None = None,
    data_s: str | None = None,
    proxy: str | None = None,
    proxy_type: str | None = None,
) -> str:
    if not site_key.strip():
        raise ValueError(
            "site_key cannot be empty."
        )

    if not page_url.strip():
        raise ValueError(
            "page_url cannot be empty."
        )

    if not action.strip():
        raise ValueError(
            "action cannot be empty."
        )

    if not 0.0 <= min_score <= 1.0:
        raise ValueError(
            "min_score must be between "
            "0.0 and 1.0."
        )

    payload: dict[str, Any] = {
        "key": api_key,
        "method": "userrecaptcha",
        "version": "v3",
        "googlekey": site_key,
        "pageurl": page_url,
        "action": action,
        "min_score": min_score,
        "domain": domain,
        "json": 1,
    }

    if enterprise:
        payload["enterprise"] = 1

    if user_agent:
        payload["userAgent"] = (
            user_agent
        )

    if cookies:
        payload["cookies"] = cookies

    if data_s:
        payload["data-s"] = data_s

    if proxy:
        payload["proxy"] = proxy

    if proxy_type:
        payload["proxytype"] = (
            proxy_type
        )

    response = requests.post(
        CREATE_TASK_URL,
        data=payload,
        timeout=30,
    )

    result = parse_response(
        response
    )

    if result.get("status") != 1:
        raise SolveCaptchaError(
            "Task creation failed: "
            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(
    *,
    api_key: str,
    task_id: str,
) -> str | None:
    response = requests.get(
        GET_RESULT_URL,
        params={
            "key": api_key,
            "action": "get",
            "id": task_id,
            "json": 1,
        },
        timeout=30,
    )

    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 failed: {error_code}"
    )

def solve_recaptcha_v3(
    *,
    api_key: str,
    site_key: str,
    page_url: str,
    action: str,
    min_score: float = 0.3,
    domain: str = "google.com",
    enterprise: bool = False,
    user_agent: str | None = None,
    cookies: str | None = None,
    data_s: str | None = None,
    proxy: str | None = None,
    proxy_type: str | None = None,
) -> RecaptchaV3Solution:
    task_id = create_task(
        api_key=api_key,
        site_key=site_key,
        page_url=page_url,
        action=action,
        min_score=min_score,
        domain=domain,
        enterprise=enterprise,
        user_agent=user_agent,
        cookies=cookies,
        data_s=data_s,
        proxy=proxy,
        proxy_type=proxy_type,
    )

    time.sleep(
        INITIAL_WAIT_SECONDS
    )

    deadline = (
        time.monotonic()
        + MAX_WAIT_SECONDS
    )

    while time.monotonic() < deadline:
        token = get_result(
            api_key=api_key,
            task_id=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 main() -> None:
    api_key = os.environ.get(
        "SOLVECAPTCHA_API_KEY",
        "",
    ).strip()

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

    solution = solve_recaptcha_v3(
        api_key=api_key,
        site_key="SITE_KEY",
        page_url=(
            "https://example.com/login"
        ),
        action="login",
        min_score=0.3,
    )

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

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

if __name__ == "__main__":
    main()

Run the script:

python solve_recaptcha_v3.py

Example output:

Task ID: 2122988149
Token: 03AFcWeA5dCJ...

Method 1: Submit the token through an HTTP request

Direct HTTP submission can work when you know the exact request that the application sends after generating the token.

First complete the action manually and inspect the request in DevTools:

  1. Open the Network panel.
  2. Perform the protected action.
  3. Find the login, registration, or form request.
  4. Inspect its request body.
  5. Identify the token field.
  6. Preserve cookies, CSRF values, and headers.

The token field may be:

g-recaptcha-response

or a custom field such as:

recaptchaToken
captchaToken
verificationToken
token

Example with Requests:

import requests

from solve_recaptcha_v3 import (
    solve_recaptcha_v3,
)

session = requests.Session()

session.headers.update({
    "User-Agent": (
        "Mozilla/5.0 "
        "(Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 "
        "Chrome/134.0.0.0 "
        "Safari/537.36"
    )
})

page_url = (
    "https://example.com/login"
)

page_response = session.get(
    page_url,
    timeout=30,
)

page_response.raise_for_status()

solution = solve_recaptcha_v3(
    api_key="YOUR_API_KEY",
    site_key="SITE_KEY",
    page_url=page_url,
    action="login",
    min_score=0.3,
    user_agent=session.headers[
        "User-Agent"
    ],
)

response = session.post(
    "https://example.com/api/login",
    json={
        "username": "[email protected]",
        "password": "PASSWORD",
        "recaptchaToken": solution.token,
    },
    headers={
        "Referer": page_url,
    },
    timeout=30,
)

print(
    "Status:",
    response.status_code,
)

print(
    "Response:",
    response.text[:500],
)

Use the actual token field and content type expected by the application.

Do not assume that every site uses JSON or g-recaptcha-response.

TLS impersonation is not a universal score fix

Libraries such as curl_cffi can reproduce selected browser-like TLS and HTTP characteristics.

This does not guarantee:

  • a higher reCAPTCHA score;
  • acceptance by the website;
  • a valid browser session;
  • correct cookies;
  • matching client hints;
  • successful application validation.

reCAPTCHA scoring is not documented as depending on one TLS fingerprint alone.

Replacing Requests with a browser-impersonation library may change the network profile, but it does not fix:

  • an incorrect action;
  • an expired token;
  • the wrong hostname;
  • a missing CSRF token;
  • session inconsistency;
  • account restrictions;
  • application-level blocking.

Start by reproducing the complete legitimate request before changing the HTTP stack.

Method 2: Use SeleniumBase

SeleniumBase can manage the browser session while your Python code requests a SolveCaptcha token.

Install it:

python -m pip install seleniumbase

Create run_recaptcha_v3.py:

#!/usr/bin/env python3

from __future__ import annotations

import os

from seleniumbase import SB

from solve_recaptcha_v3 import (
    solve_recaptcha_v3,
)

TARGET_URL = (
    "https://example.com/login"
)

SITE_KEY = "SITE_KEY"
ACTION = "login"

def format_cookies(
    browser,
) -> str | None:
    cookies = (
        browser.driver.get_cookies()
    )

    if not cookies:
        return None

    return "".join(
        f"{cookie['name']}:"
        f"{cookie['value']};"
        for cookie in cookies
        if cookie.get("name")
    )

def apply_token(
    browser,
    *,
    token: str,
    callback_path: str | None = None,
) -> dict:
    return browser.execute_script(
        """
        const token = arguments[0];
        const callbackPath = arguments[1];

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

        for (const field of fields) {
          field.value = token;
          field.innerHTML = token;

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

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

        let callbackCalled = false;

        if (callbackPath) {
          const callback = callbackPath
            .split(".")
            .reduce(
              (object, key) =>
                object?.[key],
              window
            );

          if (
            typeof callback
            === "function"
          ) {
            callback(token);
            callbackCalled = true;
          }
        }

        return {
          fieldsUpdated: fields.length,
          callbackCalled
        };
        """,
        token,
        callback_path,
    )

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

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

    with SB(
        headless=False
    ) as browser:
        browser.open(
            TARGET_URL
        )

        browser.sleep(3)

        user_agent = (
            browser.execute_script(
                "return navigator.userAgent"
            )
        )

        cookies = format_cookies(
            browser
        )

        solution = solve_recaptcha_v3(
            api_key=api_key,
            site_key=SITE_KEY,
            page_url=(
                browser.get_current_url()
            ),
            action=ACTION,
            min_score=0.3,
            user_agent=user_agent,
            cookies=cookies,
        )

        result = apply_token(
            browser,
            token=solution.token,
            callback_path=None,
        )

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

        print(
            "Fields updated:",
            result["fieldsUpdated"],
        )

        print(
            "Callback called:",
            result["callbackCalled"],
        )

        browser.click(
            "#login-button"
        )

if __name__ == "__main__":
    main()

Update:

TARGET_URL
SITE_KEY
ACTION
#login-button

for the application you are testing.

reCAPTCHA v3 may not have a hidden response field

Unlike many reCAPTCHA v2 integrations, reCAPTCHA v3 often passes the token directly to application code:

grecaptcha.execute(
  siteKey,
  {
    action: "login"
  }
).then((token) => {
  submitLogin(token);
});

In this workflow, the page may not contain:

g-recaptcha-response

A generic token-injection script will therefore update zero fields.

You must determine how the application uses the token.

Possible implementations include:

JavaScript callback
Fetch request
XMLHttpRequest
JSON body
Hidden input
Framework state
Custom event

Inspect the normal browser request in the Network panel.

Call the application callback

When the application exposes a global callback:

function loginCallback(token) {
  // Continue login workflow.
}

Call it with the SolveCaptcha token:

browser.execute_script(
    """
    const token = arguments[0];

    if (
      typeof window.loginCallback
      !== "function"
    ) {
      throw new Error(
        "loginCallback was not found."
      );
    }

    window.loginCallback(token);
    """,
    solution.token,
)

Pass the token as a JavaScript argument.

Do not interpolate it directly into an f-string:

# Avoid this:
browser.execute_script(
    f"loginCallback('{solution.token}')"
)

Direct interpolation can produce invalid JavaScript when the token contains special characters.

Submit through a custom request

Some applications generate the token and immediately send an HTTP request:

fetch("/api/login", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    username,
    password,
    recaptchaToken: token
  })
});

In this case, reproduce the same request using:

  • the same endpoint;
  • the same cookies;
  • the same headers;
  • the same CSRF token;
  • the same field name;
  • the SolveCaptcha token.

Do not create an arbitrary hidden field if the application never reads it.

Session consistency

Keep the following values consistent until the protected request is complete:

Page URL
Hostname
Action
Cookies
CSRF state
User-Agent
Proxy
Browser profile
Form state

Avoid:

  • reloading the page while the task is processing;
  • changing the proxy before submission;
  • using cookies from another browser;
  • solving for one action and submitting to another;
  • using a token from another hostname;
  • waiting unnecessarily after receiving the token.

If the page state changes, create a new task with fresh parameters.

Proxy configuration

A proxy is optional for the basic SolveCaptcha reCAPTCHA v3 request.

When the authorized workflow requires the solving task to use your proxy, add:

proxy=login:password@host:port
proxytype=HTTP

Example:

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=SITE_KEY" \
  --data-urlencode "pageurl=https://example.com/login" \
  --data-urlencode "action=login" \
  --data-urlencode "min_score=0.3" \
  --data-urlencode "proxy=user:[email protected]:8000" \
  --data-urlencode "proxytype=HTTP" \
  --data-urlencode "json=1"

Supported proxy types are:

HTTP
HTTPS
SOCKS4
SOCKS5

Do not assume that a residential proxy automatically produces a higher score.

Proxy quality, consistency, availability, and target-site acceptance are more important than the marketing category attached to the proxy.

User-Agent consistency

When sending userAgent, use the exact value from the current browser:

navigator.userAgent

With SeleniumBase:

user_agent = browser.execute_script(
    "return navigator.userAgent"
)

Do not select an unrelated User-Agent string only because it looks newer.

A consistent browser profile is preferable to independently changing:

User-Agent
Platform
Client hints
Viewport
Locale
Timezone
WebGL values

Random combinations can create an internally inconsistent environment.

reCAPTCHA Enterprise v3

A page using reCAPTCHA Enterprise may load:

/recaptcha/enterprise.js

or call:

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

For Enterprise, add:

enterprise=1

Example:

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 "enterprise=1" \
  --data-urlencode "googlekey=SITE_KEY" \
  --data-urlencode "pageurl=https://example.com/login" \
  --data-urlencode "action=login" \
  --data-urlencode "min_score=0.3" \
  --data-urlencode "json=1"

Do not add enterprise=1 to a standard reCAPTCHA v3 task.

Why the score may be lower than expected

A low score does not identify one specific technical defect.

Possible factors include:

  • the action differs from the expected value;
  • the site key is incorrect;
  • the token is submitted too late;
  • the token belongs to another hostname;
  • the browser session changed;
  • the network address has poor reputation;
  • the request pattern is unusual;
  • cookies are missing;
  • the application applies additional risk rules;
  • the requested score is unavailable.

Google does not provide clients with a complete list of every scoring signal or its weight.

Avoid claims such as:

TLS fingerprint is always the main cause
Residential proxy always gives a high score
Undetected Chrome guarantees acceptance
Mouse movement guarantees a higher score

These statements cannot be applied reliably across all websites.

Common API errors

ERROR_WRONG_USER_KEY

The SolveCaptcha API key is invalid.

Copy it again from the account settings and remove spaces or line breaks.

ERROR_ZERO_BALANCE

The account balance is insufficient.

Add funds before creating another task.

ERROR_CAPTCHA_UNSOLVABLE

The task could not be completed with the submitted parameters.

Check:

  • googlekey;
  • pageurl;
  • action;
  • min_score;
  • version=v3;
  • enterprise;
  • proxy configuration;
  • optional session parameters.

Capture fresh values before retrying.

CAPCHA_NOT_READY

The task is still processing.

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

Do not create another task.

Website-side troubleshooting

Token is returned but the website blocks the request

Check:

  • whether the token field is correct;
  • whether the action matches;
  • whether the hostname matches;
  • whether the session cookies are current;
  • whether the CSRF token is valid;
  • whether the token has expired;
  • whether another anti-bot system blocked the request;
  • whether the application rejected the submitted data.

The response says action mismatch

Find the actual value passed to:

grecaptcha.execute()

Then create a new task with that exact action.

The token field cannot be found

reCAPTCHA v3 may pass the token directly to a callback or HTTP request.

Inspect the Network panel instead of creating a hidden field blindly.

The task works on one page but fails on another

Different pages can use:

  • different actions;
  • different site keys;
  • different thresholds;
  • different server-side policies.

Extract the parameters from each protected workflow.

The token expires before submission

Request the token immediately before the protected action and submit it without unnecessary delay.

The score cannot be read from the API response

This is expected.

The score is returned during server-side verification by the protected website, not as part of the SolveCaptcha token response.

Common implementation mistakes

Using reCAPTCHA v2 parameters without version

Incorrect:

method=userrecaptcha
googlekey=SITE_KEY
pageurl=PAGE_URL

Correct for v3:

method=userrecaptcha
version=v3
googlekey=SITE_KEY
pageurl=PAGE_URL
action=ACTION

Using websiteKey instead of googlekey

Incorrect:

websiteKey=SITE_KEY

Correct:

googlekey=SITE_KEY

Using websiteURL instead of pageurl

Incorrect:

websiteURL=PAGE_URL

Correct:

pageurl=PAGE_URL

Using createTask and getTaskResult

Incorrect:

createTask
getTaskResult
clientKey
taskId

Correct:

in.php
res.php
key
request

Guessing the action

Inspect the active page and JavaScript.

Assuming the action is always verify

verify may be used as a default, but the website can require another action.

Expecting the score in the token response

The client receives only the token.

Reusing a token

Treat every token as short-lived and single-use.

Applying the token to g-recaptcha-response without checking

Many v3 pages use a custom callback or request field.

Using v2 test keys for v3

reCAPTCHA v2 test keys are not a drop-in replacement for a reCAPTCHA v3 integration.

For applications you control, configure separate staging credentials or mock the server-side verification result.

Assuming SeleniumBase guarantees a high score

SeleniumBase is an automation framework. It does not guarantee any reCAPTCHA score or website acceptance.

Changing browser properties independently

Use a coherent browser environment rather than randomizing individual fingerprint values.

Testing applications you control

For ordinary QA tests, avoid solving production reCAPTCHA during every automated run.

Better options include:

  • staging-specific site keys;
  • mocked server-side verification;
  • a test-only verification adapter;
  • deterministic accepted and rejected responses;
  • provider-supported test configuration;
  • limited production integration tests.

Use a real SolveCaptcha task when the purpose of the test is to verify the complete third-party integration.

Best practices

Extract the action from the current workflow

One website may use several actions:

homepage
login
register
checkout

Do not reuse one action for every request.

Request the token immediately before submission

Reduce the time between:

Token received

and:

Protected request sent

Preserve the session

Keep the same cookies, page state, User-Agent, and proxy.

Use controlled polling

A practical configuration is:

Initial wait: 20 seconds
Polling interval: 5 seconds
Maximum wait: 180 seconds

Validate the final website response

The important result is not whether the API returned a token.

The important result is whether the protected application accepted the request.

Log useful diagnostics

Record:

  • task ID;
  • hostname;
  • page URL;
  • action;
  • requested minimum score;
  • Enterprise mode;
  • task creation time;
  • completion time;
  • API error;
  • target response status.

Do not log:

  • API keys;
  • proxy passwords;
  • authentication cookies;
  • full reCAPTCHA tokens;
  • user passwords.

Pre-launch checklist

Before deploying the integration, confirm:

  • [ ] The page uses reCAPTCHA v3.
  • [ ] The current site key was extracted.
  • [ ] The exact action was identified.
  • [ ] The complete page URL is correct.
  • [ ] method=userrecaptcha is used.
  • [ ] version=v3 is included.
  • [ ] The site key is sent as googlekey.
  • [ ] The page URL is sent as pageurl.
  • [ ] The action matches the protected workflow.
  • [ ] min_score is supported and realistic.
  • [ ] Enterprise mode is detected correctly.
  • [ ] The task ID is read from request.
  • [ ] The first result request waits 15–20 seconds.
  • [ ] Later requests use five-second intervals.
  • [ ] The completed token is read from request.
  • [ ] The expected request field or callback was identified.
  • [ ] The browser or HTTP session remains unchanged.
  • [ ] The token is submitted immediately.
  • [ ] A new task is created after the page or action changes.

Frequently asked questions

What is reCAPTCHA v3?

It is a background verification system that generates an action-specific token and allows the website backend to evaluate risk using a score.

Does reCAPTCHA v3 display image puzzles?

Normally, no.

The site may respond to a low score by showing another verification step, including reCAPTCHA v2.

What score is required?

There is no universal threshold.

The website owner determines which score is acceptable for each action.

Can SolveCaptcha guarantee a particular score?

The min_score parameter requests a minimum score, but it does not guarantee acceptance by the target website.

Where can I find the site key?

Look for:

api.js?render=SITE_KEY

or the first argument passed to:

grecaptcha.execute()

Where can I find the action?

Look inside:

{
  action: "login"
}

passed to grecaptcha.execute().

Which SolveCaptcha method should I use?

Use:

method=userrecaptcha
version=v3

Where is the token returned?

With json=1, the token is returned in:

request

Where should the token be inserted?

Inspect the website’s normal request.

It may use:

g-recaptcha-response
recaptchaToken
captchaToken

or pass the token directly to a callback.

Can I read the score from the token?

No.

The score becomes available to the protected website during server-side verification.

Is a proxy required?

Not always.

Use one when the authorized workflow requires a consistent network address or specific location.

Does curl_cffi guarantee a higher score?

No.

It can reproduce selected browser-like network characteristics, but it does not guarantee any score or website acceptance.

Does SeleniumBase UC Mode guarantee a high score?

No.

Browser automation configuration is only one part of the complete request context.

Can I reuse a token?

No.

Treat the token as short-lived and single-use.

How often should I poll?

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

Continue every five seconds while the API returns:

CAPCHA_NOT_READY

Conclusion

Bypassing reCAPTCHA v3 with SolveCaptcha requires more than obtaining a random valid token.

The correct workflow is:

  1. Confirm that the page uses reCAPTCHA v3.
  2. Extract the current site key.
  3. Identify the exact action.
  4. Determine whether the page uses standard or Enterprise reCAPTCHA.
  5. Record the full page URL.
  6. Submit method=userrecaptcha.
  7. Add version=v3.
  8. Pass the site key as googlekey.
  9. Pass the exact action.
  10. Request a realistic min_score.
  11. Save the task ID returned in request.
  12. Wait approximately 15–20 seconds.
  13. Poll res.php every five seconds.
  14. Read the completed token from request.
  15. Inspect how the website normally submits the token.
  16. Use the expected form field, callback, or request property.
  17. Preserve cookies, CSRF state, User-Agent, and proxy.
  18. Submit the token immediately.
  19. Validate the complete website response.
  20. Create a new task when the action or page state changes.

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