Cloudflare is one of the most common anti-bot challenges you’ll run into when scraping or automating the web. Unlike reCAPTCHA, it doesn’t show an image puzzle — it silently analyzes browser signals and either passes you through or blocks you. In this guide you’ll learn exactly how to solve Cloudflare automatically using Python and Playwright — using a free click-based solver or the 2Captcha API.
What is Cloudflare?
Cloudflare is a CAPTCHA alternative that verifies users without making them solve a puzzle. It works by checking browser fingerprints, JavaScript signals, cookies, and behavioral patterns.
There are two types you’ll encounter:
- Turnstile Widget — embedded on a page, usually inside a form. You click a checkbox or it passes automatically.
- Cloudflare Interstitial — a full-page challenge that appears before you can access the site. You have to wait for it to resolve before the real page loads.
Both can be bypassed automatically — here’s how.
Requirements
- Python 3.8+
- Playwright installed
playwright-captchalibrary
Install everything:
pip install playwright playwright-captcha
playwright install chromium
Two ways to solve
There are two solving methods in this guide — pick the one that fits your use case:
Click-based solver (free) The browser clicks the Turnstile checkbox automatically, just like a human would. No external service needed. Works best with a stealth browser (Camoufox or Patchright) since standard Playwright is often detected and blocked. Fast, cheap, but less reliable.
API-based solver (2Captcha) Sends the challenge to an external service that solves it and returns a token. More reliable across all Cloudflare configurations, works even with standard Playwright, but costs money (~$3 per 1000 solves) and is slower (10–30 seconds per solve). Good for production scrapers where reliability matters more than cost.
If you’re just starting out — try the click-based solver first. Switch to API-based if you’re getting blocked.
Method 1: Click-Based Solver (No API Key)
The click-based solver works by using a stealthy browser that looks like a real human to Cloudflare’s detection systems. It clicks the captcha checkbox automatically.
Important: Standard Playwright is often detected by Cloudflare. For best results, use Camoufox, Patchright, or another anti-detect browser — these are stealth-patched browsers that spoof fingerprinting signals. The examples below show Camoufox and Patchright.
Solving Cloudflare Turnstile (Click)
import asyncio
import logging
from playwright.async_api import async_playwright
from playwright_captcha import CaptchaType, ClickSolver, FrameworkType
logging.basicConfig(level='INFO')
async def solve_turnstile():
async with async_playwright() as playwright:
browser = await playwright.chromium.launch(headless=False)
page = await browser.new_page()
framework = FrameworkType.PLAYWRIGHT
# Create solver BEFORE navigating to the page
async with ClickSolver(framework=framework, page=page) as solver:
await page.goto('https://2captcha.com/demo/cloudflare-turnstile')
await asyncio.sleep(5) # wait for page to load
# Find the Turnstile container
turnstile_container = page.locator('#cf-turnstile')
await turnstile_container.wait_for()
# Solve it
await solver.solve_captcha(
captcha_container=page,
captcha_type=CaptchaType.CLOUDFLARE_TURNSTILE
)
# Submit the form
submit_button = page.locator('//button[@data-action="demo_action"]')
await submit_button.wait_for()
await submit_button.click()
await asyncio.sleep(5)
try:
await page.locator('//p[text()="Captcha is passed successfully!"]').wait_for(timeout=10000)
logging.info('Captcha solved successfully!')
except Exception as e:
logging.error(f'Failed: {e}')
asyncio.run(solve_turnstile())
Solving Cloudflare Interstitial (Full-Page Challenge, Click)
import asyncio
import logging
from playwright.async_api import async_playwright
from playwright_captcha import CaptchaType, ClickSolver, FrameworkType
logging.basicConfig(level='INFO')
async def solve_interstitial():
async with async_playwright() as playwright:
browser = await playwright.chromium.launch(headless=False)
page = await browser.new_page()
framework = FrameworkType.PLAYWRIGHT
async with ClickSolver(framework=framework, page=page) as solver:
await page.goto('https://2captcha.com/demo/cloudflare-turnstile-challenge')
await asyncio.sleep(5)
await solver.solve_captcha(
captcha_container=page,
captcha_type=CaptchaType.CLOUDFLARE_INTERSTITIAL,
expected_content_selector="#root" # selector that appears after the challenge passes
)
await asyncio.sleep(5)
try:
await page.locator('//p[text()="Captcha is passed successfully!"]').wait_for(timeout=10000)
logging.info('Interstitial solved successfully!')
except Exception as e:
logging.error(f'Failed: {e}')
asyncio.run(solve_interstitial())
Method 2: API-Based Solver with 2Captcha
If the click-based approach isn’t reliable enough for your use case, you can use an external solving service like 2Captcha. The service uses real humans (or AI) to solve the challenge and returns a token you inject into the page.
First, set up your API key:
# .env file
TWO_CAPTCHA_API_KEY=your_api_key_here
Install the 2Captcha Python SDK:
pip install 2captcha-python python-dotenv
Solving Cloudflare Turnstile (2Captcha)
import asyncio
import logging
import os
from dotenv import load_dotenv
from playwright.async_api import async_playwright
from twocaptcha import AsyncTwoCaptcha
from playwright_captcha import CaptchaType, TwoCaptchaSolver, FrameworkType
logging.basicConfig(level='INFO')
load_dotenv()
TWO_CAPTCHA_API_KEY = os.getenv('TWO_CAPTCHA_API_KEY')
async def solve_turnstile_api():
async with async_playwright() as playwright:
browser = await playwright.chromium.launch(headless=False)
context = await browser.new_context()
page = await context.new_page()
framework = FrameworkType.PLAYWRIGHT
async with TwoCaptchaSolver(
framework=framework,
page=page,
async_two_captcha_client=AsyncTwoCaptcha(TWO_CAPTCHA_API_KEY)
) as solver:
await page.goto('https://2captcha.com/demo/cloudflare-turnstile')
await asyncio.sleep(5)
turnstile_container = page.locator('#cf-turnstile')
await turnstile_container.wait_for()
await solver.solve_captcha(
captcha_container=turnstile_container,
captcha_type=CaptchaType.CLOUDFLARE_TURNSTILE,
)
submit_button = page.locator('//button[@data-action="demo_action"]')
await submit_button.wait_for()
await submit_button.click()
await asyncio.sleep(5)
try:
await page.locator('//p[text()="Captcha is passed successfully!"]').wait_for(timeout=10000)
logging.info('Captcha solved successfully!')
except Exception as e:
logging.error(f'Failed: {e}')
asyncio.run(solve_turnstile_api())
Solving Cloudflare Interstitial (2Captcha)
import asyncio
import logging
import os
from dotenv import load_dotenv
from playwright.async_api import async_playwright
from twocaptcha import AsyncTwoCaptcha
from playwright_captcha import CaptchaType, TwoCaptchaSolver, FrameworkType
logging.basicConfig(level='INFO')
load_dotenv()
TWO_CAPTCHA_API_KEY = os.getenv('TWO_CAPTCHA_API_KEY')
async def solve_interstitial_api():
async with async_playwright() as playwright:
browser = await playwright.chromium.launch(headless=False)
context = await browser.new_context()
page = await context.new_page()
framework = FrameworkType.PLAYWRIGHT
async with TwoCaptchaSolver(
framework=framework,
page=page,
async_two_captcha_client=AsyncTwoCaptcha(TWO_CAPTCHA_API_KEY)
) as solver:
await page.goto(
'https://2captcha.com/demo/cloudflare-turnstile-challenge',
wait_until='domcontentloaded'
)
await asyncio.sleep(15) # interstitial needs more time to load
await solver.solve_captcha(
captcha_container=page,
captcha_type=CaptchaType.CLOUDFLARE_INTERSTITIAL,
)
await asyncio.sleep(5)
try:
await page.locator('//p[text()="Captcha is passed successfully!"]').wait_for(timeout=10000)
logging.info('Interstitial solved successfully!')
except Exception as e:
logging.error(f'Failed: {e}')
asyncio.run(solve_interstitial_api())
Using Stealth Browsers for Higher Success Rates
Standard Playwright leaks browser automation signals. For production use, switch to a stealth browser. Popular options include Camoufox, Patchright, AdsPower, Dolphin Anty, Multilogin, and GoLogin — any browser that spoofs fingerprinting signals will work with the click-based solver.
Option A: Patchright
Patchright is a patched version of Playwright that removes detection signals.
pip install patchright
patchright install chromium
from patchright.async_api import async_playwright
from playwright_captcha import FrameworkType
async with async_playwright() as playwright:
browser = await playwright.chromium.launch(channel="chrome")
context = await browser.new_context()
page = await context.new_page()
framework = FrameworkType.PATCHRIGHT
# ... rest of your code
Option B: Camoufox
Camoufox is a Firefox-based stealth browser with advanced fingerprinting spoofing.
pip install camoufox
camoufox fetch
from camoufox import AsyncCamoufox
from playwright_captcha.utils.camoufox_add_init_script.add_init_script import get_addon_path
from playwright_captcha import FrameworkType
import os
ADDON_PATH = get_addon_path()
async with AsyncCamoufox(
headless=False,
geoip=True,
humanize=True,
main_world_eval=True, # required for playwright-captcha
addons=[os.path.abspath(ADDON_PATH)] # required for playwright-captcha
) as browser:
context = await browser.new_context()
page = await context.new_page()
framework = FrameworkType.CAMOUFOX
# ... rest of your code
Note: Camoufox has a known issue with
add_init_script. Theplaywright-captchapackage includes a built-in workaround — just addmain_world_eval=Trueand the addon path as shown above.
Solver Configuration Options
You can customize both solvers:
# Click solver options
solver = ClickSolver(
framework=framework,
page=page,
max_attempts=5, # retry up to 5 times
attempt_delay=3 # wait 3 seconds between attempts
)
# API solver options
solver = TwoCaptchaSolver(
framework=framework,
page=page,
async_two_captcha_client=captcha_client,
max_attempts=3,
attempt_delay=10,
sitekey='your_sitekey_here' # optional: provide manually if auto-detection fails
)
Which Method Should You Use?
| Click Solver | 2Captcha API | |
|---|---|---|
| Cost | Free | ~$3 per 1000 solves |
| Speed | Fast (2-5s) | Slower (10-30s) |
| Requires stealth browser | Yes (recommended) | No |
| Reliability | High with Camoufox/Patchright | Very high |
| Works headless | Yes | Yes |
Use click-based if you want free, fast solving and are already using a stealth browser. Use 2Captcha if you need maximum reliability and don’t want to deal with stealth browser setup.
Common Issues and Fixes
Turnstile keeps failing with standard Playwright Switch to Patchright or Camoufox. Standard Playwright is detected by Cloudflare’s fingerprinting.
add_init_script error with Camoufox
Add main_world_eval=True and the addon path when creating the Camoufox instance. The playwright-captcha package handles the rest automatically.
Sitekey not detected automatically
Pass it manually via sitekey='your_sitekey' in the solver constructor. You can find it in the page source — look for data-sitekey in the Turnstile widget HTML.
Full Project on GitHub
The playwright-captcha library supports:
- Cloudflare Turnstile (widget + interstitial)
- reCAPTCHA v2 and v3
- Multiple solving services (2Captcha, TenCaptcha, more coming)
Check it out and leave a star if it helped: github.com/techinz/playwright-captcha