Browser automation tools like Selenium, Playwright, and Puppeteer drive real browsers. When a CAPTCHA appears, the browser is blocked until the challenge is solved. This article explains how to combine these tools with a solving service so your automation never stops.
This is the midpoint of the Learning Path. By the end you will be able to wire solving into any browser workflow.
The Two Integration Patterns
Pattern A: Solve first, inject the token
Used for token CAPTCHAs like reCAPTCHA v2 and Turnstile. Your script detects the CAPTCHA, sends the sitekey and page URL to the solving service, waits for the token, and injects it into the hidden response field before submitting the form.
Pattern B: Solve the image, submit the answer
Used for classic image CAPTCHAs. Your script takes a screenshot of the CAPTCHA image, sends it to the service, and types the returned text into the input field.
Pattern A with Playwright (Python)
from playwright.sync_api import sync_playwright
import deathbycaptcha
client = deathbycaptcha.SocketClient("user", "pass")
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("https://example.com/login")
# Solve the reCAPTCHA v2 token
result = client.decode({
"googlekey": "SITE_KEY",
"pageurl": "https://example.com/login",
}, type=4, timeout=60)
if result:
token = result.text
# Inject the token into the response textarea
page.eval_on_selector(
"#g-recaptcha-response",
"el => el.value = arguments[0]", token,
)
page.click("button[type=submit]")
browser.close()
The same pattern in Node.js with Playwright:
const { chromium } = require('playwright');
const DBC = require('deathbycaptcha');
const client = new DBC.SocketClient('user', 'pass');
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com/login');
// Solve the reCAPTCHA v2 token
const result = await client.decode({
googlekey: 'SITE_KEY',
pageurl: 'https://example.com/login',
}, 60, 4);
if (result) {
// Inject the token into the response textarea
await page.evalOnSelector('#g-recaptcha-response',
(el, token) => { el.value = token; }, result.text);
await page.click('button[type=submit]');
}
await browser.close();
And in C# with Playwright:
using System.Threading.Tasks;
using Microsoft.Playwright;
using DeathByCaptcha;
Client client = new DeathByCaptcha.HttpClient("user", "pass");
await using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync();
var page = await browser.NewPageAsync();
await page.GotoAsync("https://example.com/login");
string tokenParams = "{\"googlekey\":\"SITE_KEY\",\"pageurl\":\"https://example.com/login\"}";
Captcha result = client.Decode(Client.DefaultTimeout,
new Hashtable { { "type", 4 }, { "token_params", tokenParams } });
if (result != null)
{
await page.EvalOnSelectorAsync("#g-recaptcha-response",
"(el, token) => { el.value = token; }", result.Text);
await page.ClickAsync("button[type=submit]");
}
Pattern B with Selenium (Python)
from selenium import webdriver
from selenium.webdriver.common.by import By
import deathbycaptcha
client = deathbycaptcha.SocketClient("user", "pass")
driver = webdriver.Chrome()
driver.get("https://example.com/register")
captcha_img = driver.find_element(By.ID, "captcha-image").screenshot_as_png
captcha = client.decode(captcha_img, timeout=60)
if captcha:
driver.find_element(By.NAME, "captcha").send_keys(captcha.text)
driver.find_element(By.TAG_NAME, "form").submit()
The image flow in Node.js with Selenium:
const { Builder, By } = require('selenium-webdriver');
const DBC = require('deathbycaptcha');
const client = new DBC.SocketClient('user', 'pass');
const driver = await new Builder().forBrowser('chrome').build();
await driver.get('https://example.com/register');
const img = await driver.findElement(By.id('captcha-image')).takeScreenshot();
const captcha = await client.decode(Buffer.from(img, 'base64'), 60);
if (captcha) {
await driver.findElement(By.name('captcha')).sendKeys(captcha.text);
await driver.findElement(By.tagName('form')).submit();
}
And in C# with Selenium:
using System.Collections;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using DeathByCaptcha;
Client client = new DeathByCaptcha.HttpClient("user", "pass");
using var driver = new ChromeDriver();
driver.Navigate().GoToUrl("https://example.com/register");
byte[] png = ((ITakesScreenshot)driver)
.GetScreenshot().AsByteArray;
Captcha captcha = client.Decode(png, Client.DefaultTimeout);
if (captcha != null)
{
driver.FindElement(By.Name("captcha")).SendKeys(captcha.Text);
driver.FindElement(By.TagName("form")).Submit();
}
Waiting for the CAPTCHA to Appear
Automation should not assume a CAPTCHA is present. Wait for it with an explicit wait:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.ID, "g-recaptcha-response"))
)
This makes the script robust when the site shows the CAPTCHA conditionally.
Handling Proxies
Many CAPTCHAs are tied to the IP that views the page. If your automation uses a proxy, pass the same proxy to the solving service so the challenge and the solve come from the same IP:
result = client.decode({
"googlekey": "SITE_KEY",
"pageurl": "https://example.com",
"proxy": "http://user:[email protected]:3128",
}, type=4, timeout=60)
The proxy parameter is identical in Node.js:
const result = await client.decode({
googlekey: 'SITE_KEY',
pageurl: 'https://example.com',
proxy: 'http://user:[email protected]:3128',
}, 60, 4);
And in C#:
string proxyParams = "{\"googlekey\":\"SITE_KEY\",\"pageurl\":\"https://example.com\",\"proxy\":\"http://user:[email protected]:3128\"}";
Captcha result = client.Decode(Client.DefaultTimeout,
new Hashtable { { "type", 4 }, { "token_params", proxyParams } });
Common Pitfalls
- Injecting before the CAPTCHA widget loads: wait for the response field to exist first.
- Wrong page URL: the sitekey and pageurl must match the page that generated the challenge.
- Forgetting to trigger the callback: some sites call a JavaScript callback after the token is set. Trigger it if present.
- Reusing tokens: tokens are single-use and short-lived. Solve fresh for each submission.
Key Takeaways
- Token CAPTCHAs: detect, solve, inject, submit.
- Image CAPTCHAs: screenshot, solve, type the answer.
- Always wait for the CAPTCHA to appear before solving.
- Pass your proxy to the solver for IP consistency.
Now you can wire solving into any browser flow. The advanced articles cover scaling, invisible CAPTCHAs, and production patterns.

English
Spanish
Russian
Chinese
French
Hindi
Arabic
Bengali
Indonesian
Portuguese
com, 