Skip to content

Puppeteer + CaptchaSonic

Solve reCAPTCHA, Turnstile, and more inside Puppeteer with the CaptchaSonic SDK — solved server-side over gRPC and injected as a token.

Automate captcha solving for headless Chrome in Puppeteer. CaptchaSonic solves the challenge server-side over a native gRPC connection and returns a ready-to-inject token, so your script submits the form as if a human passed the challenge.

TIP

This walkthrough uses the token flow. The repo also ships a script solver (ScriptSolver) for challenges you want solved in-page.

The complete, runnable project lives on GitHub: puppeteer-solver.


Install

npm install captchasonic puppeteer
export CAPTCHASONIC_API_KEY=sonic_your_key_here   # dashboard → API Keys

You need a CaptchaSonic API key with credits (get one, then add funds) and the target page's reCAPTCHA sitekey — found in the page HTML as data-sitekey="…".


Quick start

import puppeteer from 'puppeteer';
import { CaptchaSonic } from 'captchasonic';

// Solves over a native gRPC connection (no HTTP overhead).
const client = new CaptchaSonic(process.env.CAPTCHASONIC_API_KEY);

const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox'] });
const page = await browser.newPage();
await page.goto('https://example.com/login', { waitUntil: 'networkidle2' });

// 1. Read the sitekey from the page.
const sitekey = await page.$eval('[data-sitekey]', (el) => el.getAttribute('data-sitekey'));

// 2. Ask CaptchaSonic for a token (auto-polls, returns when ready).
const result = await client.solveRecaptchaV2Token({
  websiteURL: page.url(),
  websiteKey: sitekey,
});
const token = result.solution.gRecaptchaResponse;

// 3. Inject the token and submit the form.
await page.evaluate((t) => {
  document.getElementById('g-recaptcha-response').innerHTML = t;
}, token);
await page.click('button[type="submit"]');
await browser.close();

How it works

  1. Read the sitekey from the target page (data-sitekey).
  2. SolvesolveRecaptchaV2Token() sends the sitekey and URL to CaptchaSonic over gRPC and resolves once a token is ready.
  3. Inject the returned gRecaptchaResponse into the hidden #g-recaptcha-response field.
  4. Submit the form — the site's handler reads the token exactly as if a human solved the challenge.

The same client solves reCAPTCHA v3, Cloudflare Turnstile, GeeTest, AWS WAF, and image captchas — see the Node.js SDK reference.


Common pitfalls

  • Token bound via callback. Some sites bind the token through a JS callback (data-callback="…") instead of the field. Call that function with the token inside page.evaluate.
  • Token expires before submit. reCAPTCHA tokens live ~120 s — solve as late as possible, right before the submit click.
  • Sitekey differs per environment. Read it from the live page at runtime rather than hard-coding it.
  • Geo-locked validation. Pass a proxy option so the token is solved through your IP when the target validates IP↔token coherence.

See also