Security
How to stop contact form spam on a small business site
Why spam gets past a basic contact form, the cheap fixes that work, when a captcha is worth it, and when it costs you real enquiries.
Ben Harvie6 min read

This week my own contact form sent me an enquiry from "MoumBoig" at a company called "google", who had heard about me from the "FBI" and was interested in AI for their business. The message itself, in Russian, said I had a money transfer of 142,078 roubles waiting and gave me a link to collect it. It was a phishing attempt, meaning a message designed to trick you into clicking a link that steals your details or installs something nasty.
If you run a small business website, you have probably had something like it. Here is what is actually going on, what I did about it on my own site, and how to decide what your site needs. I will also tell you when a spam check is not worth adding, because it can cost you more than the spam does.
Why spam gets through a normal contact form
A contact form is just a web page that sends what you type to an address on the website. Anyone, or anything, that knows that address can send to it directly. Nobody has to load the page, look at the fields or press the button.
That is how most form spam arrives. A spammer runs a script, a small program that repeats a job for you, which fires the same message at thousands of websites an hour. It fills in every field it finds with something plausible enough to pass ("google" for the business name, a made-up phone number) and moves on. It does not care whether anyone reads it. If one person in ten thousand clicks the link, it has paid for itself.
So the question is not "how do I hide my form", because you cannot. It is "how does my site tell a real person from a script, without getting in the real person's way".
The cheap fixes, and why mine was not enough
My site already had two defences, and they are worth having on any site.
A honeypot field
A honeypot is a hidden box on the form that a human never sees, so a human never fills it in. A lazy bot fills in every box it finds, including the hidden one, and the site quietly throws that message away. It costs your visitors nothing, which is why I like it.
It did not catch MoumBoig. The honeypot was empty, which tells me the script never loaded my page at all. It posted straight to the address behind the form and only sent the fields it expected. A honeypot only works on bots that read the page.
A rate limit
A rate limit caps how many messages one connection can send in a short window. Mine allows a handful every fifteen minutes, which is plenty for a person and useless for a spammer trying to send hundreds. It stops floods, but it does nothing about one message from one address, and that is exactly what this was.
Checking what was written
You can also block messages by their content: a link in a message from someone who has never been in touch, text in an alphabet your customers do not use, the same message arriving twice. These rules catch a lot, but they need looking after, and sooner or later one blocks a real customer. A Polish-speaking plumber or a customer sending you a link to a photo of their broken boiler is not spam.
What a captcha actually does
A captcha is a check that tries to tell a person from a bot. You will know the old kind: the squiggly letters, or "click every square with a bus in it". Those work, but they annoy people, they are hard for anyone using a screen reader (software that reads the page aloud for people who cannot see it), and some people give up halfway.
The newer kind gives no puzzle at all. Google's reCAPTCHA v3, which is what I chose, quietly watches how the page is used, things like whether someone moves around the page and types like a person, and gives each visit a score between 0 and 1. When the form is sent, the website asks Google for the score and decides what to do with it. A real visitor never sees anything except a small line under the button saying the form is protected.
The important bit for spam like mine: a script that posts straight to the form has no score at all, because it never loaded the page where the check runs. My site now refuses any message without a valid score, before anything is saved or emailed to me.
Cloudflare Turnstile and hCaptcha do a similar job. Turnstile in particular is free and sets no tracking cookies, which makes it a good choice if privacy matters most to you.
When a captcha is not worth it
This is the part most guides leave out.
If you get one spam message a month, do not bother. Deleting it takes five seconds. Adding a check means another moving part, another company in your privacy notice and a small chance of turning away a real customer. A honeypot and a rate limit are enough for most small sites.
If your form is how most of your work arrives, be careful. Every check has false positives, meaning real people wrongly treated as bots. A score check can mark down someone on an old phone, someone using a privacy-focused browser, or someone who pasted their message in from an email. If you add one, set it up so that a refused person is told what happened and given your email address, not left staring at an error.
Google's version sets cookies. reCAPTCHA sets cookies and sends visit data to Google, which you need to mention in your privacy notice. On my site it only loads once someone starts filling in a form, not on every page, so people who just want to read never meet it.
It needs JavaScript. JavaScript is the part of a web page that makes it interactive. A small number of people browse with it switched off, and a captcha cannot work for them. My site now tells them to email me instead.
How I set mine up
For anyone curious, or anyone briefing their own web person, these are the rules I followed on my own forms:
- Checks in a sensible order. The rate limit first, then the honeypot, then the score, then the usual checks that an email address looks like an email address. Nothing is saved until a message has passed all of them.
- Check on the server, not just in the browser. The browser is the visitor's side, and a script can skip anything that happens there. The website itself has to ask Google for the score.
- Let messages through if Google is down. If the checking service does not answer within a few seconds, my form lets the message through. One spam message is a nuisance. A lost enquiry from a real customer is lost work.
- One check per form. Each form asks for a score labelled for that form, so a token taken from the newsletter box cannot be reused on the contact form.
- Keep a way to test it. I have an automatic check that sends a test enquiry after every update to make sure emails still arrive. It carries a secret that lets it skip the captcha, so protecting the form did not break the alarm that tells me the form is broken.
None of that is exotic, but each step is easy to get wrong, and a form that quietly drops real enquiries is worse than one that lets in a bit of spam. If you are not sure how your own form behaves, my free website health check is a quick place to start, and the website security page explains what I look after for clients.
What to do this week
- Look at your last month of form messages. Count the spam. If it is a handful, add a honeypot and leave it there.
- If it is more than you want to deal with, add a no-puzzle check such as Turnstile or reCAPTCHA v3, and make sure a refused visitor sees your email address.
- Never click a link in a form message you were not expecting, however official it looks. Money waiting for you is never real.
- Send yourself a test message after any change, from your phone, to make sure real enquiries still arrive.
If you would rather someone else sorted it, book a free consultation (opens in a new tab) and I will look at your form with you.


