Skip to main content

CAPTCHA Solving

Browserless detects and solves CAPTCHAs programmatically using Chrome DevTools Protocol events and commands. Use stealth routes to prevent CAPTCHAs from appearing in the first place. This page covers what to do when they still appear.

How it works

The CAPTCHA system operates through Chrome DevTools Protocol (CDP) events and commands:

  • Automatic CAPTCHA solving: Add solveCaptchas=true to your connection URL to monitor and solve CAPTCHAs in real-time without manual CDP commands
  • Detection: The Browserless.captchaFound event fires automatically when a CAPTCHA is detected
  • Solving: The Browserless.solveCaptcha command programmatically solves detected CAPTCHAs

Automatic CAPTCHA Solving

Add solveCaptchas=true as a query parameter in your connection URL. Browserless monitors the session for CAPTCHA challenges and solves them in real-time, firing CDP events for programmatic monitoring. This approach requires no manual solveCaptcha calls.

import puppeteer from "puppeteer-core";

const TOKEN = "YOUR-API-TOKEN";
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const waitForCaptchaResolved = (cdp, timeout = 180000) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(null);
}, timeout);

cdp.on("Browserless.captchaAutoSolved", resolve);

cdp.on("Browserless.captchaFound", (params) => {
console.log("Captcha found, type:", params.type, params.status);
});
});
};

(async () => {
const browser = await puppeteer.connect({
browserWSEndpoint: `wss://production-sfo.browserless.io/stealth?token=${TOKEN}&solveCaptchas=true`,
});

const page = await browser.newPage();
const cdp = await page.target().createCDPSession();

await page.goto("https://www.google.com/recaptcha/api2/demo", {
waitUntil: "networkidle0",
});

if (await page.$(".g-recaptcha")) {
console.log("Captcha found in page, solving...");
const { token, found, solved, time } = await waitForCaptchaResolved(cdp);

console.log("CAPTCHA solved:");
console.log({ token, found, solved, time });

await page.click("[type='submit']");
await sleep(2500);
await page.screenshot({ path: "screenshot.png" });
}

await browser.close();
})();

CAPTCHA Detection

The Browserless.captchaFound CDP event fires when Browserless detects a CAPTCHA on the page. Set up a listener before navigating so you don't miss the event.

Passive Detection with Event Listeners

Set up automatic CAPTCHA detection using CDP event listeners. The system monitors network traffic patterns and automatically emits events when CAPTCHA services are detected:

const cdp = await page.createCDPSession();
await new Promise((resolve) =>
cdp.on("Browserless.captchaFound", () => {
console.log("Found a captcha!");
return resolve();
})
);

Detection Mechanism

The system automatically detects CAPTCHAs by monitoring network requests and matching against known CAPTCHA service patterns. When a CAPTCHA is detected, the Browserless.captchaFound event is emitted to all active CDP sessions for that page.

Playwright and CDP

Playwright uses its own browser protocols by default. To use Browserless CDP events, connect over CDP and reuse the existing context and page instead of creating new ones. See the full example below.

Here are complete scripts demonstrating CAPTCHA detection and solving in context:

import puppeteer from "puppeteer-core";

const waitForCaptcha = (cdpSession) => {
return new Promise((resolve) =>
cdpSession.on("Browserless.captchaFound", resolve)
);
};

const browserWSEndpoint =
"wss://production-sfo.browserless.io/stealth?token=YOUR_API_TOKEN_HERE&timeout=300000";

try {
const browser = await puppeteer.connect({ browserWSEndpoint });

const page = await browser.newPage();
const cdp = await page.createCDPSession();

await page.goto("https://www.google.com/recaptcha/api2/demo", {
waitUntil: "networkidle0",
});

await waitForCaptcha(cdp);
console.log("Captcha found!");

const { solved, error } = await cdp.send("Browserless.solveCaptcha");
console.log({ solved, error });

// Continue...
await page.click("#recaptcha-demo-submit");
await browser.close();
} catch (e) {
console.error("There was a big error :(", e);
process.exit(1);
}

CAPTCHA Solving

Use this approach when you need programmatic control over when CAPTCHAs are solved. Set up a Browserless.captchaFound event listener, then call Browserless.solveCaptcha to trigger solving on demand.

Programmatic Solving

Once a CAPTCHA is detected, use the Browserless.solveCaptcha command to solve it:

const cdp = await page.createCDPSession();
const { solved, error } = await cdp.send("Browserless.solveCaptcha");
console.log({
solved,
error,
});
Playwright and CDP

Playwright uses its own browser protocols by default. Connect over CDP and reuse the existing context and page instead of creating new ones.

Here are complete scripts demonstrating CAPTCHA detection and solving:

import puppeteer from "puppeteer-core";

const waitForCaptcha = (cdpSession) => {
return new Promise((resolve) =>
cdpSession.on("Browserless.captchaFound", resolve)
);
};

const browserWSEndpoint =
"wss://production-sfo.browserless.io/stealth?token=YOUR_API_TOKEN_HERE&timeout=300000";

try {
const browser = await puppeteer.connect({ browserWSEndpoint });

const page = await browser.newPage();
const cdp = await page.createCDPSession();

await page.goto("https://www.google.com/recaptcha/api2/demo", {
waitUntil: "networkidle0",
});

await waitForCaptcha(cdp);
console.log("Captcha found!");

const { solved, error } = await cdp.send("Browserless.solveCaptcha");
console.log({ solved, error });

// Continue...
await page.click("#recaptcha-demo-submit");
await browser.close();
} catch (e) {
console.error("There was a big error :(", e);
process.exit(1);
}

Response Fields

The solveCaptcha response includes information about the solving attempt:

  • found: Whether a CAPTCHA was detected on the page
  • solved: Whether the CAPTCHA was successfully solved
  • time: Time taken to solve the CAPTCHA, in milliseconds
  • token: The solved CAPTCHA token, if available
  • error: Any errors during execution

Integration with Live Sessions

CAPTCHA solving integrates with Browserless live URL sessions for hybrid automation workflows. This lets a human step in when automated solving fails, providing a fallback for complex CAPTCHAs.

Performance Considerations

  • CAPTCHA solving can take several seconds to minutes. Adjust timeouts accordingly.
  • Each CAPTCHA solve attempt costs 10 units (see your account dashboard for unit details)
  • Use stealth features and residential proxies to reduce CAPTCHA frequency

Next Steps