I logged every bot that hit our forms for 30 days. Here is what they wanted.
April 1, 2026 · 7 min read
I left a honeypot up for thirty days.
Nothing fancy. One public endpoint on a throwaway domain, no CAPTCHA, no rate limit at first, and a landing page that said "contact us" with a real-looking form. I logged every request — method, headers, body, timing, IP, the whole thing — into a boring Postgres table and walked away.
Here's what came out the other end.
The headline numbers
| Metric | 30-day total |
|---|---|
| Total POST requests | 47,318 |
| Unique IPs | 3,104 |
| Countries represented | 62 |
| Real human submissions | 12 |
| Spam-to-human ratio | 3,943 : 1 |
| Peak hour | 03:00–04:00 UTC (Tuesday) |
| Quietest hour | 14:00–15:00 UTC (Saturday) |
Twelve humans. Three people I personally know, eight from a small Reddit thread, and one genuinely lovely email from a stranger in Lisbon asking if we were hiring.
Everyone else was a machine.
Where they came from
I expected a heavy tail from a few huge datacenters. I got something messier.
- ~41% came from residential IP ranges — home routers, mobile carriers, compromised boxes. The rise of "residential proxy" services is not a rumor. It is the current default.
- ~33% came from cloud providers. DigitalOcean, Hetzner, and a long tail of small VPS shops. AWS and GCP were barely represented, which tracks with their abuse reporting being slightly better.
- ~18% came from known bad-neighborhood ASNs with names I won't dignify.
- ~8% came from genuinely weird places. A municipal library in one European capital submitted 140 times in an hour. A university in East Asia contributed 600 requests at 2 a.m. local time. Someone's IoT-connected printer sent three.
IP-based blocking is dead as a first-line defense. Residential proxies have killed it. You can still use IP signals for something, but if you're relying on GeoIP or ASN blocklists alone, you're playing a game from 2014.
What they were selling
Every spam POST is a tiny ad. Once you group them, the market is easy to see.
| Category | Share | What it looked like |
|---|---|---|
| SEO / "backlink services" | 34% | "I can get your site on the first page of Google in 30 days" |
| Crypto pump / "investment" | 22% | "Our fund returned 38% last quarter, book a call" |
| Gambling / casino | 14% | "Partner program, up to 60% revenue share" |
| Generic web-dev outreach | 11% | "Your website has these 3 bugs we can fix for $99" |
| Loan / "finance" | 8% | Usually impersonating a bank |
| Pure malware links | 6% | Shortened URLs, sometimes obfuscated |
| Unclassifiable | 5% | The cryptic ones. Maybe testing for vulnerabilities. Maybe lonely. |
The SEO outreach is the loudest category, and it's been the loudest category for a decade. It will probably still be loudest when my grandchildren ship their first form. Some things don't change.
The timing was the most interesting part
If you plotted the requests on a clock, you'd see a shape that does not look like a human workday. Traffic peaked between 02:00 and 05:00 UTC, which is exactly when you'd want it to peak if you were running spam infrastructure and wanted the forms to notify nobody.
The interesting wrinkle: human submissions and spam had completely different weekly shapes. Humans submitted on Tuesday, Wednesday, and Thursday afternoons. Spam submitted every day with a small dip on Sunday, which I can only assume is because the bot herders also like brunch.
This matters because time-of-arrival turns out to be one of the cleanest signals you have, and it barely costs anything to implement.
What actually stopped them
I tried things in sequence. Each number is the daily spam volume after the change stabilized.
- Baseline (nothing): 1,577/day
- Added a honeypot field (hidden
websiteinput, dropped if non-empty): 412/day- A ~74% drop from one line of HTML. This is the single highest return you will ever get on a form.
- Added a minimum submission-time threshold (ignore anything submitted in <1.2s): 186/day
- Another big cut. Real humans cannot type a contact form in under a second. Bots, famously, can.
- Added header heuristics (no
Accept-Language, curl-ish UA, missingRefereron a known landing page): 71/day- Meaningful but diminishing returns. This is where false positives start.
- Added a per-IP rate limit (5/minute): 58/day
- Smaller than I hoped, because residential proxies rotate.
- Added a content classifier on the message body (keyword + embedding similarity): 4/day
- The last mile. This is expensive to build and maintain, which is one reason most teams don't.
Four junk submissions a day is livable. One honeypot field got me most of the way there. I want to be very clear about that.
Why I finally killed reCAPTCHA
I ran reCAPTCHA v3 for one week of the experiment as a comparison. It caught plenty of bots. It also:
- Added ~140ms to initial page load
- Made the form feel slightly janky on mobile Safari
- Annoyed three out of twelve real humans enough that they mentioned it
- Tracked my visitors across the web in ways that raised GDPR questions I didn't want to answer on a Sunday
Meanwhile, the honeypot plus timing combo cost me exactly zero milliseconds, zero user complaints, and zero legal meetings. The ROI wasn't close.
I'm not saying never use CAPTCHA. I'm saying it should be the fourth thing you try, not the first.
The takeaways, short version
- Public forms get hit, constantly, by real spam infrastructure. The ratio will shock you the first time you see it.
- One honeypot field is the highest-leverage ten seconds you will spend on a form this year.
- Time-of-submission is free and underused.
- Residential proxies broke IP blocking. Don't rely on it alone.
- reCAPTCHA is not the default it used to be. Treat it as a last resort.
- The goal is not zero spam. The goal is "my inbox is usable again."
We built all of this into FormTo so you don't have to run the experiment yourself. Honeypot traps, timing checks, per-IP limits, and a reputation layer — all on by default, even on the free plan. You can see the full rundown in Security & reliability.
Or just point a form at us and watch the junk not arrive. That part still feels slightly magical to me and I built it.
More posts