Use a CAPTCHA solver with Playwright
Solve the reCAPTCHA Enterprise task first, then submit solution.token through your application's form in Playwright. Use the same proxy and the returned browser identity for that browser request.
The example below targets an owned HTTPS form with a known token field and Submit button. It's an explicit SDK-to-form handoff, not a browser plugin.
On this page
Prepare the dependencies and owned page
- 1.
Install Node.js 22+, Playwright and Chromium
Install the
playwrightpackage and its Chromium browser binary. Install the official solvethree JavaScript SDK using the downloadablesolvethree-sdk-0.1.0.tgzpackage; the Node.js integration instructions provide its direct-download installation command. - 2.
Configure the hostname in solvethree
Your owned HTTPS page's hostname must have an active reCAPTCHA profile available to your workspace. Set that up in the console before running the example. Sending a hostname and action in a task doesn't create the profile.
- 3.
Set the three environment variables
Set
TARGET_URLto your complete owned HTTPS page URL,SOLVETHREE_PROXYto the proxy URL, andSOLVETHREE_API_KEYto your workspace API key. Run the script server-side; don't put the API key in page JavaScript. The example uses the actionlogin, which you must change if your application uses a different action. - 4.
Provide the example form
The page must contain a textarea named
g-recaptcha-responseand a button whose accessible name is exactlySubmit. If your form differs, adapt the handoff described below before running it.
The task's proxy and Playwright's browser proxy are configured separately. A browser context proxy does not automatically route the SDK's server-side API requests. This example supplies one proxy to the task and reuses it for the browser's target traffic.
Solve, then submit through Playwright
// Install playwright and the official solvethree SDK first.
import { chromium } from 'playwright';
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 chromium.launch();
try {
const context = await browser.newContext({
proxy: {
server: `${proxy.protocol}//${proxy.host}`,
username: decodeURIComponent(proxy.username),
password: decodeURIComponent(proxy.password),
},
userAgent: result.solution.userAgent,
extraHTTPHeaders: { 'sec-ch-ua': result.solution.secChUa },
});
const page = await context.newPage();
await page.goto(target.href);
// This example form has this field and a button named Submit.
// Adapt the selectors/callback to your own application's form contract.
await page.locator('[name="g-recaptcha-response"]').waitFor({ state: 'attached' });
await page.locator('[name="g-recaptcha-response"]').evaluate((field, token) => {
field.value = token;
field.dispatchEvent(new Event('input', { bubbles: true }));
}, result.solution.token);
await Promise.all([
page.waitForResponse(response =>
response.request().method() === 'POST' &&
new URL(response.url()).origin === target.origin),
page.getByRole('button', { name: 'Submit', exact: true }).click(),
]);
// Check your application's success response here.
} finally {
await browser.close();
}solve creates the task once and polls until it is ready or throws. The browser starts only after that call succeeds. Its context uses the original proxy, including any URL-encoded credentials, and the returned solution.userAgent and solution.secChUa.
The form receives solution.token, not the task ID. The example waits for the field to be attached because a token textarea need not be visible. It assigns the token, dispatches an input event, then clicks Submit.
TARGET_URLbelongs to your application. The solver task receives its hostname assite; Playwright navigates to the complete URL.loginis the example's action. Replace it with the action used by your application.[name="g-recaptcha-response"]is the example's token-field selector. Replace it if your application expects the token in another field or request parameter.Submitis the example button's accessible name. Replace that locator, or use your application's actual submission path.- The input event is part of this demo's handoff. A real application may also require a callback, application state update, CSRF value or existing session. There is no universal token-fill callback.
If the form doesn't accept the token
Before paying for another solve, inspect the outgoing application request using Playwright's request and response observation. A ready task means a solution is available; the application's response tells you whether the submission was accepted.
- The submitted token is missing or unchanged.
Inspect the actual request parameter, not just the textarea's value.
Try this: Pass
solution.tokenthrough the application's real submission path. Updating the demo field won't help if the application builds its request from separate state.- The request contains the token but is rejected.
Compare the submission's proxy, user agent, client hints, target hostname and action with the solve. Check the application's session and CSRF requirements.
Try this: Keep the solve and submission on the same proxy, apply the returned browser identity, and satisfy the application's form requirements before submitting.
- The script fails before opening the browser.
Distinguish an HTTP request error from a terminal failed task. For a failed task, inspect
errorCodeanderror.Try this: Correct the reported input, profile or connectivity problem rather than repeatedly submitting unchanged inputs. The SDK throws on failure; don't continue to the token-fill step.
Sources and API reference
Run your first task.
Start with $5 in workspace credit.