What our own data shows: about 1 in 5 stored submissions is spam
Between May 2 and September 29, 2026, splitforms stored about 26,200 form submissions across 1,390 forms that received at least one entry. About 5,600 of them — roughly 21% — were flagged as spam. All but 13 of those flags came from the automatic, rule-based filters; the other 13 were marked by form owners from the dashboard.
| Month (2026) | Stored submissions | Flagged as spam | Share |
|---|---|---|---|
| May | 1,410 | 262 | 19% |
| June | 2,981 | 492 | 17% |
| July | 4,448 | 749 | 17% |
| August | 7,594 | 2,369 | 31% |
| September (to the 29th) | 9,785 | 1,748 | 18% |
The share sits at 17–19% in most months. August's 31% was concentrated: five forms accounted for about 80% of that month's flagged spam. Spam is lumpy — a form that gets discovered by one bot operator can see weeks of attempts while most forms see very little.
How we counted. A read-only count of the splitforms submissions table on September 29, 2026, from its first row (May 2, 2026). It only sees submissions that were stored. Honeypot and time-trap hits are dropped silently before anything is saved, requests over the per-IP rate limit are rejected with HTTP 429, and submissions owners permanently deleted are gone — none of those are in these numbers. So the real volume of spam aimed at these forms is higher than 21%; this is what got far enough to be stored and then caught. September is counted through the 29th.
1. Why form spam is worse in 2026 than ever
If you ran a contact form between 2018 and 2022, the spam landscape was boring: viagra-link bots, the same SEO outreach templates copy-pasted across millions of domains, and the occasional crypto pump. A single honeypot field was enough for most sites. Then three things changed in fast succession, and the entire defense playbook needed a rewrite.
LLM-driven outreach abuse. Generative models made it trivial to produce ten thousand plausibly-personalized messages for the cost of a few cents of inference. The old-school keyword filter that flagged "cheap SEO services" now misses messages that read like "Hi, I came across your site and noticed your footer is missing a sitemap link. Would you be open to a quick call?" — generated, fake, but indistinguishable from a real cold pitch.
Residential proxy networks. Bot operators no longer route traffic through data-center IPs that any competent firewall can flag. They route through tens of thousands of consumer connections rented from compromised IoT devices and shady VPN apps. Your spam now arrives from IPs that look exactly like real customers because, from the network's perspective, they are real customers.
Scale economics. Solved-CAPTCHA-as-a-service now costs roughly $1–$3 per 1,000 solves. A targeted attack against your contact form might cost $20 to bypass even a well-configured reCAPTCHA v2. The attacker math has flipped: spam protection is no longer about making it impossible, it is about making it expensive enough to not be worth the attacker's time relative to easier targets.
Our companion post, the complete 2026 form spam protection guide, walks through the attacker economics with real cost data — start there for the deep dive on why every solo defense leaks.
2. The 5 categories of form spam
Not all spam is the same. Different categories need different defenses, and lumping them together is why most teams end up with a stack that catches one type and lets the other four through.
Link bait. The classic. A bot fills your form with a message containing one or more URLs, hoping the auto-reply email or a public submissions log surfaces those links and earns a backlink. Volume: high. Defense: trivial — link-count and spam-phrase rules catch these reliably.
Contact-form SEO spam. Outreach pitches from fake agencies offering "guest posting", "guaranteed first page rankings", or "niche edits". LLM-generated, plausibly targeted, often references something real about your site. Volume: very high in 2026. Defense: rule-based content scoring plus pattern matching against known campaign templates.
Credential stuffing scaffolding. Attackers use contact forms to test whether email addresses bounce or whether your auto-replies leak account-status information. Volume: low but targeted. Defense: rate limiting per source email, not just per IP.
Contact harvesting. Some spammers do not want your inbox — they want your auto-reply, because your auto-reply confirms the form endpoint is live and worth selling to a spam-as-a-service marketplace. Defense: don't auto-reply on every submission, especially not before spam filtering runs.
Automated reply chains. A submitter fills the form with an email address that auto-replies, your endpoint replies, their auto-replier replies again — and now you and an unrelated mail server are in an infinite loop. Defense: dedupe on submission fingerprint and block on suspicious From headers. Our guide to stopping contact form spam walks through real reply-chain attacks we have seen in production.
3. How spammers actually find your form
You did not get spammed by accident. Bots find new forms through a handful of predictable channels, and understanding them changes which defenses matter.
Google dorking. Attackers run queries like inurl:"contact" or intext:"send message" site:.com to surface millions of contact pages. They scrape the SERP, parse out form endpoints, and feed the result into a worker queue. This is why brand-new contact forms get hit within hours of going live — the dorks run continuously.
Sitemap scraping. Your sitemap.xml is a free map of every URL on your site. Spammers pull it, regex-match for paths containing "contact", "quote", "demo", or "signup", and add the matches to their queue. There is no good defense against sitemap-based discovery — your sitemap is supposed to be public — so the protection has to happen at submission time, not at discovery time.
Public crawlers. Common Crawl, archive.org, and a dozen smaller crawl services maintain public datasets of every form on the web. Spammers download the dataset, filter by domain and form type, and bootstrap a campaign without ever touching your servers themselves until the actual attack.
GitHub and PR scraping. If you wired up a new form, there is a non-zero chance you committed a snippet to a public repo. Bots watch new commits to *.html and *.tsx files containing <form action= and harvest the endpoints in near-real-time. This is one reason splitforms uses access keys instead of leaking your real email in the form action — a public access key can be rotated; a hard-coded mailto: address cannot.
4. The defense-in-depth model
Single-shot defenses fail because every individual technique has a known bypass. A CAPTCHA can be solved by a human farm. A honeypot can be skipped by a DOM-inspecting bot. Rule-based content scoring can be evaded by writing cleaner, less flaggable copy. A rate limiter can be sidestepped by rotating residential IPs. Each of those bypasses costs the attacker something — money, time, or technical sophistication — and the goal of defense-in-depth is to stack so many of them that the total attacker cost exceeds the value of spamming you.
The model splitforms uses, in order of execution per submission:
- Honeypot check — cheap, in-page, kills lazy bots before they ever reach your backend.
- Rate limiting — runs at the edge, drops burst attacks in microseconds.
- Rule-based content scoring — the heaviest layer; runs after the cheap layers so you do not waste cycles on submissions you already rejected.
- Disposable email + signal aggregation — combines weak signals into a strong one.
- Turnstile fallback — only triggered on ambiguous cases; the real user experience stays clean.
No layer is required to be perfect on its own. The combined system is designed to catch the large majority of spam while keeping false positives rare and reviewable — every flagged submission stays visible in the dashboard rather than disappearing, so a false positive is one click from recovery instead of a silent loss.
5. Layer 1: Honeypot fields
A honeypot is a form field that real users cannot see but naive bots will fill anyway. The classic implementation:
<label for="hp-botcheck" style="position:absolute;left:-9999px" aria-hidden="true" > Leave this field empty </label> <input id="hp-botcheck" name="botcheck" type="text" tabindex="-1" autocomplete="off" style="position:absolute;left:-9999px" />
On splitforms, that botcheck name is checked automatically — no server code needed. It also recognizes _gotcha, hp, honey, trap, do_not_fill, and leave-blank as honeypot names. On your own backend, check whether the field you chose is empty; if it is filled, the submission is silently dropped — no error, no rate-limit hit, no signal back to the bot that the trap exists.
False-positive concerns. The two real concerns are password managers (which sometimes autofill fields named "url" or "website") and accessibility tooling. Mitigation: use autocomplete="off" plus aria-hidden="true" plus tabindex="-1", and name the field something password managers do not auto-fill and that doesn't double as a real field (avoid "email", "name", "phone", or "website" — a hosted backend like splitforms deliberately treats those as ordinary fields rather than a honeypot, since genuine forms collect them too).
For a full tear-down of how honeypots compare to CAPTCHA, read our honeypot vs reCAPTCHA comparison. If you want a generator that emits accessible honeypot markup for you, use the honeypot generator tool.
6. Layer 2: CAPTCHA — reCAPTCHA, hCaptcha, Turnstile compared
CAPTCHAs are the most controversial layer because they are the one real users actually see when they fail. Pick the wrong one and real visitors give up at the challenge. Here is the honest 2026 comparison:
| Provider | Cost | Privacy | Script weight | UX |
|---|---|---|---|---|
| reCAPTCHA v2 | Free up to 10,000/mo per organization | Google trackers | ~150 KB | Checkbox + image challenge |
| reCAPTCHA v3 | Free up to 10,000/mo per organization | Google trackers | ~150 KB | Invisible, score-based |
| hCaptcha | Free or paid (revenue share) | Privacy-first | ~100 KB | Checkbox + image challenge |
| Cloudflare Turnstile | Free, unlimited | Privacy-first | ~70 KB | Invisible for most users |
Our recommendation in 2026 is Turnstile for greenfield projects: zero cost, no Google tracking, lowest script weight, and the best invisible-by-default UX. hCaptcha is the right pick if you specifically need monetization or stronger accessibility controls. reCAPTCHA stays only if you are already deeply embedded in Google's ecosystem. Torn between the two classic widgets? See hCaptcha or reCAPTCHA? for free limits, pricing and privacy side by side.
Splitforms triggers Turnstile lazily — only when earlier layers flag a submission as suspicious — so your real users never see a challenge. Our guide to choosing the best CAPTCHA for a contact form walks through implementation for each provider, and the best reCAPTCHA alternatives for 2026 covers the migration path off Google's stack.
7. Layer 3: spam scoring
This is the layer that catches the spam your rules-of-thumb will miss. The interesting bit is what "rule-based spam scoring" actually means under the hood, because the term is used loosely across vendors.
Splitforms's scorer is a fixed set of server-side rules, not a trained model — it is not an AI or machine-learning classifier, and there is no embeddings lookup or model retraining involved. It checks each submission for signals like link count, spam phrases, disposable-email domains, gibberish text, suspicious TLDs and hosts, and repeated content, adds points for every signal that fires, and quarantines the submission once the total crosses a fixed threshold. No single weak signal is enough on its own.
Why we don't publish a synthetic accuracy number. A precision/recall figure from someone else's test set doesn't tell you what will happen on your traffic. What's verifiable instead: every quarantined submission stays in your dashboard's Spam tab until you delete it, so you can judge the false-positive rate on your own traffic and recover any mistake in one click.
The full walkthrough of how spam scoring works under the hood goes deeper on the mechanics. For the product-level feature breakdown including the admin UI for false-positive review, see splitforms spam protection.
8. Layer 4: Rate limiting
Rate limiting caps how many submissions a single source can send in a window. The three dimensions worth limiting on:
- Per IP — kills naive volume attacks. Cap at ~5 per minute, ~30 per hour for most forms.
- Per access key (per form) — protects you from one form being targeted disproportionately. Cap at whatever your real peak traffic plus 3× headroom looks like.
- Per email address — catches the credential-stuffing scaffolding pattern where one attacker tests many inputs through one form.
Splitforms doesn't run an IP-reputation lookup against third-party abuse databases — rate limiting and content scoring cover the same ground without depending on a feed that can be stale or wrong about a shared or rotating IP. A submission from a flagged network still has to trip the content scorer or the rate limit to be quarantined; the IP itself is never treated as guilty on its own.
Where rate limiting should live. At the edge, not in your application code. Cloudflare's WAF and rate-limiting rules run before the request ever hits an origin server. Vercel's firewall product offers a similar primitive. Splitforms handles per-form and per-IP limits for you automatically — if you build your own backend, you should still front it with one of these edge layers.
9. Layer 5: Disposable email blocking
Disposable email domains — "mailinator.com", "tempmail.dev", the hundreds of clones that pop up monthly — are a strong signal but a weak hard-block. The right treatment is contextual.
When to block hard. Free-trial signups, newsletter lists where you pay per subscriber, anywhere a throwaway email pollutes your funnel math. Block at the email-validation step, return a friendly error explaining that a working address is required, and move on.
When to soft-flag. Generic contact forms, support inboxes, anywhere a privacy-conscious real user might legitimately use a forwarding service like Apple Hide My Email or SimpleLogin. Treat disposable as a signal that raises the spam score, not a guillotine.
Splitforms takes the soft-flag route on every form: each email address in a submission is checked against a bundled copy of the public disposable-email-domains list, and a match sends the submission to the Spam tab instead of rejecting it. There is no per-form hard-block setting, so if your use case needs one, validate the address on your own form before it posts.
10. The dark art of negative signals
Negative signals are the heuristics that say "this looks wrong" without proving it. Individually they are weak. Combined, they're how many rule-based scoring systems build a score in practice — this is general background on the technique, not a claim that every signal below is one splitforms scores today; the signals splitforms actually checks are listed in the spam scoring breakdown.
Mouse movement. Real users move their cursor. Bots usually do not. A submission that arrives with no mousemove events on the form page is a soft signal of automation — not a block, but a score nudge.
Time-on-page. A human takes seconds to minutes to fill a contact form. A bot takes milliseconds. A submission that arrives 400ms after the page loaded is almost certainly automated.
JS execution fingerprint. Did the browser execute the page's JavaScript? Did it render the form client-side? Did it call the expected analytics beacons? Headless bots increasingly run a real browser engine, so this signal is weakening — but it is still useful as part of an ensemble.
Field-fill order. Humans fill name, then email, then message. Bots fill in DOM order regardless of what looks natural. If the form was reordered with CSS flexbox so message visually comes second but is third in the DOM, a bot will fill in DOM order and humans will fill in visual order — a free signal.
Paste vs type. A long, well-written message that was pasted into the textarea in one event is a different signal than the same message that was typed character-by-character. Neither is conclusive; both feed the score.
11. Spam protection vs accessibility
Every defense layer above can be implemented in an accessibility-hostile way, and most poor implementations are. The non-negotiable rules:
- Honeypot fields must be
aria-hidden="true"andtabindex="-1", with a label that warns sighted-but-screen-reader users to leave the field blank in case it leaks into AT. - CAPTCHAs must have an audio fallback and must not be the primary defense. Turnstile and hCaptcha both offer accessible alternatives; reCAPTCHA v2's audio challenge is broken in many screen readers and should not be relied on.
- Rate-limit error messages must be human-readable, not just HTTP 429. A user who hits a limit accidentally needs to know what to do — wait, contact you directly, etc.
- Disposable-email blocks must explain why and offer a workaround. "We can't send to that domain — please use a permanent address" is acceptable. Silent rejection is not.
We cover the GDPR-plus-accessibility intersection in our guide to GDPR-compliant form submissions — compliance is part of the same conversation as accessible spam defenses.
12. What to do after spam gets through
No defense is perfect. The interesting question is what happens to the spam that slips through your filters. Two options:
Delete on detection. Cheapest, lowest cognitive load, but you lose the audit trail. The problem: if your rules start producing false positives, you will never know, because the evidence was deleted before you could review it.
Review queue. Flagged submissions go to a separate Spam tab, not your main inbox. You review weekly, and marking a false positive "Not spam" recovers it to your inbox and allowlists that sender going forward. This is the splitforms default — every spam-flagged submission stays in the quarantine view until you delete it rather than being auto-deleted (only its file attachments are purged, 7 days after flagging). The scorer itself is a fixed rule set — it doesn't retrain on your overrides — so allowlisting a sender is what actually improves your own results over time, not a model learning in the background.
A related sub-topic — why contact form emails land in spam folders (false positives on the delivery side, not the filtering side) — is covered separately; both directions of "spam" matter for real-world deliverability.
13. Performance impact of each defense layer
Defense layers cost milliseconds and kilobytes. Done carelessly, the cost is significant. Done correctly, the cost is essentially zero on the user-perceived path.
| Layer | Page weight | Submit latency | Notes |
|---|---|---|---|
| Honeypot | ~50 bytes HTML | 0 ms | Server-side check only |
| Rate limit | 0 bytes | ~5 ms | Runs at edge |
| Rule-based scoring | 0 bytes | ~1–5 ms | Server-side, no external API call |
| Disposable check | 0 bytes | ~2 ms | In-memory list lookup |
| Turnstile (lazy) | ~70 KB | ~150 ms render | Loaded only when triggered |
| reCAPTCHA v3 (eager) | ~150 KB | ~250 ms on every load | Not recommended in 2026 |
The honest takeaway: server-side layers cost essentially nothing on the user-perceived path. The only layer with a real page-speed impact is a client-side CAPTCHA, and the fix is to load it lazily — only when you need it, only after the earlier layers have already triaged the submission. That is the default behavior at splitforms.
14. The 2026 stack we recommend
If you take nothing else from this guide, take this stack. It is what we ship by default at splitforms, and it is what we recommend to every team we onboard regardless of which backend they use:
- Honeypot field on every form. Free, accessible, and it kills the laziest bots before any billable work happens.
- Per-IP and per-form rate limiting at the edge. Cloudflare or Vercel firewall, or splitforms's built-in edge limiter.
- Rule-based content scoring — link count, spam phrases, disposable-email domains, gibberish, and suspicious TLDs/hosts. Splitforms by default, or roll your own with a maintained list.
- Disposable email as a signal, not a block — unless your business model requires it.
- Cloudflare Turnstile fallback, loaded lazily only when earlier layers flag a submission as ambiguous. Never reCAPTCHA v3 as a primary defense in 2026.
- A quarantine inbox, not auto-delete, so you can audit false positives weekly.
How splitforms compares to other form backends on this dimension specifically: every comparison page on the site (e.g. vs Formspree, vs Web3Forms, vs Getform, vs Basin, vs Netlify Forms) breaks down which competitor ships which layers and where splitforms leads — short version: rule-based scoring on every plan including Free, and the lazy-Turnstile pattern, are two places splitforms invests that several competitors gate behind paid plans or skip entirely.
15. Get started with splitforms's spam protection
Sign up at /login and grab a free access key. Every layer in this guide ships on the free 500-submission plan. Drop the access key into your existing form's action attribute, add the honeypot snippet from the honeypot generator, and you are done.
If you want to verify your protection is actually working before you ship, use the spam test tool to send synthetic bot-shaped submissions against your form and see what gets through. For the API reference and webhook payload formats, see the docs and API reference. Pricing for higher submission caps lives at /pricing — Pro is $5/month, Annual is $49/year, and both include the same spam stack as the free tier.
The full feature page for spam protection specifically lives at /features/spam-protection — read it if you want the product-level walkthrough with screenshots of the quarantine UI.