How to Solve reCAPTCHA v3 in Node.js and Set an Action

solve recaptcha v3 in node.js - How to Solve reCAPTCHA v3 in Node.js and Set an Action

reCAPTCHA v3 never shows a puzzle. It scores the visit silently and hands the page a token, which the site verifies on its own backend. From your side there is nothing to click, so the entire job is producing a token the site will accept. In Node.js that is the same recaptcha method used for v2, with one extra option.

The detail that decides whether it works is the action.

Setup

npm install capskip
const { CapSkip } = require('capskip');

const solver = new CapSkip({
  host: '127.0.0.1',
  port: 8080,
  recaptchaTimeout: 300,   // seconds, shared with Turnstile and GeeTest
});

CapSkip runs locally, so the desktop app needs to be open before any call succeeds.

The basic call

const result = await solver.recaptcha(
  '6Lc...YOUR_SITEKEY',
  'https://example.com/checkout',
  { version: 'v3', action: 'submit' },
);

console.log(result.code);   // the v3 token

Two differences from v2: version: 'v3' is required, and action should match what the page passes to grecaptcha.execute. Leave it out and it defaults to verify.

Why the action matters

Actions are labels a site attaches to each protected interaction so a login and a checkout can be scored independently. Most backends check that the action on the token matches the one they expected for that endpoint.

Send the wrong label and the token is genuine but arrives tagged for a different interaction, which many verifiers reject. Read the real value from the page rather than guessing:

const html = await (await fetch('https://example.com/checkout')).text();

// Sites normally call execute() with the action as a string literal.
const match = html.match(/execute\([^,]+,\s*\{\s*action:\s*['"]([^'"]+)/);
const action = match ? match[1] : 'verify';

const result = await solver.recaptcha(sitekey, pageUrl, {
  version: 'v3',
  action,
});

Common values are login, submit, homepage and checkout, but they are arbitrary strings chosen by whoever built the site.

Enterprise v3

const result = await solver.recaptcha(sitekey, pageUrl, {
  version: 'v3',
  enterprise: 1,
  action: 'submit',
});

Enterprise is an orthogonal flag rather than a different product, so it simply stacks. Tell the two apart by the script the page loads: Enterprise pulls enterprise.js, standard pulls api.js. A wrong guess fails the solve rather than returning a bad token, so it is cheap to check.

Submitting the token

const response = await fetch('https://example.com/checkout', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    token: result.code,
    orderId: '...',
  }),
});

Unlike v2 there is no standard form widget, so v3 integrations vary. Some use a hidden g-recaptcha-response field, others post JSON with a custom key. Check what the page’s own JavaScript does before assuming a field name.

Solving in bulk

const tokens = await Promise.all(
  urls.map((url) =>
    solver.recaptcha(sitekey, url, { version: 'v3', action: 'submit' })),
);

console.log(tokens.map((t) => t.code));

AsyncCapSkip exists in this package too, but it is an alias of CapSkip. Every method already returns a Promise, so Promise.all is the whole concurrency story in Node.

Errors

const { ApiException, NetworkException } = require('capskip');

try {
  const result = await solver.recaptcha(sitekey, pageUrl, { version: 'v3' });
} catch (err) {
  if (err instanceof NetworkException) {
    // CapSkip is not running on the configured port
  } else if (err instanceof ApiException) {
    // the sitekey or pageurl was rejected
  } else {
    throw err;
  }
}

Frequently asked questions

Can I see the score before submitting?

No. The score stays with Google and is only revealed to the site owner when their backend verifies the token. From the client side you receive a token and nothing else, so there is no way to inspect or filter on a score first.

What if the page has no visible action?

Some pages call execute without one, in which case the default verify is correct. If the regex above finds nothing, that is usually why rather than a parsing failure.

How long does a v3 token last?

Roughly two minutes, single use, same as v2. Solve immediately before the request that needs it rather than building a pool.

Summary

Pass version: 'v3', set action to whatever the page actually executes, add enterprise: 1 when it loads enterprise.js, and submit quickly because the token expires in about two minutes.

Other languages are covered on the reCAPTCHA v3 solver page, Enterprise specifics on the Enterprise solver page, and the wider Node surface on the Node.js CAPTCHA solver page. Watch a real token appear on our v3 demo. CapSkip is a captcha solver that runs on your own machine.