CAPTCHA Solving

Hyperbrowser automatically solves CAPTCHAs when the solveCaptchas parameter is set to true for session creation.

import { connect } from "puppeteer-core";
import { Hyperbrowser } from "@hyperbrowser/sdk";
import { config } from "dotenv";

config();

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

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

  try {
    const browser = await connect({
      browserWSEndpoint: session.wsEndpoint,
      defaultViewport: null,
    });

    const [page] = await browser.pages();

    // Navigate to a website
    console.log("Navigating to Hacker News...");
    await page.goto("https://news.ycombinator.com/");
    const pageTitle = await page.title();
    console.log("Page 1:", pageTitle);
    await page.evaluate(() => {
      console.log("Page 1:", document.title);
    });
  } catch (err) {
    console.error(`Encountered error: ${err}`);
  } finally {
    await client.sessions.stop(session.id);
  }
};

main();

CAPTCHA solving is only available on PAID plans.

Waiting for CAPTCHA Solve

Captcha solving can take a bit of time, so make sure to implement proper waiting strategies when navigating to pages that might contain CAPTCHAs:

const sleep = (ms) => new Promise((res) => setTimeout(res, ms));

await page.goto("https://news.ycombinator.com/",
    { waitUntil: "networkidle0" }
);
await sleep(20000);

A better approach for this would be to use the session events to know when a CAPTCHA is detected and when it is solved. Here is an example of doing this with a simple function. You can change the values to fit your needs and use another automation library like puppeteer as well.

import { Hyperbrowser } from "@hyperbrowser/sdk";
import { config } from "dotenv";
import { chromium } from "playwright";

config();

const hbClient = 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 hbClient.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 hbClient.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 hbClient.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 hbClient.sessions.stop(session.id);
  }
};

main();

Last updated