Solve reCAPTCHA in Playwright
Bypass a reCAPTCHA v2 challenge inside a Playwright script using the CaptchaSonic Python SDK β drop-in token injection, no DOM scraping.
You have a Playwright script that hits a login form gated by reCAPTCHA v2. Instead of clicking image tiles by hand, this recipe asks CaptchaSonic for a fresh g-recaptcha-response token and injects it into the page, so the form submits as if a human solved the challenge.
TIP
This recipe uses the token flow (no image scraping). The SDK polls our infrastructure and returns a ready-to-submit token in 6β12 s on average.
What you'll build
A Playwright script that opens a target page, solves its reCAPTCHA v2 via CaptchaSonic, injects the token, and submits the form β fully headless, no human interaction.
Time: ~5 minutes Β· Difficulty: beginner.
Setup
pip install captchasonic playwright
playwright install chromium
export CAPTCHASONIC_API_KEY=sonic_xxx # from /app
You need:
- A CaptchaSonic API key with credits (get one, then add funds).
- The target page's
website_urlandwebsite_key(the reCAPTCHA sitekey, found in the page's HTML asdata-sitekey="β¦").
The recipe
import os
from playwright.sync_api import sync_playwright
from captchasonic import CaptchaSonic
TARGET = "https://example.com/login"
SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
solver = CaptchaSonic(os.environ["CAPTCHASONIC_API_KEY"])
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto(TARGET)
# 1. Ask CaptchaSonic for a token (auto-polls, returns when ready).
result = solver.solve_recaptcha_v2_token(
website_url=TARGET,
website_key=SITEKEY,
)
token = result["token"]
# 2. Inject the token into the page's g-recaptcha-response field.
# The textarea is hidden by default β make it visible-to-DOM first.
page.evaluate(
"""(t) => {
const el = document.getElementById('g-recaptcha-response');
el.style.display = 'block';
el.value = t;
}""",
token,
)
# 3. Submit the form.
page.fill("input[name='username']", "[email protected]")
page.fill("input[name='password']", "hunter2")
page.click("button[type='submit']")
page.wait_for_url("**/dashboard", timeout=15_000)
print("logged in:", page.url)
browser.close()
import { chromium } from "playwright";
import { CaptchaSonic } from "captchasonic";
const TARGET = "https://example.com/login";
const SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-";
const solver = new CaptchaSonic(process.env.CAPTCHASONIC_API_KEY);
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
await page.goto(TARGET);
const result = await solver.solveRecaptchaV2Token({
websiteURL: TARGET,
websiteKey: SITEKEY,
});
const token = result.solution.gRecaptchaResponse;
await page.evaluate((t) => {
const el = document.getElementById("g-recaptcha-response");
el.style.display = "block";
el.value = t;
}, token);
await page.fill("input[name='username']", "[email protected]");
await page.fill("input[name='password']", "hunter2");
await page.click("button[type='submit']");
await page.waitForURL("**/dashboard", { timeout: 15_000 });
console.log("logged in:", page.url());
await browser.close();
Returns a
g-recaptcha-responsetoken you write into the hidden textarea β the form's submit handler reads it directly, exactly as if a human had solved the challenge.
Common pitfalls
g-recaptcha-responseis missing from the page. Some sites bind the token via a JavaScript callback (data-callback="β¦"). Call that function with the token instead of (or in addition to) writing the textarea β e.g.page.evaluate("window.onCaptchaSolved(t)", token).- Token expires before submit. reCAPTCHA tokens live ~120 s. Solve as late as possible in your script β right before
click('submit'), not at script start. - Sitekey changes per environment. Read it from the page at runtime:
page.get_attribute(".g-recaptcha", "data-sitekey")rather than hard-coding. - Need geo-locked solving? Pass
proxy="http://user:pass@host:port"tosolve_recaptcha_v2_tokenso the token is solved through your IP β required when the target validates IPβtoken coherence.
See also
- Python SDK β reCAPTCHA v2 (token)
- Capability Matrix β which return field for which captcha type
- Error Handling β
InsufficientBalanceError,MinuteLimitExceededError, retry behavior