Requirements

Install everything:

pip install playwright playwright-captcha 2captcha-python python-dotenv
playwright install chromium

Set up your API key in a .env file:

TWO_CAPTCHA_API_KEY=your_api_key_here

How the API Solver Works

The 2Captcha service receives your captcha challenge (sitekey + page URL), solves it using real humans or AI, and returns a token. You inject that token into the page and submit the form. The whole process takes 10–30 seconds.

playwright-captcha handles all of this automatically — finding the sitekey, sending it to 2Captcha, injecting the response, and confirming success.


Solving reCAPTCHA v2

reCAPTCHA v2 is embedded in a container on the page. Find the selector of the reCAPTCHA container on your target page and pass it to the solver — in this example we use #g-recaptcha from the demo page.

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_recaptcha_v2():
    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 TwoCaptchaSolver(
            framework=framework,
            page=page,
            async_two_captcha_client=AsyncTwoCaptcha(TWO_CAPTCHA_API_KEY)
        ) as solver:
            await page.goto('https://2captcha.com/demo/recaptcha-v2')
            await asyncio.sleep(5)

            # Find the reCAPTCHA container
            recaptcha_container = page.locator('#g-recaptcha')
            await recaptcha_container.wait_for()

            # Solve it
            await solver.solve_captcha(
                page=page,
                captcha_container=recaptcha_container,
                captcha_type=CaptchaType.RECAPTCHA_V2,
            )

        # 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('reCAPTCHA v2 solved successfully!')
        except Exception as e:
            logging.error(f'Failed: {e}')

asyncio.run(solve_recaptcha_v2())

Solving reCAPTCHA v3

reCAPTCHA v3 is invisible — there’s no container to find. The library detects it from the page’s JavaScript and handles everything automatically.

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_recaptcha_v3():
    async with async_playwright() as playwright:
        browser = await playwright.chromium.launch(headless=True)
        page = await browser.new_page()

        framework = FrameworkType.PLAYWRIGHT

        # Create solver BEFORE navigating to the page
        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/recaptcha-v3')
            await asyncio.sleep(5)

            # v3 is invisible — pass the full page as container
            await solver.solve_captcha(
                page=page,
                captcha_container=page,
                captcha_type=CaptchaType.RECAPTCHA_V3,
            )

        # 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('reCAPTCHA v3 solved successfully!')
        except Exception as e:
            logging.error(f'Failed: {e}')

asyncio.run(solve_recaptcha_v3())

Using Stealth Browsers for Better Results

Standard Playwright is often detected by Google’s bot analysis. For higher success rates — especially with reCAPTCHA v3 which relies heavily on browser signals — use a stealth browser. Popular options include Camoufox, Patchright, AdsPower, Dolphin Anty, Multilogin, and GoLogin.

This guide covers Camoufox and Patchright since they’re free and integrate directly with Playwright.

Option A: Patchright

Patchright is a patched version of Playwright that removes headless 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", headless=True)
    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=True,
    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. The playwright-captcha package includes a built-in workaround — just add main_world_eval=True and the addon path as shown above.


Solver Configuration Options

solver = TwoCaptchaSolver(
    framework=framework,
    page=page,
    async_two_captcha_client=captcha_client,
    max_attempts=3,       # retry up to 3 times
    attempt_delay=10,     # wait 10 seconds between attempts
    sitekey='your_sitekey_here'  # optional: provide manually if auto-detection fails
)

v2 vs v3: Key Differences

reCAPTCHA v2reCAPTCHA v3
Visible to userYes (checkbox)No (invisible)
Image puzzleSometimesNever
How it’s solvedToken injectionScore-based token injection
Harder with standard PlaywrightYesVery much so
Recommended browserPatchright or CamoufoxCamoufox (score matters more)

Common Issues and Fixes

reCAPTCHA v3 score too low / keeps failing Switch to Camoufox — it spoofs browser fingerprints much better than standard Playwright, which directly affects the v3 score Google assigns.

Sitekey not detected automatically Pass it manually via sitekey='your_sitekey' in the solver constructor. Find it in the page source — look for data-sitekey in the reCAPTCHA widget HTML, or search for grecaptcha.execute in the page’s JavaScript for v3.

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.


Full Project on GitHub

The playwright-captcha library supports:

  • reCAPTCHA v2 and v3
  • Cloudflare Turnstile (widget + interstitial)
  • Multiple solving services (2Captcha, TenCaptcha, more coming)

Check it out and leave a star if it helped: github.com/techinz/playwright-captcha