Captcha solving service blog | SolveCaptcha How to bypass captcha in Google Chrome with solver

How to bypass captcha in Google Chrome browser with solver

Captchas can interrupt browser automation, QA testing, data collection, and other authorized workflows in Google Chrome.

The correct integration depends on how much automation you need.

You can:

  1. Test SolveCaptcha requests manually through Postman.
  2. Use the SolveCaptcha browser extension directly in Chrome.
  3. Connect to the SolveCaptcha API from Python.
  4. Combine the API with Selenium or Puppeteer.

The general workflow is:

Open the protected page in Chrome
→ identify the captcha type
→ extract the required public parameters
→ submit them to SolveCaptcha
→ wait for the solution
→ apply the returned token or answer
→ continue the normal page workflow

This guide uses reCAPTCHA v2 as the main example because its token workflow is easy to demonstrate. Other captcha types require different parameters and may return a token, cookie, coordinates, or text answer.

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

What you need

Before starting, prepare:

  • Google Chrome;
  • a SolveCaptcha account;
  • your SolveCaptcha API key;
  • Postman for manual API testing;
  • Python 3.10 or later for Python automation;
  • Selenium or Puppeteer for browser automation;
  • the URL of the page containing the captcha.

Copy the API key from your SolveCaptcha account settings.

Store it in an environment variable rather than placing it directly in source code.

Linux or macOS:

export SOLVECAPTCHA_API_KEY="YOUR_API_KEY"

Windows PowerShell:

$env:SOLVECAPTCHA_API_KEY="YOUR_API_KEY"

Do not expose the API key in:

  • browser-console scripts;
  • public repositories;
  • screenshots;
  • application logs;
  • client-side JavaScript;
  • shared Postman collections.

Captcha types supported by SolveCaptcha

SolveCaptcha supports common visual, interactive, and token-based challenges, including:

  • image and letter captchas;
  • text questions;
  • reCAPTCHA v2;
  • Invisible reCAPTCHA v2;
  • reCAPTCHA v3;
  • reCAPTCHA Enterprise;
  • Cloudflare Turnstile;
  • Arkose Labs FunCaptcha;
  • GeeTest v3 and v4;
  • Friendly Captcha;
  • DataDome;
  • Amazon AWS WAF CAPTCHA;
  • audio captchas;
  • coordinate and grid challenges.

Each captcha type has its own required parameters and result format.

For example:

Captcha type Typical input Typical result
Image captcha Image file or Base64 data Recognized text
reCAPTCHA v2 Site key and page URL Response token
reCAPTCHA v3 Site key, page URL, action, score Response token
FunCaptcha Public key, page URL, optional blob Session token
DataDome Captcha URL, proxy, User-Agent datadome cookie
Amazon WAF Site key, context, IV Voucher and token
Coordinate captcha Image and instruction Click coordinates

Do not use one generic request body for every captcha provider.

Check the SolveCaptcha API documentation and select the method that matches the captcha detected in Chrome.

Three ways to solve captchas in Chrome

The three main integration options are:

Method Coding required Automation level Best use case
Postman No Manual API testing and debugging
Browser extension Minimal Semi-automatic or automatic Interactive Chrome workflows
Direct API Yes Full Production automation

Postman is the easiest way to understand the API.

The extension is convenient when you want the solution applied inside Chrome.

Direct API integration provides the most control over parameters, polling, proxy configuration, and error handling.

Method 1: Test captcha solving with Postman

Postman does not modify the Chrome page automatically.

It allows you to:

  1. create the SolveCaptcha task;
  2. retrieve the completed token;
  3. copy the result;
  4. apply it manually in Chrome.

This is useful before implementing a complete automation script.

SolveCaptcha API endpoints

Create a task through:

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

Retrieve the result through:

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

Do not use unrelated API structures such as:

/createTask
/getTaskResult
clientKey
websiteKey
websiteURL
RecaptchaV2TaskProxyless

For reCAPTCHA v2, the documented parameters are:

key
method=userrecaptcha
googlekey
pageurl
json=1

Create a Postman request

Create a new POST request in Postman:

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

Open the Body tab and select:

x-www-form-urlencoded

Add these fields:

Key Value
key Your SolveCaptcha API key
method userrecaptcha
googlekey The reCAPTCHA site key
pageurl Full URL containing the captcha
json 1

Example:

key=YOUR_API_KEY
method=userrecaptcha
googlekey=6LcExampleSiteKey
pageurl=https://example.com/login
json=1

A successful response contains a task ID:

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

Save the value returned in:

request

Import the request from cURL

Postman can also import this cURL request:

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

In Postman:

  1. Click Import.
  2. Select Raw text.
  3. Paste the cURL command.
  4. Confirm the import.
  5. Replace the example values.
  6. Send the request.

Retrieve the result in Postman

Create a GET request:

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

Add these query parameters:

Key Value
key Your SolveCaptcha API key
action get
id Task ID returned by in.php
json 1

Example URL:

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 send the same request again.

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

A completed response looks like this:

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

The value in request is the reCAPTCHA response token.

Apply a reCAPTCHA v2 token in Chrome

Open Chrome DevTools and select the Console tab.

Use this script:

function applyRecaptchaToken(token) {
  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
      })
    );
  }

  return {
    fieldsUpdated: fields.length
  };
}

console.log(
  applyRecaptchaToken(
    "TOKEN_FROM_SOLVECAPTCHA"
  )
);

Do not use only:

document.getElementById(
  "g-recaptcha-response"
).textContent = "TOKEN";

The page may contain several response fields, and application code may read the value property rather than textContent.

Call the captcha callback when required

A reCAPTCHA widget may define:

<div
  class="g-recaptcha"
  data-sitekey="SITE_KEY"
  data-callback="onCaptchaSolved">
</div>

After updating the response field, call:

window.onCaptchaSolved(
  "TOKEN_FROM_SOLVECAPTCHA"
);

For a nested callback:

application.forms.onCaptchaSolved

use:

function resolveFunction(path) {
  const value = path
    .split(".")
    .reduce(
      (object, key) =>
        object?.[key],
      window
    );

  return typeof value === "function"
    ? value
    : null;
}

const callback = resolveFunction(
  "application.forms.onCaptchaSolved"
);

if (callback) {
  callback(
    "TOKEN_FROM_SOLVECAPTCHA"
  );
}

Do not call an arbitrary function simply because its name contains captcha.

Use the callback configured by the current page.

Limitations of the Postman method

Postman is useful for testing, but it is not a complete Chrome automation solution.

Limitations include:

  • task creation is manual;
  • polling is manual unless you create a Postman script;
  • the token must be copied into Chrome;
  • session-dependent parameters may change;
  • short-lived tokens must be used immediately;
  • different captcha types require different result handling.

Move to the extension or direct API integration when the workflow becomes repetitive.

Method 2: Use the SolveCaptcha Chrome extension

The SolveCaptcha browser extension is the simplest way to solve supported captchas directly inside Chrome.

The extension can inspect the current page, detect supported widgets, send the required parameters to SolveCaptcha, and apply the returned result.

The exact controls and labels may vary between extension versions, but the basic setup remains the same.

Install and configure the extension

  1. Install the official SolveCaptcha extension for Chrome.
  2. Open the extension settings.
  3. Enter your SolveCaptcha API key.
  4. Enable only the captcha types you need.
  5. Choose manual or automatic solving.
  6. Open a supported page.
  7. Start the solve action.
  8. Wait for the result.
  9. Continue the normal page workflow.

Use manual mode while testing the integration.

Enable automatic solving only after confirming that the extension behaves correctly on the target page.

Manual and automatic modes

The extension can generally be used in two ways.

Manual solving

The extension detects the captcha and displays a solve control.

You decide when to submit the challenge.

This mode is better for:

  • debugging;
  • one-off tasks;
  • login forms;
  • pages with several captchas;
  • workflows where the page must be completed before solving.

Automatic solving

The extension submits supported challenges as soon as they are detected.

This mode is useful for repeatable workflows but can cause problems when:

  • the page reloads the captcha frequently;
  • the form is incomplete;
  • the captcha is connected to another button;
  • automatic submission creates a loop;
  • several widgets exist on the page.

Test automatic mode carefully before relying on it.

Image captchas

A basic image captcha usually has two separate elements:

  1. the image containing distorted text;
  2. the input where the answer must be entered.

When automatic detection is unavailable, the extension may require you to identify both elements manually.

The typical setup is:

  1. select the captcha image;
  2. mark it as the image to solve;
  3. select the corresponding answer field;
  4. mark it as the destination for the result;
  5. save the configuration for the domain.

Confirm that the selected image belongs to the current captcha and not to a logo, icon, or previous challenge.

Avoid automatic submission loops

Automatic form submission can cause repeated solving when:

  • required fields are empty;
  • the password is invalid;
  • CSRF validation fails;
  • the page regenerates the captcha;
  • the website returns to the same form;
  • the extension immediately detects the new challenge.

During setup:

Disable automatic submission
→ solve one challenge
→ verify that the answer is inserted correctly
→ submit the form manually
→ inspect the result
→ enable automatic submission only if necessary

Use a finite retry limit in automated workflows.

Token freshness

Captcha tokens are generally short-lived and often single-use.

After a token is returned:

  • apply it immediately;
  • do not reload the page;
  • do not change the browser session;
  • do not reuse it for another form submission;
  • request a new token when the widget resets.

Do not rely on one fixed lifetime for every captcha provider.

Launch Chrome with an unpacked extension using Selenium

For controlled testing, Selenium can launch Chrome with an unpacked extension.

from pathlib import Path

from selenium import webdriver

extension_path = Path(
    "/absolute/path/to/SolveCaptchaExtension"
).resolve()

if not extension_path.is_dir():
    raise FileNotFoundError(
        f"Extension directory not found: "
        f"{extension_path}"
    )

options = webdriver.ChromeOptions()

options.add_argument(
    f"--disable-extensions-except={extension_path}"
)

options.add_argument(
    f"--load-extension={extension_path}"
)

driver = webdriver.Chrome(
    options=options
)

driver.get(
    "https://example.com/login"
)

Configure the extension through its own settings before using it.

For persistent settings, launch Chrome with a dedicated user-data directory:

options.add_argument(
    "--user-data-dir=/absolute/path/"
    "to/chrome-profile"
)

Do not use your primary personal Chrome profile for automated testing.

Extension advantages

  • minimal code;
  • works inside the browser session;
  • convenient for manual and semi-automatic workflows;
  • can handle several supported captcha types;
  • returned results can be applied directly to the page;
  • useful for QA and interactive browser testing.

Extension limitations

  • requires a Chrome session;
  • detection may depend on the page implementation;
  • dynamically loaded widgets may require additional time;
  • custom callbacks may not be triggered automatically;
  • extension behavior can vary between websites;
  • complex application state may still require custom code.

Use direct API integration when you need predictable control over each step.

Method 3: Full automation through the SolveCaptcha API

Direct API integration gives you control over:

  • captcha detection;
  • parameter extraction;
  • task creation;
  • polling;
  • proxy configuration;
  • timeouts;
  • token insertion;
  • callback execution;
  • error handling;
  • logging.

The following example solves reCAPTCHA v2.

Complete Python API client

Install Requests:

python -m pip install requests

Create solve_recaptcha.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 CaptchaSolution:
    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,
    invisible: bool = False,
    user_agent: str | None = None,
    proxy: str | None = None,
    proxy_type: str | None = None,
) -> str:
    payload: dict[str, Any] = {
        "key": api_key,
        "method": "userrecaptcha",
        "googlekey": site_key,
        "pageurl": page_url,
        "json": 1,
    }

    if invisible:
        payload["invisible"] = 1

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

    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(
    *,
    api_key: str,
    site_key: str,
    page_url: str,
    invisible: bool = False,
    user_agent: str | None = None,
    proxy: str | None = None,
    proxy_type: str | None = None,
) -> CaptchaSolution:
    task_id = create_task(
        api_key=api_key,
        site_key=site_key,
        page_url=page_url,
        invisible=invisible,
        user_agent=user_agent,
        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 CaptchaSolution(
                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(
        api_key=api_key,
        site_key="6LcExampleSiteKey",
        page_url=(
            "https://example.com/login"
        ),
    )

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

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

if __name__ == "__main__":
    main()

Run it:

python solve_recaptcha.py

Use a proxy with the API

For captcha types that support or require a proxy, send:

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

Example:

solution = solve_recaptcha(
    api_key=api_key,
    site_key="6LcExampleSiteKey",
    page_url=(
        "https://example.com/login"
    ),
    proxy=(
        "user:password@"
        "proxy.example.com:8000"
    ),
    proxy_type="HTTP",
)

Supported proxy types can include:

HTTP
HTTPS
SOCKS4
SOCKS5

Do not split the proxy into unsupported fields such as:

proxyAddress
proxyPort
proxyLogin
proxyPassword

The documented format is:

proxy=login:password@host:port

Use the same proxy throughout a session when the captcha or target website connects the challenge to the source IP.

Integrate the API with Selenium

Install Selenium:

python -m pip install selenium

Example:

#!/usr/bin/env python3

from __future__ import annotations

import os

from selenium import webdriver
from selenium.webdriver.common.by import By

from solve_recaptcha import (
    solve_recaptcha,
)

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

def detect_recaptcha(
    driver,
) -> dict:
    return driver.execute_script(
        """
        const result = {
          siteKey: null,
          invisible: false,
          callbackName: null,
          domain: "google.com"
        };

        const widget = document.querySelector(
          ".g-recaptcha[data-sitekey],"
          + "[data-sitekey]"
        );

        if (widget) {
          result.siteKey =
            widget.getAttribute(
              "data-sitekey"
            );

          result.invisible =
            widget.getAttribute(
              "data-size"
            ) === "invisible";

          result.callbackName =
            widget.getAttribute(
              "data-callback"
            );
        }

        const frame = document.querySelector(
          'iframe[src*="/recaptcha/api2/anchor"]'
        );

        if (frame?.src) {
          const url = new URL(
            frame.src
          );

          result.siteKey =
            result.siteKey
            || url.searchParams.get("k");

          result.invisible =
            result.invisible
            || url.searchParams.get("size")
              === "invisible";

          result.domain =
            url.hostname.includes(
              "recaptcha.net"
            )
              ? "recaptcha.net"
              : "google.com";
        }

        return result;
        """
    )

def apply_token(
    driver,
    *,
    token: str,
    callback_name: str | None,
) -> dict:
    return driver.execute_script(
        """
        const token = arguments[0];
        const callbackName = 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 (callbackName) {
          const callback = callbackName
            .split(".")
            .reduce(
              (object, key) =>
                object?.[key],
              window
            );

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

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

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

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

    driver = webdriver.Chrome()

    try:
        driver.get(
            TARGET_URL
        )

        parameters = detect_recaptcha(
            driver
        )

        site_key = str(
            parameters.get(
                "siteKey"
            )
            or ""
        ).strip()

        if not site_key:
            raise RuntimeError(
                "reCAPTCHA site key "
                "was not found."
            )

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

        solution = solve_recaptcha(
            api_key=api_key,
            site_key=site_key,
            page_url=driver.current_url,
            invisible=bool(
                parameters.get(
                    "invisible"
                )
            ),
            user_agent=user_agent,
        )

        result = apply_token(
            driver,
            token=solution.token,
            callback_name=parameters.get(
                "callbackName"
            ),
        )

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

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

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

        submit_button = (
            driver.find_element(
                By.CSS_SELECTOR,
                "#submit-button"
            )
        )

        submit_button.click()

    finally:
        driver.quit()

if __name__ == "__main__":
    main()

Replace:

TARGET_URL

and:

#submit-button

with values from the application you are testing.

Pass tokens safely to JavaScript

Avoid inserting the token directly into a Python f-string:

driver.execute_script(
    f"callback('{token}')"
)

The token may contain characters that break the generated JavaScript.

Pass the token through arguments:

driver.execute_script(
    """
    const token = arguments[0];
    window.callback(token);
    """,
    token,
)

This is safer and easier to debug.

How to find the reCAPTCHA site key in Chrome

Without the correct site key, SolveCaptcha cannot create the appropriate task.

Find data-sitekey

Open Chrome DevTools:

F12

or:

Ctrl+Shift+I

On macOS:

Command+Option+I

Open the Elements tab and search for:

data-sitekey

Example:

<div
  class="g-recaptcha"
  data-sitekey="6LcExampleSiteKey">
</div>

The value of data-sitekey is sent as:

googlekey

Find the site key in an iframe

A reCAPTCHA iframe may contain:

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

The site key is the value of:

k

Search the Network panel for:

recaptcha/api2/anchor

Find a reCAPTCHA v3 site key

reCAPTCHA v3 may load:

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

The site key is the value of:

render

You must also identify the action:

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

The action in this example is:

login

A reCAPTCHA v3 task requires additional parameters such as:

version=v3
action=login
min_score=0.3

Do not use a reCAPTCHA v2 request unchanged for v3.

Chrome console detector

Run this in DevTools:

function detectRecaptcha() {
  const result = {
    siteKey: null,
    version: null,
    invisible: false,
    actions: [],
    callbackName: null
  };

  const widget = document.querySelector(
    ".g-recaptcha[data-sitekey],"
    + "[data-sitekey]"
  );

  if (widget) {
    result.siteKey =
      widget.getAttribute(
        "data-sitekey"
      );

    result.version = "v2";

    result.invisible =
      widget.getAttribute(
        "data-size"
      ) === "invisible";

    result.callbackName =
      widget.getAttribute(
        "data-callback"
      );
  }

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

        const render =
          url.searchParams.get(
            "render"
          );

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

          result.version = "v3";
        }
      } catch {
        // Ignore malformed script URLs.
      }
    }

    const source =
      script.textContent || "";

    const actionPattern =
      /action\s*:\s*["'`]([^"'`]+)["'`]/g;

    for (
      const match of source.matchAll(
        actionPattern
      )
    ) {
      result.actions.push(
        match[1]
      );
    }
  }

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

  return result;
}

console.log(
  detectRecaptcha()
);

Review the result manually. Bundled or dynamically generated scripts may require inspection through the Sources panel.

Bonus: Puppeteer with the SolveCaptcha extension

Puppeteer can launch Chrome with an unpacked extension.

For predictable behavior, use headed Chrome during extension testing.

Install Puppeteer:

npm install puppeteer

Create run-with-extension.js:

const path = require("node:path");
const puppeteer = require("puppeteer");

const extensionPath = path.resolve(
  __dirname,
  "SolveCaptchaExtension"
);

const profilePath = path.resolve(
  __dirname,
  "chrome-profile"
);

async function main() {
  const browser =
    await puppeteer.launch({
      headless: false,
      userDataDir: profilePath,
      args: [
        `--disable-extensions-except=${extensionPath}`,
        `--load-extension=${extensionPath}`
      ]
    });

  try {
    const pages =
      await browser.pages();

    const page =
      pages[0]
      || await browser.newPage();

    await page.goto(
      "https://example.com/login",
      {
        waitUntil: "domcontentloaded"
      }
    );

    await page.waitForFunction(
      () => {
        const fields = [
          ...document.querySelectorAll(
            '[name="g-recaptcha-response"]'
          )
        ];

        return fields.some(
          (field) =>
            typeof field.value === "string"
            && field.value.length > 20
        );
      },
      {
        timeout: 180000
      }
    );

    await page.click(
      "#submit-button"
    );

    await page.waitForNavigation({
      waitUntil: "domcontentloaded",
      timeout: 30000
    }).catch(() => {
      // Some forms update the page without navigation.
    });

  } finally {
    await browser.close();
  }
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

Update:

SolveCaptchaExtension
https://example.com/login
#submit-button

to match your environment.

Configure the extension profile

The userDataDir option preserves extension settings between runs.

A practical setup is:

  1. Run the Puppeteer script.
  2. Open the extension settings in the launched browser.
  3. Enter the SolveCaptcha API key.
  4. Configure the required captcha types.
  5. Close the browser.
  6. Run the script again using the same profile directory.

Keep the automated profile separate from your personal Chrome profile.

Do not depend on extension-specific page selectors

An extension version may change:

  • injected button classes;
  • status attributes;
  • internal element names;
  • UI structure.

Instead of waiting only for a selector such as:

.captcha-solver[data-state="solved"]

prefer waiting for the actual result expected by the page.

For reCAPTCHA v2, that can be a non-empty:

g-recaptcha-response

For other providers, wait for:

  • a returned cookie;
  • a completed callback;
  • an enabled submit button;
  • a page-specific success state;
  • an expected network request.

Headless Chrome considerations

Extension behavior in headless Chrome depends on the Chrome and Puppeteer versions and the extension implementation.

For initial setup and debugging:

Use headed Chrome
→ confirm that the extension loads
→ configure the API key
→ confirm that the captcha is detected
→ verify that the solution is applied

Move to another environment only after the headed workflow works correctly.

Common API errors

ERROR_WRONG_USER_KEY

The API key is invalid.

Copy it again from the SolveCaptcha 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:

  • captcha type;
  • site key;
  • page URL;
  • challenge version;
  • proxy configuration;
  • optional provider-specific parameters;
  • whether the page generated a new challenge.

Capture fresh parameters 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 a duplicate task.

Chrome-side troubleshooting

The token is returned but the page rejects it

Check:

  • whether the correct captcha type was selected;
  • whether the site key is current;
  • whether the page URL is exact;
  • whether the token was applied to the correct field;
  • whether a callback must be called;
  • whether the page was reloaded;
  • whether the session cookies changed;
  • whether the token expired;
  • whether another application check failed.

A valid captcha token does not replace CSRF validation, session cookies, account checks, or normal form validation.

No g-recaptcha-response field exists

The field may be created dynamically after reCAPTCHA initializes.

It may also be absent in a reCAPTCHA v3 integration that passes the token directly to a callback or Fetch request.

Inspect the Network panel to determine how the application submits the token.

The extension does not detect the captcha

Possible causes include:

  • the captcha loads after a user action;
  • the widget is inside an iframe;
  • the page uses a custom integration;
  • the captcha type is disabled in extension settings;
  • the extension lacks access to the current site;
  • another extension interferes with the page;
  • the challenge is not supported by the current extension version.

Reload the page after confirming the extension permissions and settings.

The extension solves repeatedly

Disable automatic submission and retries.

Then determine why the form is returning to the captcha page.

The actual error may be:

  • empty required field;
  • invalid credentials;
  • expired session;
  • invalid CSRF token;
  • another server-side validation failure.

Selenium applies the token but nothing happens

The page may require:

  • a configured callback;
  • a custom event;
  • a specific submit button;
  • a framework state update;
  • an HTTP request rather than a hidden field.

Compare the automated flow with a successful manual submission.

Puppeteer waits indefinitely

Confirm that:

  • the extension loaded;
  • the API key is configured;
  • the captcha type is enabled;
  • the page actually contains reCAPTCHA v2;
  • the response field exists;
  • the selector matches the current page;
  • the browser profile is writable.

Use a screenshot and DevTools during debugging.

Common implementation mistakes

Using createTask and getTaskResult

Incorrect:

createTask
getTaskResult
clientKey
taskId

Correct:

in.php
res.php
key
request

Sending JSON to the wrong API format

For the documented SolveCaptcha in.php workflow, send form parameters.

In Postman, use:

x-www-form-urlencoded

or:

form-data

depending on the captcha type.

Using websiteKey instead of googlekey

Incorrect:

websiteKey=SITE_KEY

Correct for reCAPTCHA:

googlekey=SITE_KEY

Using websiteURL instead of pageurl

Incorrect:

websiteURL=PAGE_URL

Correct:

pageurl=PAGE_URL

Updating only textContent

Set the response field’s value property and dispatch the appropriate events.

Inserting tokens through string interpolation

Pass the token as a JavaScript argument instead of building executable code with an f-string.

Assuming every captcha returns a token

Some captcha methods return:

  • recognized text;
  • coordinates;
  • a cookie;
  • several token values;
  • structured JSON.

Read the documentation for the selected provider.

Reusing old tokens

Treat returned tokens as short-lived and specific to the current challenge.

Reloading while waiting

Reloading can replace the challenge and invalidate the pending result.

Changing the proxy mid-session

Keep the network path consistent when the provider connects the challenge with the source IP.

Enabling unlimited automatic retries

Set a maximum retry count and log the reason for each failure.

Recommended workflow

For a new Chrome integration:

  1. Open the page manually.
  2. Identify the captcha provider.
  3. Inspect the page parameters in DevTools.
  4. Test the task through Postman.
  5. Retrieve one valid result.
  6. determine how the page uses the result.
  7. Apply it manually in Chrome.
  8. Test the SolveCaptcha extension.
  9. Implement direct API automation if needed.
  10. Add explicit timeouts and retry limits.
  11. Preserve the browser session.
  12. Monitor whether the website accepted the result.

This sequence is easier to debug than starting with full automation.

Which method should you choose?

Choose Postman when:

  • you are testing the API for the first time;
  • you need to inspect request and response fields;
  • you are debugging a site key or page URL;
  • you need only one solution;
  • you do not want to write code yet.

Choose the Chrome extension when:

  • you want the captcha solved inside the browser;
  • the workflow is interactive;
  • minimal coding is preferred;
  • the extension supports the detected provider;
  • you need manual or semi-automatic solving.

Choose direct API integration when:

  • the workflow must be fully automated;
  • you need custom error handling;
  • you process several sessions;
  • you need proxy control;
  • you need provider-specific parameters;
  • you need reliable logging and monitoring.

Choose Puppeteer or Selenium when:

  • the page requires JavaScript;
  • the captcha is connected to browser state;
  • the token must be applied to a callback;
  • the protected workflow contains several interactive steps;
  • the final request cannot be reproduced safely with a basic HTTP client.

Pre-launch checklist

Before deploying the integration, confirm:

  • [ ] The website is within the authorized scope.
  • [ ] The captcha provider was identified correctly.
  • [ ] The current public parameters were extracted.
  • [ ] The complete page URL is correct.
  • [ ] The correct SolveCaptcha method is used.
  • [ ] The API key is stored securely.
  • [ ] Task creation uses in.php.
  • [ ] Result retrieval uses res.php.
  • [ ] The task ID is read from request.
  • [ ] Polling uses five-second intervals.
  • [ ] The result format matches the captcha provider.
  • [ ] The token or answer is applied to the correct location.
  • [ ] Required callbacks are called.
  • [ ] The browser session remains unchanged.
  • [ ] Automatic retries have a fixed limit.
  • [ ] The final website response is validated.

Frequently asked questions

Can SolveCaptcha work directly in Chrome?

Yes.

Use the SolveCaptcha browser extension for interactive Chrome workflows or connect the API to Selenium or Puppeteer.

Can I test SolveCaptcha without writing code?

Yes.

Use Postman to submit the task and retrieve the result.

Which endpoint creates a task?

Use:

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

Which endpoint retrieves the result?

Use:

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

Which method is used for reCAPTCHA v2?

Use:

method=userrecaptcha

Where can I find the reCAPTCHA site key?

Look for:

data-sitekey

or the k parameter in the reCAPTCHA iframe URL.

Which API parameter receives the site key?

Use:

googlekey

Where is the task ID returned?

With json=1, the task ID is returned in:

request

Where is the completed token returned?

The completed token is also returned in:

request

During task creation, request contains the task ID. During result retrieval, it contains the final solution.

How often should I poll?

For reCAPTCHA, wait approximately 15–20 seconds before the first result request.

Then retry every five seconds while the API returns:

CAPCHA_NOT_READY

Where should I insert a reCAPTCHA token?

The standard field is:

g-recaptcha-response

Some pages also require a callback or submit the token through a custom request field.

Does every captcha use g-recaptcha-response?

No.

That field is specific to reCAPTCHA integrations.

Is a proxy required?

Not for every captcha type.

Some providers or workflows require a proxy, while others make it optional.

Can one token be reused?

No.

Treat captcha tokens as short-lived and single-use.

Does the extension work on every website?

No browser extension can guarantee compatibility with every custom implementation.

Use direct API integration when the page requires custom parameters or result handling.

Should I make the hidden token field visible?

No.

Update its value directly. Changing its CSS is unnecessary.

Can I use the extension with Puppeteer?

Yes.

Launch Chrome with the unpacked extension and a dedicated browser profile.

Conclusion

There are three practical ways to bypass captcha in Google Chrome with SolveCaptcha:

  1. Use Postman to test API requests manually.
  2. Use the SolveCaptcha browser extension for interactive solving.
  3. Connect directly to the API for complete automation.

The correct production workflow is:

Identify the captcha
→ extract current parameters
→ send them to in.php
→ save the task ID
→ poll res.php
→ retrieve the result
→ apply it through the expected field, callback, cookie, or request
→ validate the website response

Start with Postman when learning the API.

Use the extension when you want a low-code Chrome workflow.

Use Selenium, Puppeteer, or direct HTTP integration when you need precise control, repeatable execution, and provider-specific error handling.

Use the SolveCaptcha API documentation to verify the current parameters for each captcha type before deploying the integration.