Challenge migration guide

Migrate from reCAPTCHA to Botpoison Challenge

Three edits: swap the script, move the key onto the form, and replace the siteverify call with one verify call. Your form keeps its fields, its layout and its thank-you page. The same edits work for the v2 checkbox, the invisible badge and v3.

Last verified

Migrate this project's forms from reCAPTCHA to Botpoison Challenge.
Follow the guide at https://botpoison.com/migrate/from-recaptcha.md
Make the three edits it describes, and keep the form's fields and routes.

Why sites move off reCAPTCHA

Google has moved every reCAPTCHA key into a Google Cloud project, finishing in early 2026. The first 10,000 assessments a month stay free. Past that, a key without billing set up stops returning scores until the next month.

In the EU, the French data protection authority and an Austrian court have both dealt with reCAPTCHA and consent. reCAPTCHA and the GDPR sets out what each one decided.

And the v2 checkbox still asks some visitors to pick out images, the one task many people with low vision or a screen reader cannot do.

What maps to what

Script
reCAPTCHAgoogle.com/recaptcha/api.js
Challengeunpkg.com/@botpoison/browser
On the form
reCAPTCHAA g-recaptcha div with data-sitekey
Challengedata-botpoison-public-key on the form itself
Field posted
reCAPTCHAg-recaptcha-response
Challenge_botpoison
Server check
reCAPTCHAPOST to /recaptcha/api/siteverify with the secret and the response
ChallengeThe same form POSTed to /verify, with secretKey and solution
Result
reCAPTCHAsuccess, and on v3 a score from 0.0 to 1.0
Challengeok, true or false

The three edits. Off reCAPTCHA, onto Challenge

Swap the script

Remove Google's script tag and add ours. It loads async, like theirs did.

HTML
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<script src="https://unpkg.com/@botpoison/browser" async></script>

Swap the key on the form

Delete the widget's div and put your public key on the form itself. Nothing renders in its place.

HTML
<form
action="/contact"
method="POST"
data-botpoison-public-key="pk_xxxxxxxx"
>
<textarea name="message"></textarea>
<div class="g-recaptcha" data-sitekey="your_site_key"></div>
<button type="submit">Send</button>
</form>

Swap the check on your server

Post the same form to /verify: secretKey and _botpoison in place of secret and g-recaptcha-response, and ok in place of success.

JavaScript
const google = await fetch("https://www.google.com/recaptcha/api/siteverify", {
const verified = await fetch("https://api.botpoison.com/verify", {
method: "POST",
body: new URLSearchParams({
secret: process.env.RECAPTCHA_SECRET,
response: req.body["g-recaptcha-response"],
secretKey: process.env.BOTPOISON_CHALLENGE_SECRET_KEY,
solution: req.body._botpoison,
}),
});
const { success: ok } = await google.json();
const { ok } = await verified.json();
if (!ok) return res.status(403).end();

What behaves differently

No widget. Nothing renders on the page, so remove any CSS or layout space kept for the checkbox or the badge.

Nothing runs on page load. The check starts when the visitor presses Send, so a visitor who never submits costs nothing.

No score to tune on v3. Challenge answers pass or fail. If you used the v3 score to catch spam that people type, pair Challenge with Classify, which scores the message itself.

Questions

Do I still need a Google Cloud project?

No. Once the three edits ship, nothing on the form calls Google.

I use the invisible badge. Is this different?

The same three edits apply. The button that carried the g-recaptcha class goes back to a plain submit button.

Does it work with my framework?

Yes. The Challenge getting started guide has a tab each for plain HTML, JavaScript, React, Vue, Angular and Svelte.

Sources

reCAPTCHA is a trademark of Google. Botpoison is not affiliated with Google.

Other migration guides

To Challenge

Invisible CAPTCHA alternative
  • Drop the cf-turnstile widget. The check runs fresh on each Send and moves to one verify call.

  • Remove the h-captcha div and the form-encoded siteverify request. Nobody labels images again.

To Classify

Spam classifier
  • comment-check answers "true" or "false" as text. Classify answers a label, and a score to hold the borderline ones on.

  • A score from 0 to 6 against your threshold becomes a label, with the score kept for a review queue.

Switch to Challenge for free

Stop spam now
No credit card required
Three edits
Your fields stay as they are
Free to start