# How to stop form spam without a CAPTCHA | Nolgard

> Score form submissions on the server from invisible browser, decoy-field, email and network signals instead of a puzzle. Steps, code, approaches compared and FAQ.

Source: https://nolgard.com/guides/stop-form-spam-without-captcha/
Last updated: 2026-10-26

[Nolgard](https://nolgard.com/) / [Guides](https://nolgard.com/guides/) / How to stop form spam without a CAPTCHA

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

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

- **Turn on decoy fields.** Nolgard's opt-in [honeypot](https://nolgard.com/docs/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`.

- **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();
```

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

- **On WordPress, use the plugin.** There are ready integrations for [Contact Form 7](https://nolgard.com/docs/contact-form-7/), [WPForms](https://nolgard.com/docs/wpforms/) and [WooCommerce](https://nolgard.com/docs/woocommerce/).

- **Watch first.** Run in Observe mode for a week and read the events before you enforce.

## Approaches compared

| Approach | Visible to real users? | Stops simple bots? | Stops headless browsers and AI agents? |
| --- | --- | --- | --- |
| Visual CAPTCHA (reCAPTCHA v2, hCaptcha) | Yes, when unsure | Yes | Partly; solving services exist |
| Invisible challenge (Turnstile, reCAPTCHA v3) | Rarely | Yes | Partly |
| Honeypot field only | No | Yes | No; agents can skip off-screen inputs |
| Time-to-submit check | No | Yes | No; easy to wait |
| Server-side scoring of browser, network and behaviour (Nolgard) | No visual challenge ever | Yes | Partly; Nolgard will miss some bots, see [methodology](https://nolgard.com/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](https://nolgard.com/docs/recaptcha-migration/).

## Sources

- [Nolgard docs: honeypot decoys](https://nolgard.com/docs/honeypot/)
- [Nolgard docs: quotas](https://nolgard.com/docs/#quotas)
- [Nolgard docs: ad blockers and Tor](https://nolgard.com/docs/privacy-engineering/#blocked)
- [W3C WAI: inaccessibility of CAPTCHA](https://www.w3.org/TR/turingtest/)

## Related

- [Signup abuse signals](https://nolgard.com/guides/signup-abuse-signals/)
- [Turnstile vs Nolgard](https://nolgard.com/compare/turnstile/)
- [hCaptcha vs Nolgard](https://nolgard.com/compare/hcaptcha/)

[Read the docs](https://nolgard.com/docs/)[Start free](https://nolgard.com/app/#/signup)
