Guide

How to stop form spam without a CAPTCHA

Short answer. Score each submission on your server from signals the visitor never sees: a browser check token, a hidden decoy field, time to submit, the email domain and the network. Reject clear bots, send doubtful ones to email confirmation, and accept the rest. This removes the puzzle for real people while keeping a server-side verdict you can log.

Last updated 2026-10-26 ยท Written by the Nolgard team

Steps

  1. Add an invisible browser check. Load client.js and request a token when the form is submitted. It carries no score; the verdict comes from your server.
    <script src="https://nolgard.com/v1/client.js" data-site-key="SITE_KEY" defer></script>
    <script>
      // on submit
      await Nolgard.ready;
      const token = await Nolgard.execute({ action: 'signup' });
      // send token with the form to your backend
    </script>
  2. Turn on decoy fields. Nolgard's opt-in honeypot adds one off-screen input with a random name, aria-hidden="true" and tabindex="-1". Normal autofill does not fill it. A honeypot hit alone is enforced at most as challenge, never block.
  3. Verify on the server and branch on the decision. Use action: 'contact' for a contact form. Accountless contact-form checks are not metered.
    const r = await (await fetch('https://nolgard.com/v1/verify', {
      method: 'POST', headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ secret: process.env.NOLGARD_SECRET, token, remoteIp, action: 'contact' })
    })).json();
    if (!r.success) return r.error === 'missing-token' ? confirmByEmail() : accept(); // blocked script is not a bot
    if (r.decision === 'block' || r.decision === 'shadow') return pretendSuccess();
    if (r.decision === 'challenge') return confirmByEmail();
    return accept();
  4. Handle blocked scripts. Ad blockers, Brave Shields and Tor at the Safest level can block the script. Verify then returns missing-token. Treat it as unknown, not as a bot.
  5. On WordPress, use the plugin. There are ready integrations for Contact Form 7, WPForms and WooCommerce.
  6. Watch first. Run in Observe mode for a week and read the events before you enforce.

Approaches compared

Ways to stop form spam
ApproachVisible to real users?Stops simple bots?Stops headless browsers and AI agents?
Visual CAPTCHA (reCAPTCHA v2, hCaptcha)Yes, when unsureYesPartly; solving services exist
Invisible challenge (Turnstile, reCAPTCHA v3)RarelyYesPartly
Honeypot field onlyNoYesNo; agents can skip off-screen inputs
Time-to-submit checkNoYesNo; easy to wait
Server-side scoring of browser, network and behaviour (Nolgard)No visual challenge everYesPartly; Nolgard will miss some bots, see methodology

Questions

Is a honeypot enough on its own?

Against form-filling scripts, often. Against browsers driven by an AI agent that reads the visible page, no. Use it as one signal.

Will this hurt accessibility?

Nolgard never shows a puzzle, so there is nothing to solve with a screen reader. The decoy input is hidden from assistive technology with aria-hidden and removed from tab order.

Do contact-form checks count toward my quota?

No. Accountless checks with action contact are not metered.

What should I do with a doubtful submission?

Send it through email confirmation instead of rejecting it. A false positive then costs the visitor one click.

Can I keep my CAPTCHA while I test?

Yes. Run both, compare the two verdicts on your own traffic, then remove whichever you no longer need. See reCAPTCHA migration.

Sources

Related