Use a CAPTCHA solver with Puppeteer
Use the official JavaScript SDK to obtain a reCAPTCHA v3 Enterprise token, then pass solution.token to your form through Puppeteer. The SDK solves the task; it doesn't apply the solution to a browser or provide a browser plugin.
The example below targets an owned HTTPS form with a g-recaptcha-response textarea and a submit button. Those are the demo's form requirements, not a universal interface for reCAPTCHA-protected pages.
On this page
Prepare the dependencies and owned form
- 1.
Install Puppeteer and the SDK
Use Node.js 22 or later. With npm, install
puppeteerand the official SDK tarball athttps://solvethree.com/downloads/solvethree-sdk-0.1.0.tgz. The SDK imports as@solvethree/sdk; use the download URL rather than assuming an npm registry release. Save the example as an ES module, such as a file ending in.mjs. - 2.
Configure the site profile
Set up your owned hostname in the solvethree console and make sure its profile is active for your workspace. Sending a hostname and action doesn't create that profile. The example uses action
login; change it to the action configured for your application. - 3.
Set the environment variables
Set
TARGET_URLto the owned HTTPS form,SOLVETHREE_PROXYto your HTTP or HTTPS proxy URL, andSOLVETHREE_API_KEYto your workspace key. Keep the key in the Node.js process, not in page JavaScript. The example uses one proxy for both solving and browser submission.
The task's site is the hostname extracted from TARGET_URL, not the full page URL. For reCAPTCHA, send site, action and exactly one of proxy or proxyCandidates; don't add a type or url field. This example uses proxy so Puppeteer can use that same proxy directly.
Solve, then open Puppeteer with the same identity
// Install puppeteer and the official solvethree SDK first.
import puppeteer from 'puppeteer';
import { Solvethree } from '@solvethree/sdk';
const target = new URL(process.env.TARGET_URL); // Your configured HTTPS page.
const proxy = new URL(process.env.SOLVETHREE_PROXY);
const client = new Solvethree({ apiKey: process.env.SOLVETHREE_API_KEY });
const result = await client.solve({
site: target.hostname, action: 'login', proxy: process.env.SOLVETHREE_PROXY,
});
const browser = await puppeteer.launch({
args: [`--proxy-server=${proxy.protocol}//${proxy.host}`],
});
try {
const page = await browser.newPage();
if (proxy.username) await page.authenticate({
username: decodeURIComponent(proxy.username),
password: decodeURIComponent(proxy.password),
});
await page.setUserAgent({ userAgent: result.solution.userAgent });
await page.setExtraHTTPHeaders({ 'sec-ch-ua': result.solution.secChUa });
await page.goto(target.href);
// Adapt these selectors and any required callback to your own form.
await page.waitForSelector('[name="g-recaptcha-response"]');
await page.$eval('[name="g-recaptcha-response"]', (field, token) => {
field.value = token;
field.dispatchEvent(new Event('input', { bubbles: true }));
}, result.solution.token);
await Promise.all([
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
page.click('button[type="submit"]'),
]);
// Check your application's success response here.
} finally {
await browser.close();
}client.solve creates the task once and polls until it is ready or throws. Only after it returns does this example launch Puppeteer. The browser uses the task's proxy, authenticates when proxy credentials are present, and applies solution.userAgent and solution.secChUa before navigating.
Don't replace that proxy or browser identity with unrelated values when submitting the token. If you later switch to proxyCandidates, use the SDK's successfulProxy helper to select the winning original proxy for the browser.
If solving fails, inspect the task's errorCode and error rather than retrying unchanged inputs. HTTP request errors are separate from terminal task failures. The finally block closes the local browser after browser work; closing pages isn't a remote task-cancellation mechanism.
Replace the demo's form assumptions
[name="g-recaptcha-response"]selects the demo textarea. Replace it if your application receives the token through another field or request parameter. The value to submit issolution.token, not the task ID.button[type="submit"]selects the demo's submit button. Use your application's actual control or submission mechanism.- The example assigns the token and dispatches an
inputevent. That doesn't replace an application-specific callback. Add any required callback, CSRF value, login fields and session setup before submission. - Replace the final success-check comment with an assertion against your application's response or resulting state. A ready solver task doesn't establish that the application accepted the token.
If you reuse a running browser, choose its BrowserContext deliberately: a new page isn't automatically a separate session. Keep the form's session requirements together rather than mixing pages from unrelated workflows.
Sources and API reference
Run your first task.
Start with $5 in workspace credit.