Before you can solve a CAPTCHA with CaptchaAI, you need to know what type of CAPTCHA the page uses and extract the right parameters (sitekey, action, s value, etc.). The browser console is the fastest way to find all of this.
Identifying the CAPTCHA type
Open DevTools (F12) and run this snippet in the Console tab:
(function detectCaptcha() {
const results = [];
// reCAPTCHA v2 / v2 Invisible
const recaptchaWidgets = document.querySelectorAll('.g-recaptcha');
recaptchaWidgets.forEach((el, i) => {
results.push({
type: 'reCAPTCHA v2',
sitekey: el.getAttribute('data-sitekey'),
size: el.getAttribute('data-size') || 'normal',
callback: el.getAttribute('data-callback') || 'none'
});
});
// reCAPTCHA v3 (loaded via script)
const recaptchaScripts = document.querySelectorAll(
'script[src*="recaptcha/api.js"], script[src*="recaptcha/enterprise.js"]'
);
recaptchaScripts.forEach(script => {
const renderMatch = script.src.match(/render=([A-Za-z0-9_-]+)/);
if (renderMatch && renderMatch[1] !== 'explicit') {
results.push({
type: 'reCAPTCHA v3',
sitekey: renderMatch[1],
enterprise: script.src.includes('enterprise')
});
}
});
// Cloudflare Turnstile
const turnstileWidgets = document.querySelectorAll('.cf-turnstile');
turnstileWidgets.forEach(el => {
results.push({
type: 'Cloudflare Turnstile',
sitekey: el.getAttribute('data-sitekey'),
action: el.getAttribute('data-action') || 'none'
});
});
// GeeTest
if (typeof initGeetest !== 'undefined' || document.querySelector('.geetest_holder')) {
results.push({
type: 'GeeTest',
note: 'Check network tab for gt and challenge parameters'
});
}
// hCaptcha
const hcaptchaWidgets = document.querySelectorAll('.h-captcha');
hcaptchaWidgets.forEach(el => {
results.push({
type: 'hCaptcha',
sitekey: el.getAttribute('data-sitekey')
});
});
if (results.length === 0) {
console.log('No CAPTCHA widgets detected in the DOM.');
console.log('Check: iframes, lazy-loaded scripts, or network requests.');
} else {
console.table(results);
}
return results;
})();
Expected output (example):
┌─────────┬──────────────┬──────────────────────┬──────────┐
│ (index) │ type │ sitekey │ size │
├─────────┼──────────────┼──────────────────────┼──────────┤
│ 0 │ 'reCAPTCHA v2' │ '6Le-SITEKEY-abc' │ 'normal' │
└─────────┴──────────────┴──────────────────────┴──────────┘
Extracting reCAPTCHA v2 parameters
What CaptchaAI needs:
| Parameter | Where to find it |
|---|---|
googlekey (sitekey) |
data-sitekey attribute on .g-recaptcha |
pageurl |
Current page URL — window.location.href |
data-s (optional) |
data-s attribute on .g-recaptcha (Google-owned sites) |
invisible |
data-size="invisible" on the widget |
Console command:
document.querySelectorAll('.g-recaptcha').forEach((el, i) => {
console.log(`Widget ${i}:`, {
sitekey: el.getAttribute('data-sitekey'),
size: el.getAttribute('data-size'),
callback: el.getAttribute('data-callback'),
's_value': el.getAttribute('data-s'),
pageurl: window.location.href
});
});
Extracting reCAPTCHA v3 parameters
reCAPTCHA v3 has no visible widget. Find the sitekey from the script tag or by intercepting grecaptcha.execute:
// Method 1: Script tag
document.querySelectorAll('script[src*="recaptcha"]').forEach(s => {
const match = s.src.match(/render=([A-Za-z0-9_-]+)/);
if (match) console.log('v3 sitekey:', match[1]);
});
// Method 2: Intercept execute calls (run BEFORE page load in DevTools Sources)
const origExecute = grecaptcha.execute;
grecaptcha.execute = function(sitekey, opts) {
console.log('v3 execute intercepted:', { sitekey, action: opts?.action });
return origExecute.apply(this, arguments);
};
What CaptchaAI needs for v3: googlekey, pageurl, action (from opts.action), and min_score (optional).
Extracting Cloudflare Turnstile parameters
document.querySelectorAll('.cf-turnstile').forEach((el, i) => {
console.log(`Turnstile ${i}:`, {
sitekey: el.getAttribute('data-sitekey'),
action: el.getAttribute('data-action'),
cData: el.getAttribute('data-cdata'),
pageurl: window.location.href
});
});
If the widget is rendered via JavaScript (no .cf-turnstile div), search the page source:
// Search all script contents for turnstile.render calls
document.querySelectorAll('script:not([src])').forEach(s => {
if (s.textContent.includes('turnstile.render')) {
const match = s.textContent.match(/sitekey\s*:\s*['"]([^'"]+)['"]/);
if (match) console.log('Turnstile sitekey:', match[1]);
}
});
Extracting GeeTest parameters
GeeTest requires gt, challenge, and optionally api_server. These come from a network request, not the DOM.
- Open the Network tab in DevTools
- Filter by
registerorcaptcha - Find the JSON response containing
gtandchallenge
// Quick check for GeeTest on the page
if (document.querySelector('.geetest_holder')) {
console.log('GeeTest detected. Check Network tab for:');
console.log(' - gt (32-char hex string)');
console.log(' - challenge (32-char hex string)');
console.log(' - api_server (optional, e.g. api.geetest.com)');
}
Extracting sitekeys from iframes
When the CAPTCHA is inside an iframe, check the iframe's src:
document.querySelectorAll('iframe').forEach((iframe, i) => {
const src = iframe.src || '';
if (src.includes('recaptcha')) {
const match = src.match(/k=([A-Za-z0-9_-]+)/);
console.log(`iframe ${i} — reCAPTCHA sitekey:`, match?.[1]);
}
if (src.includes('turnstile') || src.includes('challenges.cloudflare')) {
console.log(`iframe ${i} — Cloudflare challenge:`, src);
}
});
Checking for lazy-loaded CAPTCHAs
Some CAPTCHAs load only after user interaction (button click, scroll). Use a MutationObserver to catch them:
const observer = new MutationObserver(mutations => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (node.nodeType !== 1) continue;
if (node.matches?.('.g-recaptcha, .cf-turnstile, .h-captcha')) {
console.log('CAPTCHA widget added:', node.className,
node.getAttribute('data-sitekey'));
}
if (node.tagName === 'IFRAME' && node.src?.includes('recaptcha')) {
console.log('reCAPTCHA iframe added:', node.src);
}
}
}
});
observer.observe(document.body, { childList: true, subtree: true });
console.log('Watching for dynamically loaded CAPTCHAs...');
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
| Detection script finds nothing | CAPTCHA inside iframe | Check iframe src attributes or switch to iframe context |
| reCAPTCHA v3 sitekey not found | Loaded via dynamic script | Use the grecaptcha.execute intercept method |
data-sitekey is empty |
Rendered via JavaScript API | Search page source for grecaptcha.render or turnstile.render calls |
| GeeTest parameters missing | Loaded via API call | Use Network tab, filter for register endpoints |
FAQ
Can I extract parameters without opening the browser?
You can fetch the page source with curl or requests and search for sitekeys with regex. But JavaScript-rendered CAPTCHAs require a real browser or headless browser to detect.
What if the page uses reCAPTCHA Enterprise?
Enterprise uses the same sitekey extraction methods. The script URL will contain enterprise.js instead of api.js. Pass the enterprise flag when submitting to CaptchaAI.
Use the parameters you find to solve CAPTCHAs with CaptchaAI
Get your API key at captchaai.com.
Discussions (0)
Join the conversation
Sign in to share your opinion.
Sign InNo comments yet.