Captcha types
reCAPTCHA v2#
Types RecaptchaV2TaskProxyless and RecaptchaV2Task.
| Parameter | Required | Type | Description |
|---|---|---|---|
websiteURL |
yes | string | Full URL of the page where the captcha is located |
websiteKey |
yes | string | Value of the data-sitekey attribute of the reCAPTCHA widget |
isInvisible |
no | bool | true for invisible reCAPTCHA. Default is false |
recaptchaDataSValue |
no | string | Value of the data-s parameter, found on some Google pages (Search, YouTube) |
userAgent |
no | string | User-Agent under which the captcha is solved. It is advisable to pass the same one your bot uses |
cookies |
no | string | Cookies in the format name1=value1; name2=value2, if the session is important for solving |
enterprisePayload |
no | object | Additional data for reCAPTCHA v2 Enterprise, if enterprise markup is used |
Only for RecaptchaV2Task (solving via your proxy), additionally:
| Parameter | Required | Type | Description |
|---|---|---|---|
proxyType |
yes | string | http, socks4, or socks5 |
proxyAddress |
yes | string | Proxy IP address |
proxyPort |
yes | int | Proxy port |
proxyLogin |
no | string | Login for proxy authorization |
proxyPassword |
no | string | Password for proxy authorization |
Task object examples
// RecaptchaV2TaskProxyless
{
"type": "RecaptchaV2TaskProxyless",
"websiteURL": "https://example.com/login",
"websiteKey": "6Le-xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"isInvisible": false
}
// RecaptchaV2Task (your proxy)
{
"type": "RecaptchaV2Task",
"websiteURL": "https://example.com/login",
"websiteKey": "6Le-xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"proxyType": "http",
"proxyAddress": "1.2.3.4",
"proxyPort": 8080,
"proxyLogin": "user",
"proxyPassword": "password",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ..."
}
getTaskResult response example
While the task is processing:
{
"errorId": 0,
"status": "processing"
}
Once solved:
{
"errorId": 0,
"status": "ready",
"solution": {
"gRecaptchaResponse": "03AGdBq..."
}
}
You need to pass the solution.gRecaptchaResponse value to the reCAPTCHA widget or the g-recaptcha-response form parameter.
reCAPTCHA v3#
Type RecaptchaV3TaskProxyless. A proxy is not required for v3. Tasks are solved from the service IP addresses.
| Parameter | Required | Type | Description |
|---|---|---|---|
websiteURL |
yes | string | Full URL of the page with the captcha |
websiteKey |
yes | string | Site key of the reCAPTCHA v3 widget |
minScore |
yes | float | Minimum acceptable token score, for example 0.3, 0.7, or 0.9. The higher the value, the harder and longer the task takes to solve |
pageAction |
no | string | Value of the action parameter that the site sets when calling grecaptcha.execute(). If known, pass it. This increases the chance of the site accepting the token |
isEnterprise |
no | bool | true if the site uses reCAPTCHA v3 Enterprise |
apiDomain |
no | string | Domain from which the reCAPTCHA script is loaded (www.google.com or www.recaptcha.net), if the site uses a non-standard domain |
Task object example
// RecaptchaV3TaskProxyless
{
"type": "RecaptchaV3TaskProxyless",
"websiteURL": "https://example.com/login",
"websiteKey": "6Le-xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"minScore": 0.3,
"pageAction": "login"
}
getTaskResult response example
While the task is processing:
{
"errorId": 0,
"status": "processing"
}
Once solved:
{
"errorId": 0,
"status": "ready",
"solution": {
"gRecaptchaResponse": "03AGdBq..."
}
}
You use the received token (solution.gRecaptchaResponse) just like a regular reCAPTCHA v3 token.
Finding the reCAPTCHA sitekey and callback function on the page#
If there are multiple reCAPTCHA widgets on the page or the callback is not directly visible in the markup, you can find the sitekey and callback function via the ___grecaptcha_cfg object, where Google stores the configuration of all rendered widgets. Run the following code in the developer console or embed it in your automation script. It will return an array with all found reCAPTCHA clients (both v2 and v3) along with their sitekey, pageurl, and callback reference.
function findRecaptchaClients() {
// eslint-disable-next-line camelcase
if (typeof (___grecaptcha_cfg) !== 'undefined') {
// eslint-disable-next-line camelcase, no-undef
return Object.entries(___grecaptcha_cfg.clients).map(([cid, client]) => {
const data = { id: cid, version: cid >= 10000 ? 'V3' : 'V2' };
const objects = Object.entries(client).filter(([_, value]) => value && typeof value === 'object');
objects.forEach(([toplevelKey, toplevel]) => {
const found = Object.entries(toplevel).find(([_, value]) => (
value && typeof value === 'object' && 'sitekey' in value && 'size' in value
));
if (typeof toplevel === 'object' && toplevel instanceof HTMLElement && toplevel['tagName'] === 'DIV'){
data.pageurl = toplevel.baseURI;
}
if (found) {
const [sublevelKey, sublevel] = found;
data.sitekey = sublevel.sitekey;
const callbackKey = data.version === 'V2' ? 'callback' : 'promise-callback';
const callback = sublevel[callbackKey];
if (!callback) {
data.callback = null;
data.function = null;
} else {
data.function = callback;
const keys = [cid, toplevelKey, sublevelKey, callbackKey].map((key) => `['${key}']`).join('');
data.callback = `___grecaptcha_cfg.clients${keys}`;
}
}
});
return data;
});
}
return [];
}
Usage:
let res = findRecaptchaClients()
console.log(res)
For each found client, data.version will indicate whether it is v2 or v3. data.sitekey is the value for the websiteKey field in the createTask request. data.callback is the path to the callback function that needs to be executed with the token after receiving the solution (see "How to use the received token" below).
Cloudflare Turnstile#
Types TurnstileTaskProxyless and TurnstileTask.
| Parameter | Required | Type | Description |
|---|---|---|---|
websiteURL |
yes | string | Full URL of the page where the Turnstile widget is located |
websiteKey |
yes | string | Value of the data-sitekey attribute of the Turnstile widget |
action |
no | string | Value of the data-action attribute, if set on the site |
cData |
no | string | Value of the data-cdata attribute (custom payload), if the site uses it |
pageData |
no | string | Value of the chlPageData parameter for more complex Turnstile checks |
userAgent |
no | string | User-Agent under which the token will be solved and subsequently used. The token is tied to the User-Agent, so it must be passed by the same browser or bot that solved it |
Only for TurnstileTask (solving via your proxy), additionally:
| Parameter | Required | Type | Description |
|---|---|---|---|
proxyType |
yes | string | http, socks4, or socks5 |
proxyAddress |
yes | string | Proxy IP address |
proxyPort |
yes | int | Proxy port |
proxyLogin |
no | string | Login for proxy authorization |
proxyPassword |
no | string | Password for proxy authorization |
Task object examples
// TurnstileTaskProxyless
{
"type": "TurnstileTaskProxyless",
"websiteURL": "https://example.com/login",
"websiteKey": "0x4AAAAAAAxxxxxxxxxxxxxxxx"
}
// TurnstileTask (your proxy)
{
"type": "TurnstileTask",
"websiteURL": "https://example.com/login",
"websiteKey": "0x4AAAAAAAxxxxxxxxxxxxxxxx",
"proxyType": "http",
"proxyAddress": "1.2.3.4",
"proxyPort": 8080
}
getTaskResult response example
While the task is processing:
{
"errorId": 0,
"status": "processing"
}
Once solved:
{
"errorId": 0,
"status": "ready",
"solution": {
"token": "0.zxcv..."
}
}
You need to pass the received token (solution.token) to the widget callback function or the cf-turnstile-response field, depending on how you integrate Turnstile on your site.
Complex case: Cloudflare Challenge page#
A separate and more complex situation is the Cloudflare Challenge page. Besides websiteKey, additional parameters like cData, chlPageData, and action may be passed to the widget. The token will not be accepted without them. In this case, you need to intercept the turnstile.render call to extract these values. You also need to intercept the callback function definition and pass your browser userAgent in the request.
To intercept the parameters, embed the following JavaScript on the page before the Cloudflare Turnstile widget itself loads:
const i = setInterval(()=>{
if (window.turnstile) {
clearInterval(i)
window.turnstile.render = (a,b) => {
let p = {
type: "TurnstileTaskProxyless",
websiteKey: b.sitekey,
websiteURL: window.location.href,
data: b.cData,
pagedata: b.chlPageData,
action: b.action,
userAgent: navigator.userAgent
}
console.log(JSON.stringify(p))
window.tsCallback = b.callback
return 'foo'
}
}
},10)
The script replaces turnstile.render with a custom function. It intercepts the configuration object b (in which Cloudflare passes sitekey, cData, chlPageData, action, and callback). It logs the ready task object for createTask and saves a reference to the original callback function in window.tsCallback to call it later with the token.
An alternative approach is to intercept the network request to the api.js script and replace it with your own script. This script returns the required parameters and makes the callback function globally accessible (for example, via window).
When the solution is received from getTaskResult, you just need to execute the saved callback function by passing the token as an argument:
window.tsCallback('TOKEN_FROM_SOLUTION');