Playwright provides reliable browser automation across Chromium, Firefox, and WebKit. When target pages serve CAPTCHAs, CaptchaAI solves them server-side while Playwright handles the browser interaction.
Requirements
| Requirement | Details |
|---|---|
| Python | pip install playwright requests then playwright install |
| Node.js | npm install playwright axios |
| CaptchaAI API key | From captchaai.com |
Python: Playwright + CaptchaAI
Setup
from playwright.sync_api import sync_playwright
import requests
import time
API_KEY = "YOUR_API_KEY"
def solve_recaptcha(site_key, page_url):
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url
})
if not resp.text.startswith("OK|"):
raise Exception(resp.text)
task_id = resp.text.split("|")[1]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id
})
if result.text == "CAPCHA_NOT_READY": continue
if result.text.startswith("OK|"): return result.text.split("|")[1]
raise Exception(result.text)
raise TimeoutError()
Full Example
def login_with_captcha(url, username, password):
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
context = browser.new_context(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
)
page = context.new_page()
page.goto(url)
# Fill login form
page.fill("#username", username)
page.fill("#password", password)
# Check for reCAPTCHA
recaptcha = page.query_selector(".g-recaptcha")
if recaptcha:
site_key = recaptcha.get_attribute("data-sitekey")
print(f"Solving reCAPTCHA: {site_key}")
token = solve_recaptcha(site_key, page.url)
# Inject token
page.evaluate(f"""
document.getElementById('g-recaptcha-response').innerHTML = '{token}';
document.getElementById('g-recaptcha-response').style.display = '';
""")
# Submit
page.click('button[type="submit"]')
page.wait_for_load_state("networkidle")
print(f"Current URL: {page.url}")
content = page.content()
browser.close()
return content
result = login_with_captcha(
"https://example.com/login",
"user@example.com",
"password123"
)
Async Version
from playwright.async_api import async_playwright
import aiohttp
import asyncio
async def solve_recaptcha_async(site_key, page_url):
async with aiohttp.ClientSession() as session:
params = {
"key": API_KEY, "method": "userrecaptcha",
"googlekey": site_key, "pageurl": page_url
}
async with session.get("https://ocr.captchaai.com/in.php", params=params) as resp:
text = await resp.text()
task_id = text.split("|")[1]
for _ in range(60):
await asyncio.sleep(5)
params = {"key": API_KEY, "action": "get", "id": task_id}
async with session.get("https://ocr.captchaai.com/res.php", params=params) as resp:
text = await resp.text()
if text == "CAPCHA_NOT_READY": continue
if text.startswith("OK|"): return text.split("|")[1]
raise Exception(text)
raise TimeoutError()
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
await page.goto("https://example.com/form")
site_key = await page.get_attribute(".g-recaptcha", "data-sitekey")
token = await solve_recaptcha_async(site_key, page.url)
await page.evaluate(f"document.getElementById('g-recaptcha-response').innerHTML = '{token}'")
await page.click('button[type="submit"]')
await browser.close()
asyncio.run(main())
Node.js: Playwright + CaptchaAI
const { chromium } = require("playwright");
const axios = require("axios");
const API_KEY = "YOUR_API_KEY";
async function solveRecaptcha(siteKey, pageUrl) {
const submit = await axios.get("https://ocr.captchaai.com/in.php", {
params: {
key: API_KEY,
method: "userrecaptcha",
googlekey: siteKey,
pageurl: pageUrl,
},
});
const taskId = submit.data.split("|")[1];
while (true) {
await new Promise((r) => setTimeout(r, 5000));
const result = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "get", id: taskId },
});
if (result.data === "CAPCHA_NOT_READY") continue;
if (result.data.startsWith("OK|")) return result.data.split("|")[1];
throw new Error(result.data);
}
}
(async () => {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
await page.goto("https://example.com/login");
// Fill form
await page.fill("#username", "user@example.com");
await page.fill("#password", "password123");
// Solve CAPTCHA
const siteKey = await page.getAttribute(".g-recaptcha", "data-sitekey");
if (siteKey) {
const token = await solveRecaptcha(siteKey, page.url());
await page.evaluate(
(t) => (document.getElementById("g-recaptcha-response").innerHTML = t),
token
);
}
// Submit
await page.click('button[type="submit"]');
await page.waitForLoadState("networkidle");
console.log("Logged in:", page.url());
await browser.close();
})();
Handling Cloudflare Turnstile
# Detect Turnstile
turnstile = page.query_selector(".cf-turnstile")
if turnstile:
site_key = turnstile.get_attribute("data-sitekey")
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY, "method": "turnstile",
"sitekey": site_key, "pageurl": page.url
})
task_id = resp.text.split("|")[1]
# Poll and inject...
Playwright vs Selenium vs Puppeteer
| Feature | Playwright | Selenium | Puppeteer |
|---|---|---|---|
| Languages | Python, Node.js, C#, Java | Python, Java, C#, Ruby, JS | Node.js |
| Browsers | Chromium, Firefox, WebKit | Chrome, Firefox, Edge, Safari | Chromium |
| Auto-wait | ✅ Built-in | ❌ Manual waits | ⚠️ Partial |
| Network interception | ✅ | ⚠️ Limited | ✅ |
| CaptchaAI integration | ✅ Same API | ✅ Same API | ✅ Same API |
CaptchaAI works identically with all three — extract the site key, solve via API, inject the token.
Troubleshooting
| Issue | Fix |
|---|---|
page.query_selector returns null |
CAPTCHA loads dynamically; use page.wait_for_selector() |
| Token injection doesn't work | Check if the response textarea has a different ID |
| Playwright crashes in Docker | Install browser dependencies: playwright install-deps |
| CAPTCHA reappears after solving | Site may require callback execution; trigger it via page.evaluate() |
FAQ
Does Playwright's auto-wait help with CAPTCHAs?
Playwright's auto-wait ensures elements are visible before interacting, but it won't solve CAPTCHAs. You need CaptchaAI for the actual solving.
Can I use Playwright with all CAPTCHA types?
Yes. CaptchaAI handles the solving via API — Playwright just needs to extract the site key and inject the token. This works for reCAPTCHA, Turnstile, hCaptcha, and all other supported types.
Is Playwright better than Selenium for CAPTCHA automation?
Playwright's built-in auto-wait and better API design make CAPTCHA workflows more reliable. The CaptchaAI integration is identical for both.
Discussions (0)
Join the conversation
Sign in to share your opinion.
Sign InNo comments yet.