Skip to main content
Hyperbrowser can automatically detect and solve CAPTCHAs when you enable it during session creation.
CAPTCHA solving requires being on a paid plan.

Enable CAPTCHA Solving

Set the session creation parameter to enable solving:
import { Hyperbrowser } from "@hyperbrowser/sdk";
import { config } from "dotenv";

config();

const client = new Hyperbrowser({
  apiKey: process.env.HYPERBROWSER_API_KEY,
});

async function main() {
  const session = await client.sessions.create({
    solveCaptchas: true,
  });

  try {
    console.log("Session Live URL:", session.liveUrl);
    console.log("WS Endpoint:", session.wsEndpoint);
    // ... connect with Playwright/Puppeteer and automate
  } finally {
    await client.sessions.stop(session.id);
  }
}

main().catch(console.error);
Some sites require proxies to be enabled for CAPTCHA solving to work reliably.

Waiting for CAPTCHA Solve

Solving can take time. When navigating to pages that might contain CAPTCHAs, add appropriate waits:
Node.js
const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms));

await page.goto("https://news.ycombinator.com/", { waitUntil: "networkidle0" });
await sleep(20_000);
A better approach is to wait on session events so you know exactly when a CAPTCHA is detected and when it is solved. Below is an example using Playwright, but you can adapt the same logic for Puppeteer or other libraries.
import { Hyperbrowser } from "@hyperbrowser/sdk";
import { config } from "dotenv";
import { chromium } from "playwright";

config();

const client = new Hyperbrowser({
  apiKey: process.env.HYPERBROWSER_API_KEY,
});

const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

const MAX_DETECTION_TRIES = 10;
const MAX_SOLVED_TRIES = 30;

const waitForCaptcha = async (sessionId: string, startTimestamp: number) => {
  let solved = false;
  let detected = false;
  let detectionTries = 0;
  let solvedTries = 0;

  console.log("Waiting for captcha detection...");
  while (!detected && detectionTries < MAX_DETECTION_TRIES) {
    const resp = await client.sessions.eventLogs.list(sessionId, {
      startTimestamp,
      types: ["captcha_detected"],
    });
    const data = resp.data;
    detected = data.length > 0;
    detectionTries++;
    await sleep(1000);
  }
  if (detected) {
    console.log("Captcha detected!");
  } else {
    console.log("Captcha not detected!");
    return;
  }

  console.log("Waiting for captcha solving...");
  while (!solved && solvedTries < MAX_SOLVED_TRIES) {
    const resp = await client.sessions.eventLogs.list(sessionId, {
      startTimestamp,
      types: ["captcha_solved"],
    });
    const data = resp.data;
    solved = data.length > 0;
    solvedTries++;
    await sleep(1000);
  }
  if (solved) {
    console.log("Captcha solved!");
  } else {
    console.log("Captcha not solved!");
  }
};

const main = async () => {
  const session = await client.sessions.create({
    solveCaptchas: true,
  });
  console.log("Session Live URL:", session.liveUrl);

  try {
    const browser = await chromium.connectOverCDP(session.wsEndpoint);
    const context = browser.contexts()[0];
    const page = context.pages()[0];
    const startTimestamp = Date.now();
    await page.goto("https://2captcha.com/demo/cloudflare-turnstile");

    await waitForCaptcha(session.id, startTimestamp);
    await sleep(5_000);
  } catch (err) {
    console.error(`Error: ${err}`);
  } finally {
    await client.sessions.stop(session.id);
  }
};

main();

Next Steps