Automating Captchas with Playwright & Death By Captcha

Automating Captchas with Playwright & Death By Captcha

Posted on 2026-05-31 | Category: guides


Browser automation becomes significantly more powerful when combined with intelligent captcha solving. If your workflow involves solving a captcha and submitting it to a website, manually solving it quickly becomes inefficient. A more scalable approach is to combine our captcha solving API with Playwright. This article walks through how to implement that workflow using Node.js.

The workflow in a nutshell

The first step is submitting the captcha to Death By Captcha API, check if the token is ready by polling the API every 5 seconds until a token is returned, then the token is inserted into the hidden textarea element with ID g-recaptcha-response and finally the form needs to be submitted. This is a high level view of the whole pipeline:

ReCAPTCHA → Submit captcha to API → Poll API for solution token → Browser Automation → Submission

Why Use Playwright for This Workflow?

There are several browser automation frameworks available, but Playwright is especially well suited for modern API-driven automation. a) Built-in async/await support The workflow reads clearly from top to bottom.

await page.goto(...)await page.fill(...)await page.click(...)

b) Cleaner browser interaction Playwright provides direct methods for common form interactions such as:

  • Filling fields
  • Clicking buttons
  • Waiting for page readiness

This keeps your implementation concise.

Understanding how to set up your own Playwright automation

Note: We have added the full code at the bottom, this section is a high level overview of the overall Playwright workflow.

Stage 1: Configure client to solve the captcha

a) Either Integrate our existing Node.js client with your own logic, b) or use the sample code at the bottom section of the article (you can read more about it’s internal functions and setup).

Stage 2: Install required dependencies
npm install playwright
npx playwright install

The npmdependency gives your Node.js application access to browser automation.

The npxdependency is needed since it gives you the binaries, downloads the actual browsers Playwright controls:

  • Chromium
  • Firefox
  • WebKit
Stage 3: Configuring the Submission Target

The first part of the implementation defines the destination and selectors.

const SUBMISSION\_URL = "https://www.google.com/recaptcha/api2/demo";

And the page elements:

const SELECTORS = {
// add selectors here
submitButton: "#recaptcha-demo-submit"
}

Centralizing selectors makes updates easier if the page structure changes.

Stage 4: Get the Captcha Result

Before interacting with the browser, your application needs to confirm that Death By Captcha API returned a token.

const retrieveToken = async ()

Its job is to:

  • Return the token fetched
  • Close the app on error

This prevents invalid submissions.

Stage 5: Launch Chromium

Playwright launches Chromium (This creates a browser context ready for automation) and calls submitToPage() which receives Playwright context and which executes the submission to the page only if a token was successfully fetched.

const browser = await chromium.launch()
 
 const token = await retrieveToken()
 
 if (token) {
   const page = await browser.newPage()
   await submitToPage(page)
   console.log("Captcha solved successfully")
}
Stage 6: Submission of token & form

The final step:

const submitToPage = async (page) => {
await page.goto(SUBMISSION\_URL)
await page.evaluate((value) => {
const textArea = document.querySelector("#g-recaptcha-response")
textArea.value = value
textArea.dispatchEvent(new Event("input", { bubbles: true }))
}, token)
await page.click(SELECTORS.submitButton)
}

submitToPage()

1. Waits until Playwright goes to the submission URL 2. To then Wait for textArea token injection, this selector requires a different treatment since it’s a hidden element. 3. Waits until form gets submitted with a click on the submit button. This completes the workflow automatically.

Complete code:

Step 1: Make sure your ‘package.json’ is set up correctly Make sure:

  • That “type” is set to “module” for ES6
  • To have index.js as your app entry point by using: “main”: “index.js”
  • To have a “start” script which runs your Node.js app: “start”: “node index.js”
{
"name": "playwrite\_automation",
[...]
"type": "module",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo "Error: no test specified" && exit 1"
}
}

Step 2: Install dependencies Skip this step if you’ve already installed them in the previous section

npm install playwright
npx playwright install

Step 3: Use the code

recaptcha-solver.js (DBC captcha solving)
const API\_URL = "http://api.dbcapi.me/api/captcha"
const USERNAME = "your\_username"
const PASSWORD = "your\_password"
const CAPTCHA\_PARAMS = {
proxy: "http://user:[email protected]:3128", // leave empty if no proxy
proxytype: "HTTP", // leave empty if no proxy
googlekey: "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx\_mJ-",
pageurl: "https://www.google.com/recaptcha/api2/demo"
}
const TYPE = 4
const submitCaptcha = async () => {
const formData = new FormData()
formData.append("username", USERNAME)
formData.append("password", PASSWORD)
formData.append("type", TYPE)
formData.append("token\_params", JSON.stringify(CAPTCHA\_PARAMS))
const response = await fetch(API\_URL, {
method: "POST",
body: formData
})
if (!response.ok) {
throw new Error(`Submission to DBC failed: ${response.status}`)
}
const text = await response.text()
const params = new URLSearchParams(text)
return params.get("captcha")
}
const getToken = async (captchaId) => {
const response = await fetch(`${API\_URL}/${captchaId}`)
if (!response.ok) {
throw new Error(`Fetch failed: ${response.status}`)
}
return await response.text()
}
// Sleep helper
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
export const solveCaptcha = async () => {
try {
console.log("Submitting captcha...")
const captchaId = await submitCaptcha()
console.log("Solving captcha...")
console.log("Captcha ID:", captchaId)
const maxAttempts = 24
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
console.log(`Waiting 5 seconds before attempt ${attempt}...`)
await delay(5000)
console.log(`Checking result... Attempt ${attempt}`)
const result = await getToken(captchaId)
const params = new URLSearchParams(result)
const token = params.get("text")
if (token.length > 1) {
console.log("Final response:")
return {
success: true,
data: token
}
} else if (token === "?") {
return {
success: false,
error: "Empty response."
}
}
console.log("Result not ready yet.")
}
console.log("Timed out waiting for resolution.")
} catch (error) {
return {
success: false,
error
}
}
}

index.js (Playwright execution)

import { solveCaptcha } from "./recaptcha-solver.js"
import { chromium } from "playwright"
const SUBMISSION\_URL = "https://www.google.com/recaptcha/api2/demo"
const SELECTORS = {
// add selectors here
submitButton: "#recaptcha-demo-submit"
}
const retrieveToken = async () => {
const response = await solveCaptcha()
if (!response.success) {
console.error(response.error)
return
}
console.log(response.data)
return response.data
}
const token = await retrieveToken()
const submitToPage = async (page) => {
await page.goto(SUBMISSION\_URL)
await page.evaluate((value) => {
const textArea = document.querySelector("#g-recaptcha-response")
textArea.value = value
textArea.dispatchEvent(new Event("input", { bubbles: true }))
}, token)
await page.click(SELECTORS.submitButton)
}
const solvePageCaptcha = async () => {
const browser = await chromium.launch({
headless: false,
})
try {
if (token) {
const page = await browser.newPage()
await submitToPage(page)
console.log("Captcha solved successfully")
}
} catch (error) {
console.error("Token submission failed:", error.message)
} finally {
await browser.close()
}
}
solvePageCaptcha()

Expected output:



Status: OK

Server beroperasi penuh dengan waktu respons yang lebih cepat dari rata-rata.
  • Waktu penyelesaian rata-rata
  • 2 detik - Normal CAPTCHAs (1 menit. yang lalu)
  • 16 detik - reCAPTCHA V2, V3 (1 menit. yang lalu)
  • 13 detik - yang lain (1 menit. yang lalu)
Chrome and Firefox logos
Ekstensi browser tersedia

Pembaruan

  1. May 13: Crypto payments got better! You can now purchase your CAPTCHAs using cryptocurrency through the Hekelet payment processor at https://deathbycaptcha.com/user-pay and receive an extra 20% FREE CAPTCHA credit with every package purchased this way.
  2. Apr 15: GitHub Updates: We’ve upgraded our libraries, expanded sample code, enhanced documentation, and added support for C++ and Go, making integration smoother than ever. Explore what’s new at github.com/deathbycaptcha!
  3. Jan 27: RESOLVED - If your email to one of our official addresses ([email protected], [email protected], or [email protected]) has bounced or you haven’t received a response, please try resending it or reach out via our Live Chat Support at https://deathbycaptcha.com/es/contact.

  4. পূর্ববর্তী আপডেট…

Mendukung

Sistem kami dirancang untuk sepenuhnya ramah pengguna dan mudah digunakan. Jika Anda memiliki masalah dengan itu, cukup email kami diEmail dukungan teknis DBC com, dan agen dukungan akan menghubungi Anda sesegera mungkin.

Dukungan Langsung

Tersedia Senin hingga Jumat (10 pagi hingga 4 sore EST) Live support image. Link to live support page