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

HTML
<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

JavaScript
grecaptcha.ready(() => {
  grecaptcha.execute("6Lc…", { action: "signup" }).then((token) => send(token));
});

AgentGate widget

HTML
<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()

JavaScript
AgentGate.init({ siteKey: "site_…", endpoint: "https://agentgate.example" }); // at page load
const { token } = await AgentGate.execute({ action: "signup" });               // at submit
send(token);
reCAPTCHAAgentGateNotes
class="g-recaptcha"class="agentgate"
data-sitekeydata-sitekey
v3 actiondata-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), v3data-mode="invisible" (default)the check appears only when needed
data-callback, data-expired-callback, data-error-callbackcallback, expiredCallback, errorCallback options of AgentGate.render()no callback attributes on the declarative widget
g-recaptcha-response fieldagentgate_token field
grecaptcha.execute(key, {action})AgentGate.execute({action})call AgentGate.init() at page load first
grecaptcha.render, reset, getResponseAgentGate.render, reset, getResponse; plus remove
hl parameterdata-langeight languages
data-theme, data-size, data-badgenoneno 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)

Python
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)

Python
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()
reCAPTCHAAgentGateNotes
secret (form field)Authorization: Bearer ags_…or a secret JSON field
responsetoken
remoteipnone
form-encoded bodyJSON body
successsuccess
score (v3)nonethe rules decide; see below
action (v3)action; enforce with expectedActiona mismatch is refused (action_mismatch)
hostnameorigin; enforce with expectedOrigin
challenge_tsissuedAt (Unix milliseconds)
error-codeserrorinvalid-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 wouldDecision and the labels on the dashboard;
  • switch rules you are unsure about to count with 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.

View as Markdown