Stop contact form spam

Stop contact form spam6 min read

reCAPTCHA alternatives for website forms

Compare reCAPTCHA alternatives for forms, from Turnstile and hCaptcha to proof-of-work and no captcha at all, then switch with a small, safe change.

Preet SutharFounder, Ikiform

Cloudflare Turnstile is the closest swap for reCAPTCHA: it is mostly invisible, uses the same site key and secret key pattern, and its server check takes the same parameters. hCaptcha suits sites that want image challenges from someone other than Google, and proof-of-work tools such as ALTCHA run with no third party at all. For many contact forms, a honeypot, content scoring and a rate limit make a captcha unnecessary.

Why people move off reCAPTCHA

reCAPTCHA still works. The reasons to replace it are usually about cost to visitors and to you. Version 2 shows image puzzles to some visitors, which is slow on phones and hard for people using screen readers. Version 3 is invisible but returns a score you must threshold yourself, with no challenge to fall back on. And reCAPTCHA is now a Google Cloud product: Google's billing docs list a free allowance of 10,000 assessments a month, with paid tiers above it.

Some teams also want fewer third-party scripts on their pages. Whether that matters for your privacy obligations is a question for your own legal review; this page only compares how the tools work.

The alternatives compared

OptionWhat visitors seeWho verifiesWorth knowing
reCAPTCHA v2A checkbox, sometimes image puzzlesYour server, with GoogleFamiliar. The puzzles are the main complaint
reCAPTCHA v3NothingYour server, with GoogleReturns a score from 0.0 to 1.0. You pick the cut-off and handle the grey zone
Cloudflare TurnstileUsually nothing, sometimes a checkboxYour server, with CloudflareNo image puzzles. No cost for up to 20 widgets
hCaptchaA checkbox, sometimes image puzzlesYour server, with hCaptchaSimilar to reCAPTCHA v2 in shape, from a different company. A free Basic plan, with paid Pro and Enterprise plans
Friendly CaptchaA small widget that solves a puzzle in the backgroundYour server, with Friendly CaptchaProof of work instead of tracking signals. Free for small non-commercial sites, paid plans for everyone else
ALTCHAA small widget that solves a puzzle in the backgroundYour own server onlyOpen source and self-hosted, so no third party. You run and maintain it
No captchaNothingYour serverHoneypot, signed timing, content scoring and rate limits. Stops most bots, not all

Every option except the last still depends on a server-side check. A widget on its own stops nothing, because a bot can post to your endpoint without loading the page.

What each option asks of people

Judge every option by the visitor who has the hardest time with it. Image puzzles are slow on a phone and hard or impossible for someone who can't see them well; audio fallbacks help some people and frustrate others. Invisible checks, like Turnstile's usual mode, reCAPTCHA v3 and proof-of-work widgets, ask nothing of most visitors, but they can still fail for people on privacy-focused browsers, strict networks or old devices. When that happens, the person needs a way forward: a visible checkbox, a clear message, or an email address to write to instead. A form that fails silently loses exactly the messages you never hear about.

Choose in two questions

Choosing a reCAPTCHA replacement in two questionsStart hereNo server: a static site or a builderdo bots getpastinvisiblechecks?can you runserver code?your own widgetTurnstile, hCaptcha orALTCHAstay captcha-freehoneypot, scoring, ratelimitform posts to abackendbackend verifiesyour keysTurnstile only, withIkiformor a managed checkno keys at allyesyesnoChoosing a reCAPTCHA replacement in two questionsStart hereNo server: a static site or a builderdo bots getpastinvisiblechecks?can you runservercode?your own widgetTurnstile, hCaptchaor ALTCHAstaycaptcha-freehoneypot,scoring,rate limitform posts to abackendbackendverifies yourkeysTurnstile only, withIkiformor a managedcheckno keys at allyesyesno
  1. First ask whether bots get past invisible checks. If not, stay captcha-free with a honeypot, scoring and a rate limit.
  2. If they do, ask whether you can run server code. If you can, pick a widget such as Turnstile, hCaptcha or ALTCHA and verify it on your server.
  3. Without a server, post the form to a backend that verifies your Turnstile keys for you, or use a managed check that needs no keys.
Most contact forms stop at the first question. Measure your spam before you add any widget.

Switch from reCAPTCHA to Turnstile

The two are close enough that the switch is a few lines on each side. Create a Turnstile widget in the Cloudflare dashboard for the same hostnames, then change the markup and the server check together.

PiecereCAPTCHA v2Turnstile
Scripthttps://www.google.com/recaptcha/api.jshttps://challenges.cloudflare.com/turnstile/v0/api.js
Element<div class="g-recaptcha" data-sitekey><div class="cf-turnstile" data-sitekey>
Token fieldg-recaptcha-responsecf-turnstile-response
Verify URLhttps://www.google.com/recaptcha/api/siteverifyhttps://challenges.cloudflare.com/turnstile/v0/siteverify
Verify parameterssecret, response, remoteipsecret, response, remoteip, idempotency_key
<form action="/api/contact" method="POST">
  <input name="email" type="email" required />
  <textarea name="message" required></textarea>
  <div class="g-recaptcha" data-sitekey="RECAPTCHA_SITE_KEY"></div>
  <button>Send</button>
</form>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
const form = await request.formData();
const body = new URLSearchParams({
  secret: process.env.RECAPTCHA_SECRET_KEY!,
  response: String(form.get("g-recaptcha-response") ?? ""),
});
const check = await fetch("https://www.google.com/recaptcha/api/siteverify", { method: "POST", body });
const { success } = (await check.json()) as { success: boolean };
  • This covers classic reCAPTCHA keys, verified at siteverify. Keys created in Google Cloud are checked through the reCAPTCHA Enterprise assessments API instead; the Turnstile side is the same.
  • If you used v3, remove your score threshold. Turnstile answers pass or fail; check action in its answer instead.
  • Update your Content Security Policy: allow https://challenges.cloudflare.com in script-src and frame-src, and drop the Google entries once nothing uses them.
  • Ship the markup and the server change in one deploy. A page with the new widget posting to a server that still expects g-recaptcha-response fails every submission.

Replacing reCAPTCHA with Ikiform

If your form posts to Ikiform, remove the reCAPTCHA widget entirely. Ikiform doesn't verify reCAPTCHA or hCaptcha tokens. The leftover g-recaptcha-response value would arrive as an extra field, or fail with 422 validation_failed as an unknown field if you defined the form's fields. Then pick what replaces it:

  • Nothing extra. The honeypot, content scoring and rate limits run on every form. Many contact forms need no more.
  • Spam check set to Ikiform. Cloudflare Turnstile, run by Ikiform, with no account or keys. A plain HTML post gets a short check page; fetch code calls challenge() from @ikiform/sdk.
  • Your own Turnstile keys. Keep your own widget on the page, paste the keys into the form's settings, and Ikiform verifies the token.
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="POST">
  <input name="email" type="email" required />
  <textarea name="message" required></textarea>
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Send</button>
</form>

That form has no widget at all. With Spam check set to Ikiform, the human check happens on ikiform.com after the post, so your page loads no captcha script. The spam docs cover each mode.

If you are moving off a hosted form service at the same time, the comparison pages for Formspree and Netlify Forms cover what else changes.

Check it works

  1. Submit the form after the switch. The post is accepted and you saw at most a checkbox.
  2. Post to the endpoint with curl and no token. It is refused, which proves the server checks the new token.
  3. Search your pages for g-recaptcha and recaptcha/api.js. Nothing is left.
  4. Open Submissions in the dashboard. The new submission is there with every field you sent.
  5. Nothing arrived? Switch the dashboard's status filter to Spam. Spam gets the same success answer as a real submission.

Gotchas

  • Builder settings. Site builders with a built-in reCAPTCHA setting may require the element on every form while it is on. Turn the setting off before you remove the elements.
  • Cached pages. Visitors with an old cached page still send g-recaptcha-response for a while after you deploy. Expect a few failures, or accept both tokens for a day.
  • v3 scores in reports. If dashboards or alerts read the reCAPTCHA score, they go quiet after the switch. Update them.

Questions

Stuck on a step, or want a guide for your situation? Email hello@ikiform.com.