Solve reCAPTCHA Enterprise with Node.js
Use the official solvethree JavaScript SDK on Node.js 22+. Configure an active site profile, supply the site's hostname and action, and solve through a proxy. The SDK returns the token and browser identity; your application submits them to the target.
On this page
Install the SDK and configure the site
Install the official package directly from solvethree.com:
npm install https://solvethree.com/downloads/solvethree-sdk-0.1.0.tgz- 1.
Activate the site profile
Set up the target site in the console and make sure its profile is active and available to your workspace. Sending a hostname and action doesn't create a profile. See site profile setup.
- 2.
Set the server environment
Set SOLVETHREE_API_KEY to your workspace API key and SOLVETHREE_PROXY to your proxy URL in the environment of the Node.js process. Keep the API key on the server; don't expose it in browser code.
- 3.
Prepare the script
Save the next example as solve.mjs. Replace accounts.example.com with your configured hostname and login with the page's actual reCAPTCHA action.
Request the Enterprise token
Use a hostname for site, not a page URL. reCAPTCHA defaults to enterprise-v3, so the example doesn't need recaptchaType. Don't add type or url. The request requires exactly one of proxy or proxyCandidates; this example uses a single proxy.
import { randomUUID } from 'node:crypto';
import { Solvethree, SolvethreeError, TaskFailedError } from '@solvethree/sdk';
const client = new Solvethree({ apiKey: process.env.SOLVETHREE_API_KEY });
const request = {
site: 'accounts.example.com', // Use your configured hostname.
action: 'login', // Use the page's actual action.
proxy: process.env.SOLVETHREE_PROXY,
requestId: randomUUID(),
};
let result;
try {
result = await client.solve(request, { timeoutMs: 180_000 });
} catch (error) {
if (error instanceof TaskFailedError) {
throw new Error(`Task failed: ${error.errorCode}`);
}
if (error instanceof SolvethreeError) {
// Save these IDs; use them to recover the existing task.
console.error({ requestId: error.requestId, taskId: error.taskId });
}
throw error;
}
const { token, userAgent, secChUa } = result.solution;
console.log('Ready task:', result.id); // Keep solution credentials private.Run the script with Node.js after setting the environment variables. solve creates the task once and polls until it is ready or throws. The 180,000 ms timeout limits how long the client waits.
The returned fields have different jobs:
result.ididentifies the task. It isn't the CAPTCHA token.result.solution.tokenis the value to submit in the application's CAPTCHA field.result.solution.userAgentandresult.solution.secChUaare the browser identity to use with that token.
Keep solution values private. If you need recovery after a process restart, save the requestId and exact task inputs before calling solve, with any proxy credentials protected.
Submit through the same proxy
Continue in the same script after solve returns. This example uses undici, which you must install separately as its comment describes. It sends the token through request.proxy and uses both returned browser identity fields.
// Continue after client.solve(). Install undici separately: npm install undici@7.
import { fetch, ProxyAgent } from 'undici';
const dispatcher = new ProxyAgent(request.proxy);
try {
// Replace the URL and form fields with your application's contract.
const response = await fetch('https://accounts.example.com/login', {
method: 'POST',
dispatcher,
redirect: 'manual',
headers: {
'user-agent': result.solution.userAgent,
'sec-ch-ua': result.solution.secChUa,
},
body: new URLSearchParams({
'g-recaptcha-response': result.solution.token,
}),
signal: AbortSignal.timeout(30_000),
});
console.log('Application HTTP status:', response.status);
await response.arrayBuffer();
} finally {
await dispatcher.close();
}Replace the URL and form fields with your application's contract. The example supplies only g-recaptcha-response; include whatever other fields and session data the application requires. Keep the target consistent with the site and action you solved.
Because the solve request uses one proxy, reusing request.proxy keeps the submission on that proxy. If you change the request to use proxyCandidates, select the winning proxy with the SDK's successfulProxy helper instead.
A ready task means a solution was generated, not that the target accepted your application request. Check the target's response for its actual success condition; printing an HTTP status isn't enough. For rejection diagnostics, see ready token rejected.
Handle failures and recover interrupted requests
The solve example separates terminal task failures from other SDK errors. Keep that distinction: a failed task and a failed HTTP request need different handling.
- solve throws TaskFailedError
The exception includes errorCode and taskId. Call getTask(taskId) if you need the full failed-task response, including its error text.
Try this: Stop polling that task and address the reported cause before creating another. Don't retry unchanged invalid inputs.
- A SolvethreeError includes taskId
The SDK has an ID for the existing task.
Try this: Resume polling with getTask. Continue for pending or solving, use the solution only when ready, and stop on failed.
- Creation is interrupted and only requestId is available
A connection timeout doesn't prove the task wasn't created.
Try this: Recover with createTask using the identical task inputs and the same requestId. Reusing that ID with different inputs conflicts.
- The API rejects an HTTP request
Inspect the HTTP status exposed by ApiError rather than treating the response as a ready or failed task.
Try this: Address the HTTP error before processing a success payload. Don't assume every failure is insufficient credit.
The sample generates a fresh requestId every time the program starts. Rerunning it unchanged isn't recovery: use your saved request and IDs instead. The SDK never automatically retries task creation; it does honor Retry-After for temporary polling failures within the solve deadline.
For explicit polling and wait settings, see task polling and timeouts.
Sources and API reference
Run your first task.
Start with $5 in workspace credit.