JustBrowser
Tutorials12 min read

Integrate CAPTCHA Solvers with Antidetect Browsers (2026)

JustBrowser Platform Team·
captcha-solverantidetect-automationhcaptcharecaptchaturnstilebuildinpublicsaasstudioaiworkforcebuildwithclaude

Last month I watched a scraper fail 400 CAPTCHAs in a row. Not because the solver was broken — 2captcha returned valid tokens every single time. The site rejected them anyway. Every. Single. One.

The problem wasn't the CAPTCHA. It was everything else. And honestly? I should've caught it sooner. I've made this exact mistake before.

The team had a nice setup: Puppeteer with playwright-extra-plugin-stealth, rotating residential proxies, 2captcha integration that worked fine on their test environment. But the target site — a major e-commerce platform — ran hCaptcha Enterprise. And hCaptcha Enterprise doesn't just verify you clicked the right images. It scores your entire session: fingerprint consistency, mouse movement patterns, time-on-page before challenge, scroll behavior, even how you moved your cursor to the submit button.

Their browser fingerprint was leaking SwiftShader WebGL. Their mouse moved in straight lines at constant velocity. Their "user" solved a CAPTCHA in 3 seconds after sitting motionless for 47 seconds. hCaptcha saw right through it.

Bolting a CAPTCHA solver onto a leaky profile is like putting racing tires on a car with no engine. Looks right, goes nowhere.

What We're Building

By the end of this tutorial, you'll have a working integration between an antidetect browser (JustBrowser) and a CAPTCHA solving service (we'll use 2captcha as the example, but the pattern works for CapMonster, anti-captcha, or any REST-based solver). The setup handles reCAPTCHA v2/v3, hCaptcha, and Cloudflare Turnstile — the three you'll hit most often in 2026.

More importantly, you'll understand why the browser environment matters as much as the solver itself. A clean fingerprint with realistic behavior gets you past challenges that raw solving power can't crack.

Prerequisites

  • JustBrowser ($9.99/month for unlimited profiles and REST API access — the 7-day trial includes the API if you're just following along)
  • A CAPTCHA solving service account (2captcha at ~$2.99/1K solves, or CapMonster Cloud at ~$0.60/1K)
  • Node.js 18+ with Playwright installed
  • Basic familiarity with async/await and REST APIs
  • A profile already configured with a realistic fingerprint (see our WebGL fingerprinting guide if you haven't set this up). For audio and font fingerprinting, check our audio/font/hardware fingerprinting guide

Step 1: Understand How Modern CAPTCHAs Actually Work

Before we touch code, let's kill a misconception.

Old CAPTCHAs were simple: solve the puzzle, get access. reCAPTCHA v2 in 2018 checked if you clicked images correctly. That was basically it.

Modern CAPTCHAs — reCAPTCHA v3, hCaptcha Enterprise, Cloudflare Turnstile — are behavioral scoring systems that happen to include an optional visual challenge. They collect signals from the moment the page loads:

  • Fingerprint signals: Canvas hash, WebGL renderer, audio context, font list, screen resolution, timezone. Sound familiar? Same stuff antidetect browsers spoof.
  • Behavioral signals: Mouse movement patterns (velocity, acceleration, jitter), scroll behavior, keystroke timing, time between page load and interaction.
  • Network signals: IP reputation, TLS fingerprint, request timing patterns.
  • History signals: Has this fingerprint been seen before? Solving CAPTCHAs too fast? Consistent patterns across sessions?

The visual challenge is almost an afterthought. A bot with a perfect image classifier will still fail if everything else looks automated. A human with clean signals might not even see a challenge — they get a silent pass.

This is why the integration order matters: fix your browser first, add the solver second. I learned this the expensive way — burning through $40 in solver credits before realizing my profiles were trash.

Step 2: Configure a Clean Browser Profile

Launch JustBrowser and create a profile specifically for CAPTCHA-heavy automation. The settings that matter:

Fingerprint:

  • Pick a common GPU (Intel UHD 620 for laptops, NVIDIA RTX 3060 for desktops). Avoid exotic hardware.
  • Match screen resolution to something real: 1920x1080 or 1440x900, not 1366x768 (common in headless).
  • Set timezone to match your proxy's geolocation.

Proxy:

  • Residential, geo-matched to your target site's region. Datacenter proxies are basically useless here.
  • Sticky session — don't rotate mid-session or CAPTCHA systems will flag the IP change.

Warm-up: Before hitting your target, run the profile through JustBrowser's cookie warm-up. Visit Google, YouTube, Amazon. Click around. Let it accumulate normal browsing artifacts. 10-15 minutes of "being human" makes a difference.

We covered profile warming in the affiliate multi-account playbook — the same principles apply here. For proxy configuration details, see our ISP proxies setup tutorial.

Step 3: Launch Profile and Connect Playwright

Start the profile via JustBrowser's REST API:

const JUSTBROWSER_API = 'http://127.0.0.1:36542/api/v1';
const TOKEN = process.env.JUSTBROWSER_TOKEN; // from the app's API/AI tab
const PROFILE_ID = 'your-profile-id';

async function launchProfile() {
  const response = await fetch(`${JUSTBROWSER_API}/profiles/${PROFILE_ID}/start`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TOKEN}` },
    body: JSON.stringify({ headless: false })
  });

  const { data } = await response.json();
  return data.cdp_url;
}

Connect Playwright:

import { chromium } from 'playwright';

const cdpUrl = await launchProfile();
const browser = await chromium.connectOverCDP(cdpUrl);
const context = browser.contexts()[0];
const page = await context.newPage();

Now you have Playwright controlling a browser with real fingerprint protection. The page carries the profile's C++-level fingerprint — in our recorded runs it showed 0% stealth / 0% headless on CreepJS. Verify it yourself against CreepJS and FingerprintJS Pro before proceeding; no result is guaranteed. We've got a comprehensive guide on testing your setup against detection services if you want to verify before proceeding. For deeper automation patterns, see Playwright/Puppeteer antidetect integration.

Step 4: Integrate 2captcha for reCAPTCHA v2

Here's the pattern: extract CAPTCHA parameters from the page, send them to your solver, wait for the token, inject it back.

const TWOCAPTCHA_KEY = 'your-2captcha-api-key';

async function solveRecaptchaV2(page) {
  // Extract sitekey from the page
  const sitekey = await page.evaluate(() => {
    const element = document.querySelector('[data-sitekey]');
    return element?.getAttribute('data-sitekey');
  });

  if (!sitekey) throw new Error('No reCAPTCHA sitekey found');

  const pageUrl = page.url();

  // Submit to 2captcha
  const submitResponse = await fetch(
    `http://2captcha.com/in.php?key=${TWOCAPTCHA_KEY}&method=userrecaptcha&googlekey=${sitekey}&pageurl=${pageUrl}&json=1`
  );
  const { request: taskId } = await submitResponse.json();

  // Poll for result (typically 20-60 seconds)
  let token = null;
  for (let i = 0; i < 30; i++) {
    await new Promise(r => setTimeout(r, 5000));

    const resultResponse = await fetch(
      `http://2captcha.com/res.php?key=${TWOCAPTCHA_KEY}&action=get&id=${taskId}&json=1`
    );
    const result = await resultResponse.json();

    if (result.status === 1) {
      token = result.request;
      break;
    }
  }

  if (!token) throw new Error('CAPTCHA solving timed out');

  // Inject token into the page
  await page.evaluate((token) => {
    document.querySelector('#g-recaptcha-response').value = token;
    // Some sites also need this
    const callback = window.___grecaptcha_cfg?.clients?.[0]?.U?.U?.callback;
    if (callback) callback(token);
  }, token);

  return token;
}

The critical part most tutorials skip: don't just inject the token and submit. Move your mouse to the submit button naturally. Add a 500-2000ms delay. Maybe scroll slightly. The CAPTCHA is "solved," but the site is still watching.

Step 5: Handle hCaptcha

hCaptcha uses similar flow but different endpoints:

async function solveHcaptcha(page) {
  const sitekey = await page.evaluate(() => {
    const iframe = document.querySelector('iframe[src*="hcaptcha"]');
    const src = iframe?.src || '';
    const match = src.match(/sitekey=([^&]+)/);
    return match?.[1];
  });

  const pageUrl = page.url();

  // 2captcha supports hCaptcha with method=hcaptcha
  const submitResponse = await fetch(
    `http://2captcha.com/in.php?key=${TWOCAPTCHA_KEY}&method=hcaptcha&sitekey=${sitekey}&pageurl=${pageUrl}&json=1`
  );
  const { request: taskId } = await submitResponse.json();

  // Same polling logic as reCAPTCHA
  // ... poll for result ...

  // Inject into hCaptcha's response field
  await page.evaluate((token) => {
    document.querySelector('[name="h-captcha-response"]').value = token;
    document.querySelector('[name="g-recaptcha-response"]')?.value = token;
  }, token);

  return token;
}

hCaptcha Enterprise is pickier about behavioral signals than standard hCaptcha. If you're hitting Enterprise-protected sites, the warm-up and mouse movement patterns matter more than the solver speed.

Look, I'll be honest — I find hCaptcha Enterprise annoying. It's well-designed, which is frustrating when you're on the other side of it. But that's the game.

Step 6: Cloudflare Turnstile Integration

Turnstile is Cloudflare's "invisible" CAPTCHA. It often passes users silently but will challenge bots. The good news: it's lighter than reCAPTCHA v3. The bad news: Cloudflare has excellent bot detection on everything else.

async function solveTurnstile(page) {
  const sitekey = await page.evaluate(() => {
    const element = document.querySelector('[data-sitekey]') ||
                    document.querySelector('.cf-turnstile');
    return element?.getAttribute('data-sitekey');
  });

  const pageUrl = page.url();

  // 2captcha Turnstile support
  const submitResponse = await fetch(
    `http://2captcha.com/in.php?key=${TWOCAPTCHA_KEY}&method=turnstile&sitekey=${sitekey}&pageurl=${pageUrl}&json=1`
  );
  const { request: taskId } = await submitResponse.json();

  // Poll for result
  // ...

  await page.evaluate((token) => {
    const input = document.querySelector('[name="cf-turnstile-response"]');
    if (input) input.value = token;
  }, token);

  return token;
}

With Turnstile, the solve time matters less than session cleanliness. Cloudflare's broader bot detection (checking TLS fingerprint, HTTP/2 settings, IP reputation) often blocks you before Turnstile even loads. Our JA4 TLS fingerprinting deep-dive covers what Cloudflare actually checks. For timezone/geolocation mismatches that trigger flags, see timezone and geolocation spoofing.

Step 7: Add Behavioral Realism

Here's where most automations fail. The CAPTCHA token is valid. The fingerprint is clean. But the behavior screams "script."

Before and after solving, add human-like interactions:

async function humanBehavior(page) {
  // Random scroll
  await page.evaluate(() => {
    window.scrollBy(0, Math.random() * 300 + 100);
  });
  await page.waitForTimeout(Math.random() * 1000 + 500);

  // Move mouse naturally (not in a straight line)
  const { width, height } = await page.viewportSize();
  const targetX = Math.random() * width * 0.8 + width * 0.1;
  const targetY = Math.random() * height * 0.8 + height * 0.1;

  // Move in steps with slight curves
  await page.mouse.move(targetX, targetY, { steps: 25 });

  await page.waitForTimeout(Math.random() * 500 + 200);
}

Call this before solving and after injecting the token. It's not about tricking timing analysis — it's about not having zero mouse events between page load and form submission. Yes, this feels like busywork. It kind of is. But it works, so here we are.

For outbound automation workflows that need human-like pacing, VeloCalls handles call timing and JustEmails manages send patterns. Same principle: behavioral realism matters.

Common Errors and Fixes

Error: Token injected but form submission fails

The site probably uses a callback function that needs to be triggered after token injection. Check for grecaptcha.execute() or similar in the page source. Some sites verify the token server-side immediately on callback, not on form submit.

Error: CAPTCHA appears repeatedly on same session

Your fingerprint or behavior is flagged. The site keeps challenging because it doesn't trust the session. Switch to a fresh profile with different fingerprint. Let the old one cool down for 24-48 hours.

Error: Solver returns valid token but site shows "verification failed"

Token expiry. reCAPTCHA tokens expire after ~2 minutes. If your automation waits too long between getting the token and submitting the form, it's already invalid. Inject and submit within 60 seconds.

Error: Getting blocked before CAPTCHA even appears

Stop. This isn't a CAPTCHA problem. Your fingerprint or IP is flagged at page load. Run your profile against CreepJS to find leaks — we walk through interpreting results in our BrowserScan/IPHey/Pixelscan guide. Check your proxy reputation. Sites like ClickzProtect can help identify if your IPs are flagged in fraud databases.

Frequently Asked Questions

Why does my CAPTCHA solver work on some sites but not others?

Modern CAPTCHA systems like reCAPTCHA v3, hCaptcha Enterprise, and Cloudflare Turnstile score your entire session — not just the CAPTCHA interaction. If your browser fingerprint is inconsistent or your behavioral signals look automated, you'll fail even with a correct token. The solver returns a valid answer, but the site rejects the session because everything else screams bot.

Should I use browser extension CAPTCHA solvers or REST API integration?

REST API integration. Browser extensions modify the DOM and leave detectable traces — sites check for injected scripts and extension artifacts. API-based solving happens server-side: you extract the CAPTCHA parameters, send them to the solver, get a token back, and inject it via your automation framework. No extension fingerprint, no DOM modifications to detect.

How do I handle Cloudflare Turnstile with an antidetect browser?

Turnstile is lighter than reCAPTCHA but still scores session behavior. Extract the sitekey from the page source, send it to your CAPTCHA service with the page URL, wait for the token, then set cf-turnstile-response in the hidden input and submit the form. The key is maintaining a consistent fingerprint and realistic mouse movement before the Turnstile challenge even appears.

What's the cost difference between CAPTCHA solving services?

2captcha charges around $2.99 per 1,000 normal CAPTCHAs and $2.99 per 1,000 reCAPTCHA v2. CapMonster Cloud runs about $0.60 per 1,000 for reCAPTCHA. hCaptcha Enterprise and reCAPTCHA v3 cost more — typically $3-6 per 1,000 depending on the service. At scale, the CAPTCHA cost often exceeds your antidetect browser subscription.

Next Steps

Now that you've got CAPTCHA solving integrated, the weak links are usually:

  1. Proxy quality — residential, geo-matched, sticky sessions for CAPTCHA-heavy flows
  2. Profile rotation — don't burn one profile on repeated challenges; spread across a pool
  3. Behavioral telemetry — some sites send mouse/scroll data continuously; basic mouse.move() isn't enough

If you're tracking conversion data from automated flows, JustAnalytics offers cookieless analytics that won't cross-contaminate your profiles.

The antidetect browser handles fingerprint consistency. The CAPTCHA solver handles token generation. Your automation code handles behavioral realism. All three have to work together — and in 2026, the third one is where most teams fail.

Start with one profile, one target site, one CAPTCHA type. Get it working end-to-end before scaling. I've seen teams spin up 50-profile clusters before validating the basic flow, then wonder why their solve rate is 15%. Don't be that team.

(I've been that team. More than once.)


Try JustBrowser

Native Chromium antidetect browser — not extension-based. Real C++ engine patches at the canvas / WebGL / audio / font / screen layer, so 40+ identity parameters are genuine, not faked. REST API for Playwright, Puppeteer, Selenium. $9.99/month or $99.99/year. 7-day free trial, card required — cancel any time in the seven days and you are not charged. Unlimited profiles.

Get started → · How it differs from Multilogin / GoLogin / AdsPower

Ready to manage multiple accounts?

Seven days free, then $9.99/month — one plan, everything included.

We'd like to use Google Analytics, a Google service, to understand how our website is used. It sets two cookies in your browser and runs only if you click Accept. You can change your choice at any time with Cookie settings. Cookie Policy

Sign-in cookies and the cookie that remembers this choice are always on; the website needs them to work.

Google Analytics, a Google service, helps us understand how our website is used. It sets two cookies, _ga and _ga_TVZHQ99TZW. It is now onoff in this browser. If your browser sends a Global Privacy Control or Do Not Track signal, it stays off. Cookie Policy