npm package · MIT · Node ≥ 18

form-honeypot-guard

Block form spam bots without a captcha.

Layers cheap checks that most bots fail and real people never notice: an accessible honeypot, an HMAC-signed timing token, a JS proof, interaction signals, content heuristics, rate limiting and optional Altcha-style proof-of-work. webpack and Vite plugins, a <2 kB client, and server helpers for Express, Fastify, Next.js, SvelteKit, Remix, Astro and any Fetch runtime.

npm i form-honeypot-guard
~/project — zsh
$ npx form-honeypot-guard check dist dist/contact.html (2 forms)  ✖ error POST form without a honeypot [fg/no-honeypot]          form at line 1 (action=/c) posts without a honeypot field          fix: add data-guard to the form and build with FormGuardPlugin  ✖ error GET form sends personal data in the URL [fg/get-personal-data]          form at line 1 (action=/news) uses GET and sends email in the query string          fix: add method="post"
Sample output from the form-honeypot-guard README.

The problem

Captchas cost you conversions and accessibility, and most contact-form spam comes from dumb, untargeted bots that a few invisible checks would stop.

form-honeypot-guard adds those checks at build time and verifies them on the server: bots that fill every field, submit instantly, skip JavaScript, replay tokens or flood you get rejected, and people never see a puzzle.

Features

Accessible honeypot

Off-screen, aria-hidden, tabindex="-1" and autocomplete="off", with a randomised, realistic name per build.

Signed timing tokens

HMAC-SHA256 tokens reject submissions that are too fast, expired, tampered with or replayed.

JS proof & signals

A proof only a real browser writes, plus keypress, pointer and focus counts.

Rate limiting

Sliding window per IP, email or fingerprint, with a correct 429 and Retry-After.

Optional proof-of-work

Altcha-style, privacy-friendly PoW with no captcha vendor.

Build-time plugins

webpack 5 and Vite plugins add the markup to built HTML and inject the ~1.3 kB gzipped runtime.

Framework helpers

Express, Fastify, Next.js, SvelteKit, Remix, Astro, Web Fetch runtimes, and a React wrapper.

Distributed stores

Bring your own Redis, Upstash, Cloudflare KV or Durable Object client. Nothing bundled.

Usage

# Generate an HMAC secret

 npx form-honeypot-guard secret

# Audit built HTML forms

 npx form-honeypot-guard check dist

# Strict audit (warnings fail)

 npx form-honeypot-guard check dist --strict

# JSON output

 npx form-honeypot-guard check dist --json

Protect an Express route

import express from 'express';
import { expressGuard, cleanFields } from 'form-honeypot-guard';

const app = express();
app.use(express.urlencoded({ extended: false }));
app.use(expressGuard({ manifest: 'server/form-guard.manifest.json', paths: ['/contact'] }));
app.post('/contact', (req, res) => {
  sendEmail(cleanFields(req.body, { manifest: 'server/form-guard.manifest.json' }));
  res.redirect('/thanks');
});

Audit forms in CI

# .github/workflows/forms.yml
name: Forms
on: [push, pull_request]
jobs:
  forms:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npm ci && npm run build
      # exit 1 if a built form is missing protection
      - run: npx form-honeypot-guard check dist

CLI commands & key options

FlagDescription
check [dir]Audit built HTML forms (default: dist)
check --jsonJSON output
check --strictWarnings count as errors
secret [--env]Print a new HMAC secret
forms (plugin)Selector or 'all' (default 'form[data-guard]')
minTime / maxAge3000 / 7200000 ms
requireJstrue, 'soft' (adds score only) or false
threshold (server)Score at which a submission fails (default 5)
rateLimit (server){ limit: 5, windowMs: 60000, keys: ['ip'] } or false
silent (server)Fake 200 {"ok":true} for rejected bots; rate limits still return 429
pow (server)true or { maxnumber, require: true | 'soft', field }
trustProxy (server)true, a number of hops, or a list of proxy IPs

Full reference, config file format and API in the README.

Support this project

Support open-source security tools

I build free, open-source tools that help developers ship safer websites. Every coffee helps keep them maintained, documented and free for everyone.

Buy me a coffee (opens Stripe in a new tab)

Secure checkout by Stripe

Portrait of Louis Wright

About the author

Louis Wright

Cyber security researcher and software engineer based in the UK.

More tools by Louis Wright

58 tools

Sentinels security scanners & CI gates · 20