# Cloudflare Turnstile Auto-Registration Patterns ## Core Problem: Turnstile IP Binding Cloudflare Turnstile binds the solved token to the **IP that solved the challenge**. The registration request MUST come from the same IP. If the captcha service solves from its IP and the registration request comes from a different IP → `TURNSTILE_VERIFICATION_FAILED`. ### Failure Signature ```json {"code":400,"message":"turnstile verification failed","reason":"TURNSTILE_VERIFICATION_FAILED"} ``` This is NOT a bad token, wrong sitekey, or wrong endpoint. It's always IP mismatch. ## Solution Matrix | Approach | Requires | Works? | Notes | |----------|----------|--------|-------| | `TurnstileTaskProxyless` + direct API | Captcha service only | ❌ | IP mismatch (captcha IP ≠ your IP) | | `TurnstileTask` + datacenter proxy | Proxy + captcha | ❌ | Cloudflare detects datacenter IPs | | `TurnstileTask` + residential proxy | Residential proxy + captcha | ✅ | Both solve & register through same residential IP | | Browser automation (Selenium/Playwright) | Local Chrome, no sandbox | ⚠️ | Turnstile iframe may not render if bot detected | | Browser + extracted token → API | Local Chrome + API | ✅ | Same IP for solve + request | ## Anti-Captcha API Patterns ### Proxyless (DON'T USE — IP mismatch) ```python # Anti-Captcha r = requests.post('https://api.anti-captcha.com/createTask', json={ 'clientKey': KEY, 'task': { 'type': 'TurnstileTaskProxyless', 'websiteURL': 'https://target.com/register', 'websiteKey': '0x4AAAAA...', } }) # Token will be bound to Anti-Captcha's IP → registration fails ``` ### With Proxy (USE THIS) ```python r = requests.post('https://api.anti-captcha.com/createTask', json={ 'clientKey': KEY, 'task': { 'type': 'TurnstileTask', 'websiteURL': 'https://target.com/register', 'websiteKey': '0x4AAAAA...', 'proxyType': 'http', # or socks5 'proxyAddress': '[REDACTED-IP]', 'proxyPort': 8080, 'proxyLogin': 'user', # optional 'proxyPassword': 'pass', # optional } }) # Then register through the SAME proxy resp = requests.post('https://target.com/api/register', json={...}, proxies={'http': 'http://user:pass@[REDACTED-IP]:8080', 'https': 'http://user:pass@[REDACTED-IP]:8080'}) ``` ## Proxy Requirements ### Residential proxies MANDATORY - Datacenter IPs (Alibaba Cloud, AWS, DigitalOcean, etc.) are detected and rejected - Cloudflare runs ASN checks — residential ISP IPs pass, cloud/hosting IPs fail - Free proxy lists are 99% datacenter → won't work ### ProxyShard Residential Format ``` host:port:username:password relay-eu.proxyshard.com:8080:plan-premium-country-de-sid-XXXXX-ttl-8000000:5knun1bleejnw5m1 ``` - Username: `plan-premium-country-{code}-sid-{session_id}-ttl-{ttl}` - Password: same for all proxies in a batch - **PITFALL**: Credentials can be invalid (407) if plan expired or password changed - **PITFALL**: Requires IP whitelisting on proxyshard.com dashboard ### Proxy Authentication Diagnostics ```bash # Test proxy with curl curl -v --connect-timeout 10 \ -x "host:port" \ -U "username:password" \ "https://httpbin.org/ip" # 407 = auth failed ("Invalid credentials" in Proxy-Authenticate header) # 200 = proxy works ``` ### Proxy URL Format for Python requests ```python proxy_url = f'http://{username}:{password}@{host}:{port}' proxies = {'http': proxy_url, 'https': proxy_url} ``` ## Browser Automation with Turnstile ### Selenium undetected-chromedriver **IMPORTANT**: `undetected-chromedriver` requires Python 3.11 (or 3.12). Python 3.14 removed `distutils.version.LooseVersion` which the library imports. Use: `C:/Users/User/AppData/Local/Python/Python311/python.exe`. ```python import undetected_chromedriver as uc from selenium_stealth import stealth options = uc.ChromeOptions() options.add_argument('--no-sandbox') options.add_argument('--disable-blink-features=AutomationControlled') driver = uc.Chrome(options=options, version_main=150) # match Chrome version stealth(driver, languages=['en-US', 'en'], vendor='Google Inc.', platform='Win32', webgl_vendor='Intel Inc.', renderer='Intel Iris OpenGL Engine', fix_hairline=True) # CDP evasions driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', { 'source': ''' Object.defineProperty(navigator, 'webdriver', {get: () => undefined}); Object.defineProperty(navigator, 'plugins', {get: () => [1,2,3,4,5]}); window.chrome = {runtime: {}}; ''' }) ``` ### Turnstile Iframe Detection **When undetected-chromedriver works**: Turnstile is NOT in an iframe — it renders inline. The token is in a hidden input: ```python # Simple extraction (undetected-chromedriver — Turnstile is inline, not iframe) token = [REDACTED] "return document.querySelector('[name=\"cf-turnstile-response\"]')?.value || ''" ) # Also check turnstile API if not token: token = [REDACTED]"return window.turnstile?.getResponse?.() || ''") ``` **When headless Chrome is used (DON'T — Turnstile blocks it)**: Turnstile is in an iframe: ```python # Check if Turnstile iframe loaded iframes = driver.find_elements(By.TAG_NAME, 'iframe') for f in iframes: src = f.get_attribute('src') or '' if 'challenges.cloudflare' in src: # Turnstile found — click the checkbox driver.switch_to.frame(f) checkbox = driver.find_element(By.CSS_SELECTOR, '#checkbox, [role=checkbox]') checkbox.click() driver.switch_to.default_content() ``` ### Forced Turnstile Render via JS ```python # If widget not in DOM, force-render via turnstile API result = driver.execute_script(''' return new Promise((resolve) => { var div = document.createElement('div'); document.body.prepend(div); turnstile.render(div, { sitekey: '0x4AAAAA...', callback: (token) => resolve({status: 'ok', token: token}), 'error-callback': () => resolve({status: 'error'}), 'timeout-callback': () => resolve({status: 'timeout'}) }); setTimeout(() => resolve({status: 'timeout'}), 30000); }); ''') # PITFALL: script timeout if Cloudflare detects bot → challenge never auto-solves ``` ### Chrome Version Matching ```python # Check Chrome version first # chrome://version/ → e.g. 150.0.7871.182 # Pass version_main to match: driver = uc.Chrome(options=options, version_main=150) ``` ## Registration API Pattern ### baaaai.com / Sub2API Example ```python # Sitekey from page JS: window.__APP_CONFIG__.turnstile_site_key # Or from