Rate Limiting and Abuse Prevention for Public-Facing Forms

A B2B client's contact form received roughly 40,000 spam submissions over a single weekend from a bot script that had discovered the form endpoint, each one triggering a notification email via SendGrid and a Slack webhook. Beyond the noise, it burned through a meaningful chunk of their monthly email sending quota and buried the two or three genuine leads that came in during the same window.
Our first fix wasn't a CAPTCHA — we wanted to avoid the friction hit for real users if a lighter approach could work. We added a honeypot field, a text input hidden via CSS (not display:none, which some bots detect and skip) that real users never see or fill, and any submission with that field populated gets silently discarded server-side. That alone stopped roughly 90% of the bot traffic, since most simple scrapers fill every field they find in the DOM.
For the remainder, we added IP-based and fingerprint-based rate limiting at the edge using Cloudflare's rate limiting rules — a cap of 5 submissions per IP per hour on the form endpoint, with a longer-window secondary limit to catch distributed low-and-slow attempts from rotating IPs. We deliberately kept the limit generous enough that a real user retrying a failed submission a few times wouldn't hit it, since overly aggressive rate limits create their own support burden.
We reserved Cloudflare Turnstile, a CAPTCHA alternative that runs invisibly in most cases, for form endpoints that remained a target after the above — specifically a signup form that was still getting targeted by a more sophisticated bot that filled the honeypot correctly and rotated IPs fast enough to stay under the rate limit. Turnstile only shows an interactive challenge to traffic it scores as suspicious, so the vast majority of real users never see anything.
Server-side validation got tightened too — the original form accepted any string in the email field with only client-side regex validation, which is trivially bypassed by direct POST requests. We added server-side format validation plus a disposable-email-domain check for the signup flow specifically, since that form's abuse pattern was overwhelmingly free trial farming rather than pure spam.
Submission volume on the contact form dropped from the 40,000-in-a-weekend spike to a baseline of under 50 legitimate submissions a day, and the client's email sending costs and Slack noise both returned to normal without adding a single visible CAPTCHA to their main contact form.

