use case · captcha alternatives

The best CAPTCHA alternative is no CAPTCHA.

Updated May 12, 2026

Every "click all the traffic lights" task is a tax on legitimate visitors and a 95th-percentile-still-passes obstacle for modern spam bots. The fix isn't a fancier CAPTCHA — it's moving spam detection off the user's screen entirely. One server-side classification call replaces the friction with a calibrated probability the user never sees.

Why CAPTCHA is the wrong layer

On-page CAPTCHAs solve "is this a real browser session" — a question that stopped being useful around the time bots started running real headless browsers. They don't solve "is this content spammy," which is the question that actually matters. A bot driving Chromium can pass reCAPTCHA v3 reliably; a real customer trying to fill out a contact form on their phone often can't.

The cost shows up in conversion data. Form-completion rates typically drop 3-15% when reCAPTCHA is on the page, and the drop is concentrated in users on flaky connections, older browsers, and accessibility tools — exactly the visitors who shouldn't be paying the tax. Meanwhile the spam keeps coming, because spam is a content-classification problem and CAPTCHA is a session problem.

The replacement pattern

The form goes from this:

html
<!-- before: reCAPTCHA on every form, every visitor pays the friction tax -->
<form action="/api/contact" method="POST">
  <input type="email" name="email" required>
  <textarea name="message" required></textarea>
  <div class="g-recaptcha" data-sitekey="6Lc..."></div>
  <button type="submit">Send</button>
</form>
<script src="https://www.google.com/recaptcha/api.js" async defer></‌script>

To this:

html
<!-- after: clean form, classification on the server -->
<form action="/api/contact" method="POST">
  <input type="email" name="email" required>
  <textarea name="message" required></textarea>
  <button type="submit">Send</button>
</form>

And the work moves to the server-side handler that was already processing the form anyway. About 15 added lines:

typescript
// /api/contact handler — what reCAPTCHA was protecting, now done server-side.
const SPAM_THRESHOLD = 0.85;

export async function POST(req: Request) {
  const { email, message } = await req.json();

  let probability = 0;
  try {
    const resp = await fetch("https://api.siftfy.io/v1/predict", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-API-Key": process.env.SIFTFY_KEY!,
      },
      body: JSON.stringify({ text: message }),
      signal: AbortSignal.timeout(2000),
    });
    if (resp.ok) ({ spam_probability: probability } = await resp.json());
  } catch {
    // Fall open on transport failure — losing one borderline lead beats
    // breaking the form for everyone during a Siftfy outage.
  }

  if (probability >= SPAM_THRESHOLD) {
    // Always 200 to the form; the user sees "thanks" and the spammer
    // doesn't learn the threshold.
    return Response.json({ ok: true });
  }

  await sendEmail({ to: process.env.INBOX!, from: email, body: message });
  return Response.json({ ok: true });
}

The user's experience is the form they expected. The score never touches the browser, so spammers can't probe for it. And the third-party Google script that was tracking every visitor is gone — privacy improves and your CSP gets simpler.

What about hCaptcha, Cloudflare Turnstile, friendly-captcha?

They solve the privacy and accessibility problems with reCAPTCHA but they don't solve the layer problem. They're still asking "is this a real browser session" — they're just asking it more politely. A motivated bot using a real browser still passes; a real customer on a stale browser still occasionally fails. They're improvements, not a rethink.

The case for keeping a Turnstile-style invisible challenge is when you face volumetric abuse — someone is firing 1,000 submissions a second to exhaust your free tier. A stop-the-flood layer makes sense there. But for content quality — junk vs. real — the right tool is content classification.

Edge cases worth handling

  • Volumetric abuse. Pair Siftfy with a basic rate-limiter (per-IP or per-session). Classification is per-message; it doesn't help when a script is brute-forcing the endpoint. One IP, 100 requests/min, all blocked at the edge — that's a different layer.
  • Honeypot + Siftfy. A hidden form field that real users won't fill in is a free extra signal that costs zero user friction. Reject anything where the honeypot is non-empty before calling Siftfy — saves a request quota.
  • Multilingual forms. The model is primarily English-trained. Raise the block threshold to 0.92 if you serve non-English markets.
  • Don't reveal the score. Always 200 on hard block. A 4xx tells the spammer to rephrase; a 200 tells them their content shipped, and they stop tuning.
Try it free

10,000 submissions / month free, no card. Read the /v1/predict reference, or how honeypots fit alongside classification. Related use cases: contact forms, comments, signups.