Bot-Protected Forms Without Third-Party Tracking
Contact forms are one of the easiest places for spam bots to attack a small website. The usual answer is to drop in a third-party challenge service, but that adds tracking, consent questions, visual friction, and another external dependency.
Nibbly now takes a quieter approach: public contact forms are protected by several lightweight server-side layers that fit the flat-file architecture.
What Changed
- Lazy-loaded form HTML — the initial page contains only a placeholder. The actual form is fetched after a short delay, which keeps simple scraping bots from seeing a ready-to-submit form in the first response.
- One-time tokens — each rendered form receives a fresh server-generated token. Tokens are stored in a flat JSON file, expire automatically, and are consumed after validation.
- Minimum submit time — submissions that arrive too quickly after token creation are rejected.
- Honeypot field — bots that fill invisible fields are caught without bothering real visitors.
- Rate limiting — repeated attempts are throttled with hashed client keys, so the site does not need to store raw IP addresses.
- Simple content heuristics — obvious link spam is rejected before it reaches the message inbox.
No Database, No Captcha Account
The implementation stays intentionally small. Runtime state lives in content/form-tokens.json and content/form-rate-limit.json, both treated as generated files. There is no database table, no JavaScript challenge provider, and no external privacy dependency.
Developer-Friendly by Default
For custom forms, Nibbly now provides reusable helpers such as nibblyFormProtectionFields() and nibblyLazyFormPlaceholder(). People writing templates by hand, and LLMs generating Nibbly pages, can use the same simple pattern instead of rebuilding anti-spam logic for every form.
The built-in contact forms already use the new protection automatically.