# 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.

Published 2026-10-25 · https://ikiform.com/guides/spam-protection/recaptcha-alternatives

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

| Option | What visitors see | Who verifies | Worth knowing |
| --- | --- | --- | --- |
| reCAPTCHA v2 | A checkbox, sometimes image puzzles | Your server, with Google | Familiar. The puzzles are the main complaint |
| reCAPTCHA v3 | Nothing | Your server, with Google | Returns a score from 0.0 to 1.0. You pick the cut-off and handle the grey zone |
| [Cloudflare Turnstile](https://ikiform.com/guides/spam-protection/cloudflare-turnstile.md) | Usually nothing, sometimes a checkbox | Your server, with Cloudflare | No image puzzles. No cost for up to 20 widgets |
| hCaptcha | A checkbox, sometimes image puzzles | Your server, with hCaptcha | Similar to reCAPTCHA v2 in shape, from a different company. A free Basic plan, with paid Pro and Enterprise plans |
| Friendly Captcha | A small widget that solves a puzzle in the background | Your server, with Friendly Captcha | Proof of work instead of tracking signals. Free for small non-commercial sites, paid plans for everyone else |
| ALTCHA | A small widget that solves a puzzle in the background | Your own server only | Open source and self-hosted, so no third party. You run and maintain it |
| [No captcha](https://ikiform.com/guides/spam-protection/without-captcha.md) | Nothing | Your server | Honeypot, 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

Diagram: Choosing a reCAPTCHA replacement in two questions

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.

| Piece | reCAPTCHA v2 | Turnstile |
| --- | --- | --- |
| Script | `https://www.google.com/recaptcha/api.js` | `https://challenges.cloudflare.com/turnstile/v0/api.js` |
| Element | `<div class="g-recaptcha" data-sitekey>` | `<div class="cf-turnstile" data-sitekey>` |
| Token field | `g-recaptcha-response` | `cf-turnstile-response` |
| Verify URL | `https://www.google.com/recaptcha/api/siteverify` | `https://challenges.cloudflare.com/turnstile/v0/siteverify` |
| Verify parameters | `secret`, `response`, `remoteip` | `secret`, `response`, `remoteip`, `idempotency_key` |

**Before** (`contact.html`)

```html
<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>
```

**After** (`contact.html`)

```html
<form action="/api/contact" method="POST">
  <input name="email" type="email" required />
  <textarea name="message" required></textarea>
  <div class="cf-turnstile" data-sitekey="TURNSTILE_SITE_KEY" data-action="contact"></div>
  <button>Send</button>
</form>
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
```

**Before** (`verify.ts`)

```ts
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 };
```

**After** (`verify.ts`)

```ts
const form = await request.formData();
const body = new URLSearchParams({
  secret: process.env.TURNSTILE_SECRET_KEY!,
  response: String(form.get("cf-turnstile-response") ?? ""),
});
const check = await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify", { method: "POST", body });
const { success, action } = (await check.json()) as { success: boolean; action?: string };
const human = success && action === "contact";
```

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

**HTML** (`contact.html`)

```html
<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](https://ikiform.com/docs/spam.md#human-check) cover each mode.

> If you are moving off a hosted form service at the same time, the comparison pages for [Formspree](https://ikiform.com/alternatives/formspree) and [Netlify Forms](https://ikiform.com/alternatives/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

### What is the best alternative to reCAPTCHA?

For most forms, Cloudflare Turnstile: it is usually invisible, costs nothing at small scale and verifies with the same secret and response parameters. If you want no third party at all, a self-hosted proof-of-work tool such as ALTCHA works. Many contact forms need no captcha once a honeypot, scoring and a rate limit are in place.

### Is reCAPTCHA still free?

Google's billing docs list a free allowance of 10,000 assessments a month, with paid tiers above that. Check Google's current pricing before you plan around it.

### Can Ikiform verify reCAPTCHA or hCaptcha tokens?

No. Ikiform verifies Cloudflare Turnstile only, either its own managed check or your own Turnstile keys. Remove other captcha widgets from forms that post to Ikiform.

### Is switching from reCAPTCHA to Turnstile a lot of work?

Usually not. You change the script URL, the element's class, the token field name and the verify URL, and keep the same secret and response parameters. Deploy the page and the server change together.

## More guides

- [Stop contact form spam](https://ikiform.com/guides/spam-protection.md): Stop contact form spam with layers that cost real people nothing: a honeypot, timing, content scoring, rate limits and a human check only where needed.
- [Cloudflare Turnstile](https://ikiform.com/guides/spam-protection/cloudflare-turnstile.md): Add Cloudflare Turnstile to a plain HTML form: the widget, server-side siteverify, test keys, and a way to run it with no keys or server of your own.
- [Without a captcha](https://ikiform.com/guides/spam-protection/without-captcha.md): Stop most form spam with no captcha at all: a honeypot, a signed render time, a content score and a rate limit, added together instead of used alone.
- [Honeypot field](https://ikiform.com/guides/spam-protection/honeypot.md): Add a honeypot to any form that catches bots without tripping screen readers, keyboards or autofill, with the server check for every stack.
- [Rate limiting](https://ikiform.com/guides/spam-protection/rate-limiting.md): Rate limit form submissions per visitor with a shared store, answer 429 with Retry-After, and avoid locking out offices that share one IP.
- [Static sites](https://ikiform.com/guides/spam-protection/static-site.md): Stop spam on a static site form even though it can't keep a secret or count posts, with a honeypot partial, a safe script and server-side checks.
