How to bypass captchas with Playwright

How to bypass captchas with Playwright + 2Captcha (or SolveCaptcha)

If you're automating with Playwright and run into captchas — welcome to reality. reCAPTCHA, hCaptcha — they're everywhere. Playwright alone won't help. But pair it with a captcha solving service and you're through.

TL;DR: You send the sitekey and URL to a solving service (like 2Captcha or SolveCaptcha), get back a token, inject it into the page with Playwright, and move on.

When this is useful

  • scraping JS-heavy sites
  • bypassing auth flows or post-login content
  • crawling React/Vue SPAs
  • testing flows that include captchas

Setup

npm install playwright node-fetch dotenv
# .env
API_KEY=your_2captcha_or_solvecaptcha_key

Detect the captcha

Use Chrome DevTools or the captcha bypass extension to find data-sitekey. You'll need:

  • sitekey
  • page URL

Submit captcha to API

const params = {
  "clientKey": "YOUR_API_KEY",
  "task": {
    "type": "RecaptchaV2TaskProxyless",
    "websiteURL": "https://2captcha.com/demo/recaptcha-v2",
    "websiteKey": "6LfD3PIbAAAAAJs_eEHvoOl75_83eXSqpPSRFJ_u",
    "isInvisible": false
  }
};

const res = await fetch('https://api.2captcha.com/createTask', {
  method: 'POST',
  body: JSON.stringify(params),
});

const { taskId } = await res.json();

Poll for solution

const params = {
  clientKey: "YOUR_API_KEY",
  taskId
}

for (let i = 0; i < 20; i++) {
  await new Promise(r => setTimeout(r, 5000));
  const res = await fetch('https://api.2captcha.com/getTaskResult', {
    method: 'POST',
    body: JSON.stringify(params),
  });

  const json = await res.json();
  if (json.status === 'ready') {
    token = json.solution.token;
    break;
  }
}

Inject token in Playwright

await page.evaluate(token => {
  const field = document.querySelector('[name="g-recaptcha-response"]');
  if (field) field.value = token;
  else {
    const el = document.createElement('textarea');
    el.name = 'g-recaptcha-response';
    el.style.display = 'none';
    el.value = token;
    document.body.appendChild(el);
  }
}, token);

Then click the button or trigger submit:

await page.click('#submit-button');

Full script

Use Google demo page to test:

const { chromium } = require('playwright');
// see full working example above (same structure)

Notes

  • Works with 2Captcha, SolveCaptcha (same format)
  • SolveCaptcha can be faster on some sites, and supports other types too
  • Don’t reuse old tokens — they expire fast
  • Invisible captchas might auto-submit after token injection

Problems?

  • UNSOLVABLE? Retry with new captchaId
  • CAPCHA_NOT_READY forever? Wrong sitekey or expired token
  • Page does nothing after injection? You missed a JS trigger or need to submit manually

Done.

This isn’t fancy — it’s just reliable. SolveCaptcha or 2Captcha + Playwright will take you through most captchas. Production ready? Depends on your IP pool and solve delay. But it works.

Use proxies. Parallelize solves. Inject and go. Done.