Invisible CAPTCHAs never show a challenge. They score the visitor in the background and only escalate to a puzzle when something looks wrong. Solving them requires understanding how the token is produced and consumed, not just answering a puzzle.
This advanced Learning Path article covers Turnstile, reCAPTCHA v3, and GeeTest v4.
How Invisible CAPTCHAs Work
Invisible CAPTCHAs run JavaScript that collects signals: mouse movements, keyboard timing, browser fingerprint, IP reputation, and page behavior. It produces a score or token. The site decides what to do:
- Good score: proceed silently.
- Suspicious: show an interactive challenge.
- Bad: block outright.
Your automation needs to obtain a valid token in the context of the real page.
Cloudflare Turnstile
Turnstile is type 12. It can run non-interactively, which means the solver returns a token without showing the user anything. The payload is minimal:
result = client.decode({
"sitekey": "SITE_KEY",
"pageurl": "https://example.com",
}, type=12, timeout=60)
if result:
token = result.text
# inject into <input name="cf-turnstile-response">
Turnstile tokens are single-use and validated against the page URL. Inject the token and submit the form on the same page that generated the challenge.
In Node.js:
const result = await client.decode({
sitekey: 'SITE_KEY',
pageurl: 'https://example.com',
}, 60, 12);
if (result) {
const token = result.text;
// inject into <input name="cf-turnstile-response">
}
And in C#:
string turnstileParams = "{\"sitekey\":\"SITE_KEY\",\"pageurl\":\"https://example.com\"}";
Captcha result = client.Decode(Client.DefaultTimeout,
new Hashtable { { "type", 12 }, { "turnstile_params", turnstileParams } });
if (result != null)
{
string token = result.Text;
// inject into <input name="cf-turnstile-response">
}
reCAPTCHA v3
reCAPTCHA v3 (type 5) is always running in the background. Sites typically require a token with a specific action name:
result = client.decode({
"googlekey": "SITE_KEY",
"pageurl": "https://example.com/checkout",
"action": "checkout",
}, type=5, timeout=60)
The action must match what the site's JavaScript sends. Inspect the site code to find the action string, then reuse it exactly.
In Node.js:
const result = await client.decode({
googlekey: 'SITE_KEY',
pageurl: 'https://example.com/checkout',
action: 'checkout',
}, 60, 5);
And in C#:
string recaptchaParams = "{\"googlekey\":\"SITE_KEY\",\"pageurl\":\"https://example.com/checkout\",\"action\":\"checkout\"}";
Captcha result = client.Decode(Client.DefaultTimeout,
new Hashtable { { "type", 5 }, { "token_params", recaptchaParams } });
GeeTest v4
GeeTest v4 (type 9) uses a captcha_id and an optional action, plus the page URL. v3 (type 8) instead uses gt and a challenge value. Because the parameters differ, always confirm which generation the site uses:
# v3
result = client.decode({
"gt": "GT_VALUE",
"challenge": "CHALLENGE_VALUE",
"pageurl": "https://example.com",
}, type=8, timeout=60)
# v4
result = client.decode({
"captcha_id": "CAPTCHA_ID",
"action": "login",
"pageurl": "https://example.com",
}, type=9, timeout=60)
In Node.js:
// v3
let result = await client.decode({
gt: 'GT_VALUE',
challenge: 'CHALLENGE_VALUE',
pageurl: 'https://example.com',
}, 60, 8);
// v4
result = await client.decode({
captcha_id: 'CAPTCHA_ID',
action: 'login',
pageurl: 'https://example.com',
}, 60, 9);
And in C#:
// v3
string geetestParams = "{\"gt\":\"GT_VALUE\",\"challenge\":\"CHALLENGE_VALUE\",\"pageurl\":\"https://example.com\"}";
Captcha result = client.Decode(Client.DefaultTimeout,
new Hashtable { { "type", 8 }, { "geetest_params", geetestParams } });
// v4
string geetestV4Params = "{\"captcha_id\":\"CAPTCHA_ID\",\"action\":\"login\",\"pageurl\":\"https://example.com\"}";
result = client.Decode(Client.DefaultTimeout,
new Hashtable { { "type", 9 }, { "geetest_params", geetestV4Params } });
Injecting Tokens Correctly
For all invisible CAPTCHAs the final step is identical: put the token into the hidden response field and let the page's own callback do the rest.
document.querySelector('[name=cf-turnstile-response]').value = token;
Some widgets listen for a JavaScript callback. After setting the field, invoke the callback with the token if the site registered one. Without this, the form submission may still be rejected.
Why Invisible CAPTCHAs Fail in Automation
- Wrong action name in reCAPTCHA v3.
- Token from the wrong page: the URL must match exactly, including protocol.
- Missing callback invocation after injection.
- IP mismatch between the solving session and the page session. Use a matching proxy.
Key Takeaways
- Invisible CAPTCHAs are type 5 (reCAPTCHA v3), 8 (GeeTest v3), 9 (GeeTest v4), and 12 (Turnstile).
- Match the action and page URL exactly.
- Inject the token into the hidden field and trigger the site callback.
- Keep the solving IP consistent with the browsing IP.
The final article in the Learning Path covers production-grade automation patterns and how to stay reliable at scale.

English
Spanish
Russian
Chinese
French
Hindi
Arabic
Bengali
Indonesian
Portuguese
com, 