Captcha bypass tutorials

Was this helpful?

How to solve Cloudflare Turnstile on Leonardo AI

Gregory Fisher
Gregory Fisher

Technical engineer

Introduction

Leonardo AI is a popular artificial intelligence image generation platform. To protect account login and registration processes from automated scripts, the site uses Cloudflare Turnstile. This is an invisible or interactive captcha that evaluates user behavior and the browser environment.

In this guide, we will break down how to obtain the necessary parameters, solve the captcha via the 2Captcha API, and correctly inject the token into the Leonardo AI authorization page using proven injection methods.

Task parameters

To bypass Cloudflare Turnstile on Leonardo AI, the TurnstileTaskProxyless task type is used (or TurnstileTask if your own proxies are required).

json Copy
{
    "clientKey": "YOUR_API_KEY",
    "task": {
        "type": "TurnstileTaskProxyless",
        "websiteURL": "https://app.leonardo.ai/auth/login",
        "websiteKey": "0x4AAAAAAAjpS3rLKnsHyb79",
        "action": "email_continue"
    }
}

How to find parameters

websiteURL

This is the full address of the page where the captcha appears. In this case, it is the login page: https://app.leonardo.ai/auth/login

websiteKey (sitekey)

This is the public Cloudflare Turnstile key.

  1. Open the login page and press F12 (Developer Tools).
  2. Go to the Elements tab.
  3. Press Ctrl+F and type data-sitekey or cf-turnstile.
  4. Copy the attribute value. For Leonardo AI, it is 0x4AAAAAAAjpS3rLKnsHyb79.

action

Some Turnstile implementations use the action parameter to determine the context (e.g., login, registration, or continuing email input).

  1. On the Elements tab, find the captcha container (usually a div with the class cf-turnstile).
  2. Check for the presence of the data-action attribute.
  3. Alternatively, go to the Network tab, perform the action that triggers the captcha (e.g., enter an email and click Continue), and find the request to challenges.cloudflare.com. The action parameter will be specified in the request body (Payload). For Leonardo AI, when continuing login via email, this value is often email_continue.

Token injection (passing) methods

After receiving the token from the 2Captcha API, it must be correctly passed to the site. Depending on the site's architecture (especially if it is a React or Vue SPA), simple DOM manipulation might not be enough. Below are the main methods based on successful Turnstile bypass practices (including examples from VFS Global scripts).

1. Injection into hidden fields (DOM manipulation)

The most common method. Turnstile creates hidden fields that are submitted along with the form.

python Copy
# For Selenium / SeleniumBase
driver.execute_script("document.getElementsByName('cf-turnstile-response')[0].value = arguments[0];", token)
driver.execute_script(f"document.getElementById('g-recaptcha-response').innerHTML = '{token}';")
driver.execute_script(f"document.getElementById('g-recaptcha-response').value = '{token}';")

2. Calling the callback function

Modern frameworks often do not read the DOM directly but wait for a callback function to be triggered, which Turnstile registers upon initialization. If the site defines a callback, it needs to be called manually.

python Copy
# If you intercepted the callback function name (e.g., window.turnstileCallback)
driver.execute_script(f"window.turnstileCallback('{token}');")

# Or a universal search for the callback in the turnstile object (if globally available)
driver.execute_script(f"""
    if (typeof turnstile !== 'undefined' && typeof turnstile.execute === 'function') {{
        // Sometimes forced state update is required
    }}
    // Attempt to find and call the saved callback
    if (typeof window.tsCallback === 'function') {{
        window.tsCallback('{token}');
    }}
""")

3. Unlocking the submit button

Often, the form's submit button has a disabled attribute that is only removed after the callback successfully triggers. If you are injecting the token manually, you may need to force-unlock the button.

python Copy
# Find the button and remove the disabled attribute
el = driver.find_element(By.XPATH, "//button[@type='submit']")
driver.execute_script("arguments[0].removeAttribute('disabled')", el)

4. Verifying injection success

After injection, it is recommended to check if the Turnstile widget accepted the token by calling its built-in getResponse() method.

python Copy
resp = driver.execute_script("return turnstile.getResponse();")
print("turnstile.getResponse() response:", resp) # Should output your token, not null

Code examples

Python + requests (Getting the token)

This code sends a task to the API and returns the ready token.

python Copy
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))

from twocaptcha import TwoCaptcha

api_key = os.getenv('APIKEY_2CAPTCHA', 'YOUR_API_KEY')
solver = TwoCaptcha(api_key)

try:
    result = solver.turnstile(
        sitekey='0x4AAAAAAAjpS3rLKnsHyb79',
        url='https://app.leonardo.ai/auth/login',
        action='email_continue'
    )
    print(f"Token successfully received: {result['code']}")
    
except Exception as e:
    print(f"An error occurred: {e}")

Python + SeleniumBase (Automation with full injection cycle)

An adapted script using undetected-chromedriver via SeleniumBase to bypass basic detection and applying all the token injection methods described above.

python Copy
import time
import chromedriver_autoinstaller_fix
import requests
from seleniumbase import Driver
from selenium.webdriver.common.by import By

chromedriver_autoinstaller_fix.install()

agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
# Launch the driver with anti-detect settings
driver = Driver(uc=True, headless=False, proxy=False, agent=agent)

url = 'https://app.leonardo.ai/auth/login'
sitekey = "0x4AAAAAAAjpS3rLKnsHyb79"
my_key = "YOUR_2CAPTCHA_KEY"

try:
    # 1. Open the page with a delay to bypass initial Cloudflare checks
    driver.uc_open_with_reconnect(url, reconnect_time=20)
    time.sleep(5)
    
    # 2. Interact with the page to trigger the captcha (example for Leonardo AI)
    # Enter email and click the continue button
    # driver.find_element(By.ID, "email-input").send_keys("test@example.com")
    # driver.find_element(By.XPATH, "//button[contains(text(), 'Continue')]").click()
    time.sleep(3)
    
    # 3. Send the task for solving
    user_agent = driver.get_user_agent()
    data = {
        "key": my_key,
        "method": "turnstile",
        "sitekey": sitekey,
        "json": 1,
        "pageurl": url,
        "useragent": user_agent,
        "action": "email_continue"
    }
    
    response = requests.post("https://api.2captcha.com/in.php", data=data)
    print("Sent to the service:", response.text)
    task_id = response.json()["request"]
    
    # 4. Wait for the result
    time.sleep(15)
    while True:
        solu = requests.get(f"https://api.2captcha.com/res.php?key={my_key}&action=get&json=1&id={task_id}").json()
        if solu["request"] == "CAPCHA_NOT_READY":
            print("Waiting for solution...")
            time.sleep(10)
        elif "ERROR" in solu["request"]:
            print("Error:", solu["request"])
            driver.quit()
            exit(0)
        else:
            break
            
    token = solu["request"]
    print("Token received:", token)
    
    # 5. Token injection (Comprehensive approach)
    # Method 1: Hidden fields
    driver.execute_script("document.getElementsByName('cf-turnstile-response')[0].value = arguments[0];", token)
    driver.execute_script(f"document.getElementById('g-recaptcha-response').innerHTML = '{token}';")
    driver.execute_script(f"document.getElementById('g-recaptcha-response').value = '{token}';")
    
    # Method 2: Attempt to call callback (if defined)
    driver.execute_script(f"""
        if (typeof window.turnstileCallback === 'function') {{
            window.turnstileCallback('{token}');
        }}
    """)
    
    # Method 3: Unlock the submit button
    try:
        submit_btn = driver.find_element(By.XPATH, "//button[@type='submit']")
        driver.execute_script("arguments[0].removeAttribute('disabled')", submit_btn)
    except:
        pass
        
    time.sleep(2)
    
    # 6. Verify injection success
    resp = driver.execute_script("return turnstile.getResponse();")
    print("Checking turnstile.getResponse():", resp)
    print("Token successfully injected")
    
    time.sleep(10) # Pause for visual verification or further actions
    
except Exception as e:
    print(f"Error: {e}")
finally:
    driver.quit()

Solution accuracy reports

If the site rejected the received token, be sure to report it via the reportIncorrect method. This helps the service improve its algorithms and refunds your funds for the failed attempt. If the token successfully passed the verification, send reportCorrect.

You can submit a report via the API:

python Copy
import requests

API_KEY = "YOUR_API_KEY"
TASK_ID = "123456789" # Replace with the real task ID from the API response

# Report for an incorrect solution
requests.post(
    "https://api.2captcha.com/reportIncorrect",
    json={"clientKey": API_KEY, "taskId": TASK_ID}
)

# Report for a correct solution
requests.post(
    "https://api.2captcha.com/reportCorrect",
    json={"clientKey": API_KEY, "taskId": TASK_ID}
)

Detailed guide on submitting reports with examples for different languages: https://2captcha.com/h/how-to-submit-reports

Common errors and solutions

Error / Problem Cause Solution
ERROR_CAPTCHA_UNSOLVABLE IP address is blocked by Cloudflare or an incorrect action parameter was passed. Use the TurnstileTask task type with high-quality residential proxies. Ensure the action parameter exactly matches what the site expects.
Token received, but the site does not let you in Incorrect token injection or the token's lifespan has expired. Use a comprehensive injection approach: hidden fields + callback invocation + button unlocking. Verify the result via turnstile.getResponse().
Error finding elements The site has updated its layout or protection mechanisms. Check the current XPath or CSS selectors via DevTools. Increase the wait time or use explicit waits.
ERROR_WRONG_USER_KEY Invalid API key. Check that you are using the correct key from your 2Captcha dashboard.