How to Stop Contact Form Spam Without a CAPTCHA
A visible CAPTCHA stops bots and also stops real customers. Three layered defences catch most automated submissions without asking a single human to identify a bus.

Short answer: use three invisible layers — a honeypot field, a minimum time-to-submit check, and server-side content filtering. Together they remove most automated submissions and cost real visitors nothing. A visible CAPTCHA works too, but it costs genuine conversions, so it belongs after the invisible layers have failed rather than instead of them. As of August 2026 spam filtering is included on every BotForms plan, starting at $29/month.
Form spam is a nuisance that gets solved badly. The instinctive fix — add a CAPTCHA — works against bots and also works against the customers you built the form for. This post is about the layers that only affect the bots.
Why the reflex to add a CAPTCHA is wrong
A CAPTCHA is a tax on every visitor to stop a minority of them. That trade is sometimes right. It is rarely right on a contact form.
Every step between intent and submission costs you some proportion of submissions. An image challenge is not a small step: some people fail it and retry, some abandon rather than attempt it, and screen reader users hit genuine accessibility barriers. The cost lands hardest on mobile, where the challenges are fiddliest, and on older visitors — which for a lot of service businesses is a meaningful part of the customer base.
Meanwhile the spam it stops costs you almost nothing directly. It is annoying. It is not expensive. The expensive part is what spam does to your measurement, which we come back to below, and filtering fixes that just as well as blocking does.
So the ordering matters: make the cheap invisible defences work first, and hold the visible challenge in reserve for a form that is genuinely under sustained attack.
Layer one: the honeypot
Add a form field that no human will ever see, and reject any submission that fills it.
The mechanics matter slightly. Hide it with off-screen positioning or zero opacity rather than display: none alone, because some scripts check for the obvious hidden styles and skip those fields. Give it a plausible name — company_url or fax — since a field called honeypot is not much of a trap. Set autocomplete="off" and tabindex="-1" so a keyboard user tabbing through never lands in it and a password manager never autofills it.
Then reject silently. Return the same success response you would for a real submission. Telling a bot it failed just teaches whoever wrote it to adapt.
This catches the low end of the spectrum: scripts that find a form, fill everything, and submit. That is a large share of the volume and none of the effort.
Layer two: the time check
Record when the form was rendered and compare it to when it was submitted. A human reading a contact form and typing a message takes at minimum several seconds. A script takes milliseconds.
A threshold of about three seconds rejects almost nothing genuine. If you want a wider margin, set it lower rather than higher — the failure mode of an aggressive threshold is rejecting someone who prepared their message elsewhere and pasted it in, which is exactly the well-prepared enquiry you least want to lose.
The implementation detail people get wrong is putting the render timestamp in a plain hidden field, where anything can rewrite it. Sign it or store it server-side against a token. An unsigned timestamp is a suggestion, not a check.
This layer catches the middle of the spectrum: scripts sophisticated enough to skip a honeypot but not patient enough to wait.
Layer three: content filtering
The remaining spam looks like a form submission because it is one — submitted by something that behaves plausibly. Now you have to look at what was actually said.
The reliable signals, roughly in order of how well they hold up:
Links in short free-text fields. A genuine enquiry occasionally includes a URL. A name field containing one, essentially never.
The same value repeated across every field. Name, company, message all identical is not a person.
Language mismatch. If you serve one metro area and the message is in a language you have never had an enquiry in, that is worth flagging — flagging, not deleting, because occasionally it is a real customer.
Volume from one source. Six submissions in a minute is a script regardless of what each one contains.
Field-appropriateness. A phone field containing prose. An email field with a disposable domain you have never had a genuine customer from.
The important design decision here is what happens on a match. Quarantine, do not delete. Move it to a filtered view, do not notify, but keep it. Content filtering is the layer most likely to produce a false positive, and a quarantine means the cost of being wrong is that someone finds the enquiry a day late rather than never.
What each layer catches
| Layer | Catches | Cost to real visitors | Effort |
|---|---|---|---|
| Honeypot | Naive fill-everything scripts | None | Minutes |
| Time check | Scripts that skip hidden fields | Effectively none | Under an hour |
| Content filtering | Plausible-looking automated junk | Occasional false positive, mitigated by quarantine | Ongoing tuning |
| Invisible scoring (reCAPTCHA v3) | Behavioural anomalies | Third-party script, privacy disclosure | Moderate |
| Visible CAPTCHA | Nearly everything automated | Real, measurable conversion loss | Low effort, high cost |
Work down the table and stop when the spam stops. Most forms never reach row four.
If you are on a hosted form platform, the first three layers should already be running without you configuring anything — on BotForms they are included on every plan, including Starter. If you built your own endpoint on a static site, they are yours to implement, and the static-site form backend guide covers where that responsibility sits.
The real cost of spam is measurement, not annoyance
This is the part that justifies the work, and it is not the inbox clutter.
Spam inflates your submission count. A landing page converting at what looks like 4% might be converting at 2.5% with the rest being junk — and 4% looks acceptable, so nobody investigates. You lose the signal that would have told you the page needs work. That is a far more expensive problem than deleting emails.
It also slows your response to real enquiries, because a genuine lead sitting between two pieces of junk gets triaged with them. Response speed is the single strongest predictor of whether a form-sourced lead converts, and burying leads directly damages it — the mechanics are in the speed-to-lead notification comparison.
So the case for filtering is: your conversion rate becomes true, and your response time stops being sabotaged by noise. Both of those are worth more than the deleting. If you want to check whether your own numbers are being distorted, which form metrics actually matter walks through pulling a clean figure.
What not to do
Do not remove the form. People reach for this after a bad week. Replacing a contact form with an email address reliably costs more genuine enquiries than the spam ever cost you, because a mailto: link is a much worse experience on mobile and a lot of people simply will not use it.
Do not obfuscate the email address instead. Same problem, plus it breaks for anyone without a configured mail client.
Do not block by IP. Automated submissions rotate addresses, and you will eventually block a shared corporate NAT with a real customer behind it.
Do not add more required fields as a deterrent. It does deter bots slightly. It deters humans considerably more, and you have made your form worse to solve a problem that filtering solves for free. The general point about over-collection is in our piece on what AI gets wrong when it writes form questions — over-collection is the most common form design error whatever the cause.
Searching for help on this is confusing, and here is why
If you go looking for advice on this you will hit the phrase "bot form" constantly, meaning different things in different results. It is used for chat-style forms that ask one question at a time, for forms built by AI from a description, and for the automated scripts attacking your form. Three unrelated concepts, one phrase — we untangled them in what a bot form actually is, which is worth two minutes if you are getting contradictory search results.
A reasonable target
You will not reach zero, and chasing zero is where you start damaging real conversions. A well-filtered public form still lets a few plausible submissions through in a month.
The right target is: no notification for anything obviously automated, everything questionable held in a quarantine view someone glances at weekly, and a submission count you can trust for measurement. That is achievable with the three invisible layers and no CAPTCHA.
Spam protection is on every BotForms plan — see features for what is included, pricing for plan limits, or start a 30-day trial and point an existing form at it to see what your current filtering is missing.
Frequently asked questions
How do I stop spam on my contact form without a CAPTCHA?
Layer three defences that are invisible to real visitors. A honeypot field hidden with CSS catches naive scripts that fill every input they find. A minimum time-to-submit check catches anything completing the form faster than a human can read it, which in practice means under about three seconds. Server-side content filtering catches the rest by looking at what was actually submitted. Together these remove the large majority of automated submissions and cost real visitors nothing.
Does a CAPTCHA hurt conversion rates?
Yes, and the effect is larger on mobile and for older visitors. Every extra interaction between intent and submission costs some proportion of submissions, and an image challenge is a meaningful interaction — some people fail it, some abandon rather than attempt it, and screen reader users hit real accessibility problems. That cost is worth paying when invisible defences have genuinely failed, and not before.
What is a honeypot field?
An input hidden from human visitors — positioned off-screen or set to zero opacity, never with display:none alone since some bots check for that — and left empty by design. Real people never see it, so it stays blank. Naive automated scripts fill every field they can find, so a value in that field is a reliable signal to reject the submission silently. It costs nothing and catches a surprising share of low-effort spam.
Why am I suddenly getting spam through my form?
Almost always because a scraper discovered your form's endpoint, not because anything on your site changed. Automated submissions arrive in bursts rather than a trickle, often with a URL in a name field or the same text pasted into every input. Nothing you did caused it, and removing the form is a much larger cost than the spam is — hiding a contact form loses far more genuine enquiries than the junk was ever worth.
Do spam submissions affect my analytics?
Yes, in the way that hurts most. They inflate your submission count, which makes an underperforming page look acceptable so nobody investigates it. They also bury genuine leads, which slows your response time on exactly the enquiries that matter. Filtering is worth doing for measurement accuracy alone, before you count the time it saves in the inbox.
Should I use reCAPTCHA v3 instead of a visible challenge?
It is a reasonable middle ground since it scores behaviour invisibly rather than presenting a puzzle, so the conversion cost is much lower than a visible challenge. The trade-offs are that it loads third-party JavaScript on your page, it introduces a privacy consideration you may need to disclose, and it occasionally scores real people as suspicious with no path for them to prove otherwise. Try the invisible layers first, since they have none of those costs.
Can spam filtering block real customers?
Any filter can produce false positives, which is why the design matters. A time threshold set too aggressively will reject someone pasting a prepared message. Content filtering tuned too tightly will reject a genuine enquiry that happens to include a URL. The safe pattern is to flag and quarantine rather than silently discard, so a suspicious submission is still stored and reviewable rather than lost.
Build this form in about a minute
Describe what you need to collect — or upload a PDF of the form you already use — and BotForms builds it, hosts it, and routes every submission to your inbox.
Start your 30-day trialKeep reading
- How to Build an AI Lead Capture Form, Field by FieldA working build guide for an AI lead capture form: which fields earn their place, what the AI should draft versus what you must edit, and how to wire notification and reply before you publish.
- Deliver a Lead Magnet Automatically From Your Form (Without a Second Subscription)The download-in-exchange-for-an-email trade usually needs a form tool plus an email platform plus something to glue them. It does not have to.
- Form Analytics: The Four Numbers That Actually MatterMost form dashboards report submissions and completion rate. Neither tells you where you are losing money. Here are the four numbers that do, and how to get them.