Challenge migration guide

Migrate from Turnstile to Botpoison Challenge

Three edits: swap Cloudflare's script for ours, 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.

Last verified

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

Why sites move off Turnstile

Turnstile is free and often invisible, so the reasons to move off it are narrower than with a puzzle CAPTCHA.

Turnstile gets its token when the page loads. Challenge runs its check fresh on each Send, so there is no token to expire while someone fills in a long form.

The free plan allows 20 widgets, 10 hostnames for each, and keeps Cloudflare's branding on the widget.

And Turnstile only answers whether the browser looks like a person. Spam a person types still arrives. Botpoison puts Classify for that on the same plan.

What maps to what

Script
Turnstile/turnstile/v0/api.js on challenges.cloudflare.com
Challengeunpkg.com/@botpoison/browser
On the form
TurnstileA cf-turnstile div with data-sitekey
Challengedata-botpoison-public-key on the form itself
Field posted
Turnstilecf-turnstile-response
Challenge_botpoison
Server check
TurnstilePOST to /turnstile/v0/siteverify with the secret and the response
ChallengeThe same form POSTed to /verify, with secretKey and solution
Result
Turnstilesuccess, with the action and cdata the widget carried
Challengeok, true or false

The three edits. Off Turnstile, onto Challenge

Swap the script

Remove Cloudflare's script tag and add ours. Ours can be cached or served from your own domain.

HTML
<script src="https://challenges.cloudflare.com/turnstile/v0/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="cf-turnstile" 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 cf-turnstile-response, and ok in place of success.

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

What behaves differently

No widget. Nothing renders on the page, so there is no widget size, theme or language to set.

The check runs on Send. Turnstile renders and runs when the page loads. Challenge starts when the visitor presses Send, so nothing runs for a visitor who never submits.

No render calls. If your code called turnstile.render(), the attribute on the form replaces it, or use the browser library from JavaScript for a form you submit yourself.

Questions

Do I need to change anything on Cloudflare?

No. Turnstile works whether or not a site runs on Cloudflare, and so does Challenge. Your DNS, proxy and firewall rules stay as they are.

Can I keep the firewall in front of the site?

Yes. Challenge runs in the browser and is checked by your server, so whatever sits in front of the site is not involved.

Moving from reCAPTCHA or hCaptcha instead?

See the guides from reCAPTCHA and from hCaptcha.

Sources

Turnstile is a trademark of Cloudflare. Botpoison is not affiliated with Cloudflare.

Other migration guides

To Challenge

Invisible CAPTCHA alternative
  • v2 checkbox, v2 invisible or v3 score. Swap the script, the key and the siteverify 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