Files

3.3 KiB

Native reCAPTCHA v3 via Chrome CDP

Conol.ai uses reCAPTCHA v3 (site key: 6Lc3wmAtAAAAAB9YBPXQtT9uGGsH3ul6LQBc5AUu). The captcha is domain-locked — external solvers (2Captcha, AntiCaptcha, CapSolver) do NOT work.

Solution: Chrome CDP Native Execution

The browser already has the reCAPTCHA script loaded. Execute grecaptcha.execute() directly in the page context.

Generic reCAPTCHA executor (playwright)

async def recaptcha(page, action: str) -> str:
    """Execute reCAPTCHA v3 and return token."""
    return await page.evaluate(
        """async ({siteKey, action}) => {
            // Ensure grecaptcha is loaded
            if (!window.grecaptcha) {
                await new Promise((resolve, reject) => {
                    const old = document.getElementById('eni-recaptcha');
                    if (old) old.remove();
                    const script = document.createElement('script');
                    script.id = 'eni-recaptcha';
                    script.src = `https://www.recaptcha.net/recaptcha/api.js?render=${encodeURIComponent(siteKey)}`;
                    script.onload = resolve;
                    script.onerror = () => reject(new Error('recaptcha load failed'));
                    document.head.appendChild(script);
                });
            }
            await new Promise((resolve) => window.grecaptcha.ready(resolve));
            return await window.grecaptcha.execute(siteKey, {action});
        }""",
        {"siteKey": SITE_KEY, "action": action},
    )

Usage in registration flow

# Step 1: Sign Up
signup_token = await recaptcha(page, "sign_up")
r = await json_fetch(page, "/api/invites/register", method="POST", 
    captcha=signup_token, body={...})

# Step 2: Send Verification Email
verify_token = await recaptcha(page, "send_verification_email")
r = await json_fetch(page, "/api/auth/send-verification-email", method="POST",
    captcha=verify_token, body={...})

# Step 3: Sign In
signin_token = await recaptcha(page, "sign_in")
r = await json_fetch(page, "/api/auth/sign-in/email", method="POST",
    captcha=signin_token, body={...})

JSON fetch helper (via page.evaluate)

async def json_fetch(page, path: str, *, method="GET", body=None, captcha=None):
    """Fetch API endpoint from page context (uses browser's cookies)."""
    return await page.evaluate(
        """async ({path, method, body, captcha}) => {
            const headers = {Accept: 'application/json'};
            if (body !== null) headers['Content-Type'] = 'application/json';
            if (captcha) headers['x-captcha-response'] = captcha;
            const r = await fetch(path, {method, headers, credentials: 'include',
                body: body === null ? undefined : JSON.stringify(body)});
            const text = await r.text();
            let data = null;
            try { data = JSON.parse(text); } catch (_) {}
            return {status: r.status, url: r.url, text: text.slice(0, 2000), data};
        }""",
        {"path": path, "method": method, "body": body, "captcha": captcha},
    )

Key Points

  • Captcha token is sent via x-captcha-response header (NOT in body)
  • Use page.evaluate to call browser APIs within the origin context
  • Always clear cookies/storage between registrations to avoid session conflicts
  • Increasing delays between accounts (8s + 3s per index) reduces HTTP 429 errors