Migrate from reCAPTCHA
Replace Google reCAPTCHA v2 or v3 with AgentGate: widget, execute() and siteverify mapped, and what replaces the v3 score.
reCAPTCHA v2 (checkbox or invisible) and v3 (score) both map onto AgentGate's widget and /v1/siteverify. The biggest change is that AgentGate returns a decision, not a score: your server checks success, and the thresholds live in AgentGate's rules.
Note
reCAPTCHA names below are from Google's public documentation for reCAPTCHA v2 and v3 (not reCAPTCHA Enterprise). Check them against the version you use.
1. Create a site
Add your site in the console with every origin that serves the form, and one action per form. You get a site key (site_…) and a backend secret (ags_…).
2. Swap the widget
reCAPTCHA v2
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<form method="post" action="/signup">
<div class="g-recaptcha" data-sitekey="6Lc…" data-callback="onToken"></div>
<button>Sign up</button>
</form>reCAPTCHA v3
grecaptcha.ready(() => {
grecaptcha.execute("6Lc…", { action: "signup" }).then((token) => send(token));
});AgentGate widget
<script src="https://agentgate.example/sdk/v1/agentgate.js" async></script>
<form method="post" action="/signup">
<div class="agentgate" data-sitekey="site_…" data-action="signup"></div>
<button>Sign up</button>
</form>AgentGate execute()
AgentGate.init({ siteKey: "site_…", endpoint: "https://agentgate.example" }); // at page load
const { token } = await AgentGate.execute({ action: "signup" }); // at submit
send(token);| reCAPTCHA | AgentGate | Notes |
|---|---|---|
class="g-recaptcha" | class="agentgate" | |
data-sitekey | data-sitekey | |
v3 action | data-action / execute({action}) | required in every mode; configured on the site |
| checkbox (v2) | data-mode="interactive" | always shows the press-and-hold check |
data-size="invisible" (v2), v3 | data-mode="invisible" (default) | the check appears only when needed |
data-callback, data-expired-callback, data-error-callback | callback, expiredCallback, errorCallback options of AgentGate.render() | no callback attributes on the declarative widget |
g-recaptcha-response field | agentgate_token field | |
grecaptcha.execute(key, {action}) | AgentGate.execute({action}) | call AgentGate.init() at page load first |
grecaptcha.render, reset, getResponse | AgentGate.render, reset, getResponse; plus remove | |
hl parameter | data-lang | eight languages |
data-theme, data-size, data-badge | none | no badge to place; system colours |
In your CSP, replace the Google hosts (www.google.com, www.gstatic.com, and frame-src for the iframe) with your AgentGate endpoint in script-src and connect-src, plus worker-src blob:.
3. Swap the server call
Before (reCAPTCHA)
r = requests.post("https://www.google.com/recaptcha/api/siteverify",
data={"secret": SECRET, "response": token, "remoteip": ip})
v = r.json()
if not v["success"] or v.get("score", 1) < 0.5 or v.get("action") != "signup":
reject()After (AgentGate)
r = requests.post("https://agentgate.example/v1/siteverify",
headers={"Authorization": "Bearer " + os.environ["AGENTGATE_SECRET"]},
json={"token": token, "expectedAction": "signup",
"expectedOrigin": "https://app.example.com", "requestId": op_id},
timeout=5)
v = r.json()
if v.get("success") is not True:
reject()| reCAPTCHA | AgentGate | Notes |
|---|---|---|
secret (form field) | Authorization: Bearer ags_… | or a secret JSON field |
response | token | |
remoteip | none | |
| form-encoded body | JSON body | |
success | success | |
score (v3) | none | the rules decide; see below |
action (v3) | action; enforce with expectedAction | a mismatch is refused (action_mismatch) |
hostname | origin; enforce with expectedOrigin | |
challenge_ts | issuedAt (Unix milliseconds) | |
error-codes | error | invalid-input-secret → invalid_credential, invalid-input-response → invalid_token, timeout-or-duplicate → expired_token or token_used, bad-request → invalid_request |
Both products make tokens single use and expire them after two minutes.
4. Where the score went
reCAPTCHA v3 leaves the threshold to you. AgentGate decides: a token is only issued when the site's rules allow the visit (after the visible check if one was needed), so success: true already means "passed". To tune:
- start in monitor mode and read
wouldDecisionand the labels on the dashboard; - switch rules you are unsure about to
countwith overrides (managed rule groups); - use the interactive widget where v2's checkbox was a deliberate step.
Testing: replace Google's test keys with the AgentGate testing keys.