Stop contact form spam without punishing your visitors
CAPTCHA is the reflex answer, and it is the wrong one to reach for first. It taxes every honest visitor to stop a bot that a hidden input would have caught for free, and screen-reader users, people with motor impairments, and anyone on a bad connection pay the highest price. Below are the layers that actually work, in the order you should add them.
Most contact form spam comes from bots that fill every field and submit instantly. You stop them with a honeypot field a human never sees, a minimum time-to-submit check, and server-side content filtering. This blocks the large majority of automated spam without a CAPTCHA, which costs real visitors time and fails accessibility for many of them.
The minimal integration
A honeypot is a normal input, hidden from people and left empty by them. Bots fill every field they find, so a non-empty value is a reliable spam signal. Never hide it with `type="hidden"`. Bots skip those; hide it with CSS and keep it out of the tab order.
<form action="https://mtform.co/f/your-form-key" method="POST">
<label>
Name
<input name="name" autocomplete="name" required>
</label>
<label>
Email
<input type="email" name="email" autocomplete="email" required>
</label>
<label>
Message
<textarea name="message" required></textarea>
</label>
<!-- Spam trap: hidden from people, tempting to bots. Leave it empty. -->
<input
type="text"
name="_mtf_honeypot"
tabindex="-1"
autocomplete="off"
aria-hidden="true"
style="position:absolute;left:-9999px"
>
<button type="submit">Send</button>
</form>Replace your existing <form> tag, or just change its action attribute. The browser navigates to a branded success page. Configure a redirect in Settings.
Step by step
- 01
Add a honeypot field
Add a text input that humans never see, positioned off-screen with CSS and marked aria-hidden with tabindex="-1". Any submission that fills it is automated.
- 02
Add a time-to-submit check
Record when the page rendered in a hidden field. Treat submissions that arrive within a couple of seconds as automated, because no human completes a form that quickly.
- 03
Filter server-side, never in the browser
Any check that lives only in client JavaScript is trivially bypassed by posting directly to your endpoint. The decision has to happen on the server that receives the POST.
- 04
Lock the endpoint to your own origins
Restrict which domains may submit to your form. A public endpoint that accepts posts from anywhere is a spam magnet regardless of the other layers.
- 05
Review what was caught, do not just delete it
Keep filtered submissions in a spam view for a retention window so you can recover a false positive. A filter you cannot audit will eventually eat a real customer enquiry without you ever knowing.
Hidden visually and from assistive technology, removed from the tab order, and with autocomplete off so a browser never fills it on a real visitor’s behalf.
<form action="https://mtform.co/f/your-form-key" method="POST">
<label for="email">Email</label>
<input id="email" name="email" type="email" required>
<label for="message">Message</label>
<textarea id="message" name="message" required></textarea>
<!-- Honeypot: invisible to humans, irresistible to bots. -->
<div aria-hidden="true" style="position:absolute;left:-9999px;">
<label for="company">Company</label>
<input id="company" name="_gotcha" type="text" tabindex="-1" autocomplete="off">
</div>
<button type="submit">Send</button>
</form>Bots post the instant they parse the page. Stamping render time and rejecting sub-two-second submissions costs a human nothing. Nobody reads and fills a contact form that fast.
<input type="hidden" name="_rendered_at" value="">
<script>
document.currentScript.previousElementSibling.value = Date.now();
</script>Common pitfalls
Hiding the honeypot with type="hidden"
Bots specifically skip hidden inputs because they know the trick. The field must be a normal visible-type input that CSS moves off-screen, otherwise it catches nothing.
Using display:none on the honeypot
Some bots parse computed styles and skip anything with display:none. Off-screen positioning is harder to detect and behaves identically for real users.
Silently discarding suspected spam
Every filter has false positives. Discarding without a reviewable spam folder means a legitimate enquiry disappears with no trace and no way to recover it.
Relying on client-side validation alone
A bot posts straight to your endpoint URL and never runs your JavaScript. If the check is not on the server, it is decoration.
Troubleshooting
| Symptom | What is happening | Fix |
|---|---|---|
| still spammed | Volume continues after adding a honeypot. | Check the field is not type="hidden" and not display:none, and confirm the server actually rejects on a non-empty value rather than only logging it. |
| false positives | Real enquiries are landing in spam. | A password manager may be filling the honeypot. Add autocomplete="off" and give it an unusual name that no autofill heuristic recognises. |
| 403 | Submissions rejected after adding origin rules. | The posting domain is not on the allowed list. Add every origin you submit from, including the www and non-www variants. |
Frequently asked questions
→Do I need a CAPTCHA to stop contact form spam?
Usually not. A honeypot field, a time-to-submit check, and server-side filtering stop the large majority of automated spam. CAPTCHA adds friction for every legitimate visitor and creates real accessibility barriers, so it is worth trying as a last resort rather than a first line.
→Is a honeypot field bad for accessibility?
Not when implemented correctly. Position it off-screen with CSS, set aria-hidden="true" on its wrapper, and give it tabindex="-1" so keyboard and screen-reader users never encounter it. Avoid display:none, which some bots detect.
→Why am I getting spam when my form has JavaScript validation?
Because bots post directly to your form endpoint and never load your page or run your scripts. Client-side validation improves the experience for real users but provides no spam protection at all. The filtering has to happen server-side.
→Should spam be deleted automatically?
No. Keep it in a reviewable spam view for a retention window. Every filter produces false positives eventually, and without a spam folder a legitimate enquiry is lost silently.
Keep going
Last reviewed August 27, 2026
Ship this form for real
Create an endpoint, paste it in, and watch the first submission land in your inbox, in under three minutes.
Create free endpoint