TL;DR: You can’t get a valid, action-bound reCAPTCHA v3 token by POSTing to Google’s internal api2/reload endpoint. The action is bound into the token by Google’s own client script, together with the browser signals that feed the score, and Google’s servers check the action, site key and hostname when you verify. There is no missing parameter to find. If you’re building on reCAPTCHA v3, the approach that works is: call grecaptcha.execute() at the moment of the action, verify the token once on your server within two minutes, and check success, action, hostname and score before you decide anything.
Updated September 2026: Google now runs reCAPTCHA as part of Google Cloud Fraud Defense. Keys are managed in Google Cloud projects, the free tier is 10,000 assessments per month, and the classic siteverify endpoint still works. I’ve refreshed the verification steps, added a working server-side example, and dropped internals that are out of date.
Understanding reCAPTCHA v3 and the “Action” Parameter
reCAPTCHA v3 has no challenge for the user to solve. It runs in the background and returns a risk score from 0.0 to 1.0, where 1.0 is very likely a good interaction and 0.0 is very likely a bot. You tag each token request with an action such as login, checkout or submit_form, so the score is tied to a specific operation on your site. Google’s docs say an action may contain only alphanumeric characters, slashes and underscores, and must not be user-specific.
The action travels through the whole flow. You pass it to the JavaScript API, Google encodes it into the token, and when your backend verifies that token Google sends the action back with the score. Your server compares it with the action it expected. That’s why a token is only good for the action it was requested for, and only for two minutes, and it can be verified once. A common symptom of getting this wrong: a developer adds an action field to a hand-built request, the token comes back identical, and the target server answers with a verification error.
What changed since 2025: reCAPTCHA moved into Google Cloud
If you last touched reCAPTCHA a year ago, three things are different:
- New home, same product. Google’s documentation now describes reCAPTCHA as part of Google Cloud Fraud Defense. Keys live in a Google Cloud project instead of the old standalone admin console, and Google’s migration guide says the move takes 5–10 minutes and needs no code changes.
- Your integration keeps working. Existing client code and the
siteverifycall continue to work after migration. The newer, richer path is the assessments API (projects.assessments.create), which returns the token’s validity, action and hostname plus a risk score and reasons. - The free tier is capped. Google lists 10,000 assessments per month at no cost. Above that you need billing enabled on the Cloud project, so high-traffic forms need a budget line, not just a script tag.
How the reCAPTCHA v3 flow works
To see why a hand-built POST isn’t enough, it helps to have the whole flow in front of you:
Sequence diagram of the reCAPTCHA v3 flow. The browser requests a token for a specific action, your server sends it to Google for verification, and Google returns the score, action and hostname that your server uses to decide.
- The page loads Google’s script. Classic keys use
https://www.google.com/recaptcha/api.js?render=SITE_KEY. Enterprise keys usehttps://www.google.com/recaptcha/enterprise.jsandgrecaptcha.enterprise.execute(). - You call
execute()when the user acts. Google’s guidance is to call it on each action you want to protect, not once at page load, because tokens expire after two minutes. This is the only supported way to attach an action:
grecaptcha.execute('SITE_KEY', { action: 'GetAvailableDaysForOperation' })
.then(function(token) {
// send token to backend
});JavaScriptGetAvailableDaysForOperation is just an example action name here. Use something that describes your own operation.
- Google’s client does its work and returns a token. The script gathers browser and interaction signals for the risk analysis (Google doesn’t publish which) and sets a
_GRECAPTCHAcookie as part of that. In DevTools you’ll see calls toapi2/anchorandapi2/reload. Those are internal endpoints, not a public API. The token it hands back is valid for two minutes and can be verified once. - Your page sends the token to your server along with the form data or API request.
- Your server verifies the token with Google, once:
POST https://www.google.com/recaptcha/api/siteverify
secret=YOUR_SECRET_KEY
response=TOKEN_FROM_USERJavaScript- Google responds with the outcome as JSON, like this:
{
"success": true,
"score": 0.9,
"action": "GetAvailableDaysForOperation",
"challenge_ts": "2025-04-24T03:34:...Z",
"hostname": "your.site.domain"
}JSONThe action in the response is the one requested on the client, and hostname is the site where the token was generated. Compare both with what you expected, otherwise a token minted for a low-stakes action or another site can be replayed against a sensitive one.
- Your backend decides. Based on
success,scoreand the action check, it allows the request, asks for extra verification, or blocks it. Google’s suggested starting threshold is 0.5.
Why a direct HTTP call to /reload doesn’t work
Now the question this post is named for: why does POSTing to https://www.google.com/recaptcha/api2/reload with an action field not give you an action-specific token? Four reasons, and none of them is a parameter you forgot:
- The action isn’t a public API parameter. The supported contract is
grecaptcha.execute(siteKey, { action }). What the client sends toapi2/reloadis internal, undocumented and changes without notice. Anactionfield the endpoint doesn’t define is simply ignored, which is why the token looks the same with or without it. - The score comes from signals a bare HTTP client doesn’t have. Google’s risk analysis is built around a real browser session. A request with none of that context tends to score very low, and sites reject anything under their threshold, even if the action string matches.
- Tokens are bound to the site key, hostname and action. Google returns all three at verification time and a properly written backend checks them. A token that fails any check is rejected.
- Tokens are single-use and short-lived. Google documents a two-minute lifetime and one verification per token. Reusing or caching one gets you
timeout-or-duplicate.
So the only supported way to get an action-bound token is to let Google’s script run in a real page and call execute() there. Skipping the client removes exactly the steps that give the action and the score their meaning.
How to implement reCAPTCHA v3 correctly in 2026
Here’s a server-side check I’d be comfortable shipping. It verifies once, then checks success, action, hostname and score, in that order:
// Node 18+ (built-in fetch)
export async function verifyRecaptcha(token, expectedAction, { minScore = 0.5, expectedHostname } = {}) {
const res = await fetch("https://www.google.com/recaptcha/api/siteverify", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({ secret: process.env.RECAPTCHA_SECRET, response: token }),
});
const data = await res.json();
if (!data.success) return { ok: false, reason: (data["error-codes"] || ["verification-failed"]).join(",") };
if (data.action !== expectedAction) return { ok: false, reason: "action-mismatch" };
if (expectedHostname && data.hostname !== expectedHostname) return { ok: false, reason: "hostname-mismatch" };
if (data.score < minScore) return { ok: false, reason: "low-score", score: data.score };
return { ok: true, score: data.score };
}
If your key is managed in Google Cloud, you can call the assessments API instead. The request carries the token, your site key and the action you expect:
POST https://recaptchaenterprise.googleapis.com/v1/projects/PROJECT_ID/assessments
{
"event": {
"token": "TOKEN_FROM_CLIENT",
"siteKey": "SITE_KEY",
"expectedAction": "checkout"
}
}
// In the response, check:
// tokenProperties.valid -> true
// tokenProperties.action -> "checkout"
// riskAnalysis.score -> 0.0 to 1.0
Checklist before you ship:
- Call
execute()when the user acts, so the token is fresh, and verify it exactly once. - Check
actionandhostname, not justscore. - Keep the secret key on the server. Never put it in client code.
- Don’t fail open. If Google’s API times out, decide deliberately what happens instead of letting everything through.
- Log the score for every request, so you can see the real distribution before you pick a threshold.
- Handle
timeout-or-duplicateby asking the client for a fresh token, not by retrying the same one.
Testing without fighting the system
reCAPTCHA v3 relies on seeing real traffic, so automated tests behave differently from users. Google’s guidance is to use a separate key for development and testing. For v2, Google publishes test keys that always pass. For score-based keys in Google Cloud, you can create a key “for testing purposes only” and set the score it returns, which lets you test your low-score path deterministically. Google also notes that scores in staging environments and in the first days after implementation can differ from long-term production scores, so don’t tune thresholds on that data.
The product decisions behind the code
The threshold isn’t an engineering constant. It’s a trade-off between abuse and friction, and someone has to own it. If you’re writing a spec for this (my PRD guide has a template), decide these up front:
- Threshold per action. A newsletter signup can tolerate more risk than a password reset or a payment.
- A graduated response. Instead of allow or block, use a middle band that triggers step-up verification such as an email code or a second factor.
- What you measure. Track abuse that gets through and real users you block. Without the second number you’ll tighten the threshold until conversion drops.
- Cost and quota. With 10,000 free assessments a month, forms on high-traffic pages can cross the line. Budget for it, or protect only the actions that matter.
- Privacy and consent. reCAPTCHA loads Google scripts and sets a cookie, so check that your consent flow and privacy policy cover it.
Ethical and legal considerations
Trying to get tokens out of someone else’s reCAPTCHA without their client running can breach the target site’s terms and Google’s, and in some jurisdictions it can be unlawful. It’s a security control, and the point of this post is to explain why it works, not to help you get around it. On systems you own, use test keys. If you need to load-test a flow, agree with your team on an allow-listed path instead of trying to defeat the check.
Conclusion
The action in reCAPTCHA v3 isn’t a request parameter you can add to a raw call. It’s part of a client-to-server contract that Google enforces when you verify the token. To get action-specific tokens, let the official client run in your page, verify each token once on your server, and check the action, hostname and score before you act on the result.
The plumbing has moved to Google Cloud, but that contract hasn’t changed. Related reading on this site: preventing SQL injection in WordPress and why an SSL certificate isn’t enough to secure your site.