How to bypass reCAPTCHA v2 Invisible with solver
reCAPTCHA v2 Invisible runs in the background and is usually triggered when a visitor clicks a button, submits a form, or performs another protected action.
Unlike the standard reCAPTCHA v2 checkbox, the invisible version does not initially display an “I’m not a robot” widget. However, it can still display an image challenge when Google decides that additional verification is required.
For authorized testing, browser automation, and data collection, the challenge can be processed through the SolveCaptcha API.
The integration follows this workflow:
Detect reCAPTCHA
→ extract the site key
→ identify invisible mode
→ submit the task
→ retrieve the token
→ update the response field
→ call the callback
→ continue the protected action
This guide explains how to implement the complete workflow with Python and Selenium.
Use these methods only on websites you own or are authorized to test and automate.
What is reCAPTCHA v2 Invisible?
reCAPTCHA v2 Invisible is a hidden variation of reCAPTCHA v2.
It is commonly attached to:
- login buttons;
- registration forms;
- payment forms;
- contact forms;
- account recovery actions;
- protected API requests.
A typical implementation looks like this:
<button
class="g-recaptcha"
data-sitekey="6LfD3PIbAAAAAJs_eEHvoOl75_83eXSqpPSRFJ_u"
data-callback="onSubmit"
data-size="invisible">
Continue
</button>
The captcha is triggered when the button is activated.
After verification, Google returns a token and the page usually:
- writes the token to
g-recaptcha-response; - calls the function specified in
data-callback; - submits the form or sends an API request.
Standard and Invisible reCAPTCHA v2 differences
| Feature | Standard reCAPTCHA v2 | Invisible reCAPTCHA v2 |
|---|---|---|
| Visible checkbox | Yes | No |
| Activation | Checkbox interaction | Page load or protected action |
| Image challenge | Possible | Possible |
| Response field | g-recaptcha-response |
g-recaptcha-response |
| Callback | Optional | Common |
| SolveCaptcha parameter | invisible=0 |
invisible=1 |
Invisible reCAPTCHA still uses the g-recaptcha-response field. It is incorrect to assume that the token is accepted only through a callback.
Some websites read the hidden field, while others wait for the callback or include the token in a custom XHR request.
SolveCaptcha API endpoints
Create a task through:
POST https://api.solvecaptcha.com/in.php
Retrieve the solution through:
GET https://api.solvecaptcha.com/res.php
For reCAPTCHA v2 Invisible, use:
method=userrecaptcha
invisible=1
Do not use unsupported request structures such as:
RecaptchaV2TaskProxyless
RecaptchaV2Task
createTask
getTaskResult
websiteKey
websiteURL
isInvisible
The documented SolveCaptcha parameters are:
method
googlekey
pageurl
invisible
Required parameters
| Parameter | Required | Description |
|---|---|---|
key |
Yes | Your SolveCaptcha API key |
method |
Yes | Must be userrecaptcha |
googlekey |
Yes | Public reCAPTCHA site key |
pageurl |
Yes | Full URL containing the captcha |
invisible |
Yes for this guide | Set to 1 |
json |
Recommended | Set to 1 for JSON responses |
Optional parameters include:
| Parameter | Description |
|---|---|
domain |
Domain used to load reCAPTCHA: google.com or recaptcha.net |
userAgent |
User-Agent used in the active browser session |
cookies |
Cookies associated with the current session |
data-s |
Additional value used by some Google services |
proxy |
Proxy in the supported SolveCaptcha format |
proxytype |
HTTP, HTTPS, SOCKS4, or SOCKS5 |
For most normal websites, the core parameters are sufficient:
key
method=userrecaptcha
googlekey
pageurl
invisible=1
json=1
How to identify Invisible reCAPTCHA
Invisible mode can be identified through several indicators.
data-size attribute
Look for:
data-size="invisible"
Example:
<div
class="g-recaptcha"
data-sitekey="SITE_KEY"
data-size="invisible"
data-callback="onCaptchaSolved">
</div>
Iframe URL
The reCAPTCHA iframe may contain:
size=invisible
Example:
https://www.google.com/recaptcha/api2/anchor?k=SITE_KEY&size=invisible
Hidden badge
Invisible reCAPTCHA may display a small reCAPTCHA badge in a page corner rather than a checkbox.
Protected action
The captcha may be triggered only after:
- clicking Submit;
- clicking Login;
- opening checkout;
- requesting a verification code;
- sending a form.
The captcha may not exist in the DOM until the protected action begins.
How to find the site key
The site key is a public identifier used by the website’s reCAPTCHA integration.
data-sitekey
The simplest location is:
data-sitekey="6LfD3PIbAAAAAJs_eEHvoOl75_83eXSqpPSRFJ_u"
Iframe k parameter
The site key may appear in:
k=SITE_KEY
Example:
https://www.google.com/recaptcha/api2/anchor?k=6LfD3PIbAAAAAJs_eEHvoOl75_83eXSqpPSRFJ_u
JavaScript configuration
The page may render the widget through JavaScript:
grecaptcha.render("captcha-container", {
sitekey:
"6LfD3PIbAAAAAJs_eEHvoOl75_83eXSqpPSRFJ_u",
size: "invisible",
callback: onSubmit
});
Extract the parameters in the browser console
The following script checks the most common HTML and iframe locations:
function findInvisibleRecaptcha() {
const result = {
siteKey: null,
callbackName: null,
invisible: false,
domain: "google.com"
};
const element = document.querySelector(
".g-recaptcha[data-sitekey],"
+ "[data-sitekey]"
);
if (element) {
result.siteKey =
element.getAttribute(
"data-sitekey"
);
result.callbackName =
element.getAttribute(
"data-callback"
);
result.invisible =
element.getAttribute(
"data-size"
) === "invisible";
}
const iframe = document.querySelector(
'iframe[src*="/recaptcha/api2/anchor"]'
);
if (iframe) {
try {
const url = new URL(iframe.src);
result.siteKey =
result.siteKey
|| url.searchParams.get("k");
result.invisible =
result.invisible
|| url.searchParams.get("size")
=== "invisible";
if (
url.hostname.includes(
"recaptcha.net"
)
) {
result.domain =
"recaptcha.net";
}
} catch {
// Ignore malformed iframe URLs.
}
}
return result;
}
console.log(
findInvisibleRecaptcha()
);
Example result:
{
"siteKey": "6LfD3PIbAAAAAJs_eEHvoOl75_83eXSqpPSRFJ_u",
"callbackName": "onSubmit",
"invisible": true,
"domain": "google.com"
}
How to find the callback
The callback is often declared through:
data-callback="onSubmit"
The expected call is then:
onSubmit(token);
It can also be defined during JavaScript rendering:
grecaptcha.render(
"captcha-container",
{
sitekey: "SITE_KEY",
size: "invisible",
callback: onSubmit
}
);
The callback may:
- submit a form;
- enable a button;
- send an XHR request;
- update application state;
- redirect the browser.
Do not call the callback before updating the response field unless the website’s implementation explicitly requires a different order.
Step 1: Submit the task
Example 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=6LfD3PIbAAAAAJs_eEHvoOl75_83eXSqpPSRFJ_u" \
--data-urlencode "pageurl=https://example.com/login" \
--data-urlencode "invisible=1" \
--data-urlencode "domain=google.com" \
--data-urlencode "json=1"
A successful response contains the captcha task ID:
{
"status": 1,
"request": "2122988149"
}
Save the request value.
Step 2: Wait for processing
Wait approximately:
15–20 seconds
before requesting the first result.
Do not create another task while the first one is still being processed.
Step 3: Retrieve the token
Send:
key=YOUR_API_KEY
action=get
id=TASK_ID
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 processing:
{
"status": 0,
"request": "CAPCHA_NOT_READY"
}
Wait five seconds and repeat the request with the same task ID.
When the task is ready:
{
"status": 1,
"request": "03AFcWeA5dCJ..."
}
The request value is the reCAPTCHA token.
Step 4: Insert the token
Update every g-recaptcha-response field on the page:
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 fields.length;
}
Call it with:
applyRecaptchaToken(
"TOKEN_FROM_SOLVECAPTCHA"
);
A page can contain more than one response field, so update all matching elements.
Step 5: Call the callback
For a globally available callback:
onSubmit(
"TOKEN_FROM_SOLVECAPTCHA"
);
For a nested callback such as:
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"
);
}
If the callback is not globally accessible, inspect the website’s normal workflow. The page may expect the token in a form field or network request instead.
Complete Python and Selenium example
Install dependencies:
python -m pip install requests selenium
Set the API key:
export SOLVECAPTCHA_API_KEY="YOUR_API_KEY"
Create solve_invisible_recaptcha.py:
#!/usr/bin/env python3
from __future__ import annotations
import os
import time
from dataclasses import dataclass
from typing import Any
from urllib.parse import parse_qs, urlparse
import requests
from selenium import webdriver
from selenium.common.exceptions import (
NoSuchElementException,
)
from selenium.webdriver.common.by import By
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 RecaptchaParameters:
site_key: str
callback_name: str | None
invisible: bool
domain: str
@dataclass(frozen=True)
class RecaptchaSolution:
task_id: str
token: str
def parse_api_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 extract_recaptcha_parameters(
driver: webdriver.Chrome,
) -> RecaptchaParameters:
elements = driver.find_elements(
By.CSS_SELECTOR,
".g-recaptcha[data-sitekey],"
"[data-sitekey]",
)
for element in elements:
site_key = (
element.get_attribute(
"data-sitekey"
)
or ""
).strip()
if not site_key:
continue
callback_name = (
element.get_attribute(
"data-callback"
)
or ""
).strip()
invisible = (
element.get_attribute(
"data-size"
)
== "invisible"
)
return RecaptchaParameters(
site_key=site_key,
callback_name=(
callback_name or None
),
invisible=invisible,
domain="google.com",
)
frames = driver.find_elements(
By.CSS_SELECTOR,
'iframe[src*="/recaptcha/api2/anchor"]',
)
for frame in frames:
src = (
frame.get_attribute("src")
or ""
)
if not src:
continue
parsed = urlparse(src)
query = parse_qs(parsed.query)
site_key = (
query.get("k", [""])[0]
).strip()
if not site_key:
continue
invisible = (
query.get(
"size",
[""],
)[0]
== "invisible"
)
domain = (
"recaptcha.net"
if "recaptcha.net"
in parsed.hostname or ""
else "google.com"
)
return RecaptchaParameters(
site_key=site_key,
callback_name=None,
invisible=invisible,
domain=domain,
)
raise RuntimeError(
"reCAPTCHA site key was not found"
)
def format_cookies(
driver: webdriver.Chrome,
) -> str:
cookies = driver.get_cookies()
return "".join(
f"{cookie['name']}:"
f"{cookie['value']};"
for cookie in cookies
if cookie.get("name")
)
class SolveCaptchaClient:
def __init__(
self,
api_key: str,
timeout: float = 30,
) -> None:
if not api_key:
raise ValueError(
"SolveCaptcha API key is required"
)
self.api_key = api_key
self.timeout = timeout
self.session = requests.Session()
def create_task(
self,
*,
site_key: str,
page_url: str,
domain: str = "google.com",
user_agent: str | None = None,
cookies: str | None = None,
data_s: str | None = None,
) -> str:
payload: dict[str, Any] = {
"key": self.api_key,
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url,
"invisible": 1,
"domain": domain,
"json": 1,
}
if user_agent:
payload["userAgent"] = (
user_agent
)
if cookies:
payload["cookies"] = cookies
if data_s:
payload["data-s"] = data_s
response = self.session.post(
CREATE_TASK_URL,
data=payload,
timeout=self.timeout,
)
result = parse_api_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(
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.timeout,
)
result = parse_api_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,
*,
site_key: str,
page_url: str,
domain: str = "google.com",
user_agent: str | None = None,
cookies: str | None = None,
data_s: str | None = None,
) -> RecaptchaSolution:
task_id = self.create_task(
site_key=site_key,
page_url=page_url,
domain=domain,
user_agent=user_agent,
cookies=cookies,
data_s=data_s,
)
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 RecaptchaSolution(
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 apply_token(
driver: webdriver.Chrome,
token: str,
) -> int:
return int(
driver.execute_script(
"""
const token = arguments[0];
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 fields.length;
""",
token,
)
)
def call_callback(
driver: webdriver.Chrome,
callback_name: str | None,
token: str,
) -> bool:
if not callback_name:
return False
return bool(
driver.execute_script(
"""
const path = arguments[0];
const token = arguments[1];
const callback = path
.split(".")
.reduce(
(object, key) =>
object?.[key],
window
);
if (
typeof callback
!== "function"
) {
return false;
}
callback(token);
return true;
""",
callback_name,
token,
)
)
def report_result(
*,
api_key: str,
task_id: str,
accepted: bool,
) -> None:
action = (
"reportgood"
if accepted
else "reportbad"
)
response = requests.get(
GET_RESULT_URL,
params={
"key": api_key,
"action": action,
"id": task_id,
"json": 1,
},
timeout=30,
)
parse_api_response(response)
def main() -> None:
api_key = os.environ.get(
"SOLVECAPTCHA_API_KEY",
"",
).strip()
target_url = os.environ.get(
"TARGET_URL",
"https://example.com/login",
)
if not api_key:
raise SystemExit(
"Set SOLVECAPTCHA_API_KEY"
)
options = webdriver.ChromeOptions()
driver = webdriver.Chrome(
options=options
)
client = SolveCaptchaClient(
api_key
)
try:
driver.get(target_url)
parameters = (
extract_recaptcha_parameters(
driver
)
)
if not parameters.invisible:
raise RuntimeError(
"The detected widget is not "
"configured as invisible"
)
user_agent = driver.execute_script(
"return navigator.userAgent"
)
cookies = format_cookies(
driver
)
solution = client.solve(
site_key=parameters.site_key,
page_url=driver.current_url,
domain=parameters.domain,
user_agent=user_agent,
cookies=cookies or None,
)
fields_updated = apply_token(
driver,
solution.token,
)
callback_called = call_callback(
driver,
parameters.callback_name,
solution.token,
)
print(
"Task ID:",
solution.task_id,
)
print(
"Response fields updated:",
fields_updated,
)
print(
"Callback called:",
callback_called,
)
/*
* Continue the authorized page
* workflow here.
*
* For example, click the original
* submit button or call
* form.requestSubmit().
*/
time.sleep(10)
finally:
driver.quit()
if __name__ == "__main__":
main()
The comment inside the Python example must use Python syntax. Replace this section:
/*
* Continue the authorized page
* workflow here.
*/
with:
# Continue the authorized page workflow here.
# For example, click the original submit button
# or call the page's expected submission logic.
The corrected ending of main() is:
print(
"Callback called:",
callback_called,
)
# Continue the authorized page workflow.
# Do not submit an irreversible action
# without verifying the target form.
time.sleep(10)
finally:
driver.quit()
Shorter Python API example
When you already know the site key and callback, the API integration can be reduced to:
import os
import time
import requests
API_KEY = os.environ[
"SOLVECAPTCHA_API_KEY"
]
SITE_KEY = (
"6LfD3PIbAAAAAJs_"
"eEHvoOl75_83eXSqpPSRFJ_u"
)
PAGE_URL = (
"https://example.com/login"
)
create_response = requests.post(
"https://api.solvecaptcha.com/in.php",
data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": SITE_KEY,
"pageurl": PAGE_URL,
"invisible": 1,
"json": 1,
},
timeout=30,
).json()
if create_response.get("status") != 1:
raise RuntimeError(
create_response.get(
"request",
"Task creation failed",
)
)
task_id = str(
create_response["request"]
)
time.sleep(20)
while True:
result = requests.get(
"https://api.solvecaptcha.com/res.php",
params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
},
timeout=30,
).json()
if result.get("status") == 1:
token = result["request"]
break
if (
result.get("request")
!= "CAPCHA_NOT_READY"
):
raise RuntimeError(
result.get("request")
)
time.sleep(5)
print(token)
Submitting the form after applying the token
Do not immediately use:
form.submit();
The native submit() method skips the normal submit event and may bypass client-side validation.
Prefer:
form.requestSubmit();
Example:
driver.execute_script(
"""
const form =
document.querySelector(
"#login-form"
);
if (!form) {
throw new Error(
"Form was not found"
);
}
form.requestSubmit();
"""
)
Some pages do not use a traditional form. They may send the token through Fetch or XMLHttpRequest.
Inspect the normal request in DevTools to identify:
- the endpoint;
- HTTP method;
- request body;
- response-token field;
- callback behavior;
- additional required form values.
Working with dynamically loaded captcha
Invisible reCAPTCHA may not be present when the page first loads.
Wait for one of the following:
[data-sitekey]
iframe[src*="/recaptcha/api2/anchor"]
Selenium example:
from selenium.webdriver.support.ui import (
WebDriverWait,
)
from selenium.webdriver.support import (
expected_conditions as EC,
)
from selenium.webdriver.common.by import By
WebDriverWait(
driver,
20,
).until(
EC.presence_of_element_located(
(
By.CSS_SELECTOR,
"[data-sitekey],"
'iframe[src*="/recaptcha/api2/anchor"]',
)
)
)
When the widget appears only after clicking a button, perform the action first and then extract the parameters.
Working with data-s
Some Google services add a data-s value to the reCAPTCHA request.
It may appear in:
data-s="VALUE"
or inside the reCAPTCHA iframe URL.
When present, send it as:
data-s=VALUE
Example:
payload["data-s"] = data_s_value
Do not invent or reuse an old data-s value. Extract it from the current page or challenge.
Working with recaptcha.net
Some websites load reCAPTCHA from:
www.recaptcha.net
instead of:
www.google.com
In that case, send:
domain=recaptcha.net
For a standard Google integration:
domain=google.com
The parameter should match the domain used by the active page.
Working with cookies and User-Agent
The optional userAgent and cookies parameters can be passed when the captcha depends on the active browser session.
Get the browser User-Agent:
user_agent = driver.execute_script(
"return navigator.userAgent"
)
Format cookies for SolveCaptcha:
cookies = "".join(
f"{cookie['name']}:"
f"{cookie['value']};"
for cookie in driver.get_cookies()
)
Example task parameters:
payload = {
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": SITE_KEY,
"pageurl": PAGE_URL,
"invisible": 1,
"userAgent": user_agent,
"cookies": cookies,
"json": 1,
}
Do not include authentication cookies unless they are genuinely required for an authorized workflow.
Reporting accepted and rejected solutions
After using 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 website accepts the captcha;
- the form or protected request succeeds;
- no captcha validation error is returned.
Use reportbad only when the returned captcha solution itself is rejected.
Do not send reportbad when the failure was caused by:
- an incorrect site key;
- an incorrect page URL;
- a missing callback;
- an expired page;
- a refreshed widget;
- another invalid form field;
- an incorrect selector;
- application validation unrelated to captcha.
Common API errors
ERROR_WRONG_USER_KEY
The API key is invalid.
Copy the key again from the SolveCaptcha account settings.
ERROR_ZERO_BALANCE
The account balance is insufficient.
Add funds before submitting another task.
ERROR_CAPTCHA_UNSOLVABLE
The captcha could not be solved reliably.
Check:
googlekey;pageurl;invisible=1;- the loading domain;
- whether
data-sis required; - whether the page generated a new challenge.
CAPCHA_NOT_READY
The task is still processing.
Wait five seconds and request the result again using the same task ID.
Token rejected
Possible causes include:
- incorrect site key;
- incorrect page URL;
- token applied after the widget reset;
- missing callback;
- token inserted into the wrong field;
- changed browser session;
- missing
data-s; - application-specific verification requirements.
Common implementation mistakes
Using isInvisible instead of invisible
Incorrect:
isInvisible=true
Correct:
invisible=1
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
Use:
https://api.solvecaptcha.com/in.php
and:
https://api.solvecaptcha.com/res.php
Treating Invisible reCAPTCHA as reCAPTCHA v3
Invisible reCAPTCHA v2 and reCAPTCHA v3 are different systems.
For Invisible reCAPTCHA v2:
method=userrecaptcha
invisible=1
For reCAPTCHA v3:
method=userrecaptcha
version=v3
action=ACTION
Updating only the response field
Some pages also require the configured callback.
Calling only the callback
Some pages read the hidden response field during form submission.
Update the field first and then call the callback.
Reloading the page while waiting
Reloading can generate a new challenge and invalidate the pending result.
Reusing a token
Treat each token as challenge-specific and single-use.
Automatically submitting the wrong form
A page may contain multiple forms. Use a specific selector rather than:
document.querySelector("form")
Testing applications you control
For routine automated tests, avoid solving a live production captcha on every test run.
Use:
- Google test keys;
- mocked verification responses;
- staging-only captcha configuration;
- dedicated test accounts;
- approved allowlists;
- a limited number of production smoke tests.
This makes tests faster, more predictable, and less dependent on external services.
Use the real SolveCaptcha integration only when the complete captcha flow must be tested.
Frequently asked questions
Which method is used for reCAPTCHA v2 Invisible?
Use:
method=userrecaptcha
invisible=1
Which parameters are required?
Use:
key
method
googlekey
pageurl
invisible
Where can I find the site key?
Look for:
data-sitekey
or the k parameter in the reCAPTCHA iframe URL.
How do I confirm invisible mode?
Look for:
data-size="invisible"
or:
size=invisible
in the iframe URL.
Is the callback required?
Not always, but it is common. Inspect data-callback and the page’s normal submission process.
Is g-recaptcha-response still used?
Yes. Invisible reCAPTCHA commonly writes the token to g-recaptcha-response.
How long should I wait?
Wait approximately 15–20 seconds before the first result request. Poll every five seconds while the API returns CAPCHA_NOT_READY.
Where is the token returned?
With json=1, the completed token is returned in:
request
Should I pass cookies?
Only when they are required by the authorized browser workflow.
Should I pass the User-Agent?
It is optional. When used, it should match the active browser session.
Can the token be reused?
No. Treat it as specific to the current challenge and workflow.
Conclusion
Bypassing reCAPTCHA v2 Invisible with SolveCaptcha requires more than inserting a token into one hidden field.
The correct workflow is:
- Confirm that the page uses reCAPTCHA v2 Invisible.
- Extract the site key from
data-sitekeyor the iframe URL. - Find the callback name when one is configured.
- Submit
method=userrecaptcha. - Pass the site key as
googlekey. - Pass the complete page URL as
pageurl. - Set
invisible=1. - Include
domain,userAgent,cookies, ordata-sonly when required. - Wait approximately 15–20 seconds.
- Poll
res.phpevery five seconds. - Update all
g-recaptcha-responsefields. - Dispatch input and change events.
- Call the configured callback.
- Continue the page’s expected submission workflow.
- Report whether the solution was accepted.
Use the SolveCaptcha reCAPTCHA v2 Invisible documentation to verify the current parameters before deploying the integration.