The reason most teams go looking for a way to prevent contact form spam without captcha is rarely the spam itself. Deleting forty junk submissions takes a few minutes. The damage is that the real enquiry sitting at position three gets skimmed past, and that every turn of the screw on the filter also blocks somebody who genuinely wanted to get in touch. Those two failures are not symmetrical, and a defence built without that in mind ends up optimised for the cheap one.
There is also a newer reason. The captcha that was free for a decade is being repriced.
What changed about the captcha option
Google's reCAPTCHA is now presented as part of Google Cloud Fraud Defense, and the developer page that used to explain how to choose between v2 and v3 is marked deprecated, pointing readers at the Fraud Defense documentation instead.
The pricing is published and worth reading closely. reCAPTCHA Essentials is free up to 10,000 assessments per month. The footnote is the part that catches people out: those free 10,000 assessments are per organization, and the limit aggregates use across all accounts and all sites. A company running six sites does not get six free allowances. Above that, reCAPTCHA Premium charges a flat 8 USD for 10,001 to 100,000 assessments and 1 USD per 1,000 assessments beyond 100,000, while Enterprise is a monthly volume commitment at 1 USD per 1,000 assessments on a minimum twelve month subscription.
Contact Form 7, the WordPress plugin that handles a very large share of the world's contact forms, puts a notice at the top of its own reCAPTCHA page saying Google plans to migrate all reCAPTCHA users to reCAPTCHA Enterprise and that this means a cost increase for many of them. So "without a captcha" is no longer only a usability argument. For some sites it is a budget line.
The four layers, and why stacking two of the same one does nothing
Every technique in this category sits in one of four layers.
Entry checks decide whether to accept the submission based on how it arrived: browser signals, timing, hidden fields. Content scoring sends the submitted text somewhere and gets back a verdict. Blocklists reject specific words and IP addresses. Triage is not prevention at all; it is the arrangement that lets a person find the real enquiry among what got through, and find the real enquiry among what got blocked.
Two tools from the same layer add very little, because they reject on the same evidence. Two invisible entry checks are both asking whether the interaction looks human, so a submission that defeats one usually defeats the other. An entry check plus content scoring is a real gain, because one looks at the arrival and the other looks at the text.
Most teams build the first three layers, discover the filter is still imperfect, and respond by tightening it. Building the fourth layer first is what makes it safe to leave the other three loose.
Invisible entry checks that are not captchas
Cloudflare Turnstile is the most direct substitute. The documentation describes it as a smart captcha alternative that can be embedded into any website without sending traffic through Cloudflare, and that works without showing visitors a captcha. It runs non-interactive JavaScript challenges, including proof of work and proof of space, and tunes difficulty per request.
The free plan is generous enough that the paid tier is mostly irrelevant for a contact form. Cloudflare lists it as: up to 20 widgets per account, unlimited challenges, 10 hostnames per widget, seven days of analytics lookback, all widget types, and WCAG 2.2 AAA compliance. The Enterprise plan adds unlimited widgets, up to 200 hostnames per widget, 30 days of analytics, ephemeral IDs, and the removal of Cloudflare branding.
One line in the Turnstile documentation matters for anyone handling enquiries that contain personal data: Turnstile processes only the data strictly necessary for the security function and does not access, store, or transmit form entries or other page inputs. Content scoring services, by design, do the opposite.
Contact Form 7's own documentation states plainly that unlike reCAPTCHA, Turnstile is free, and recommends it unless there is a specific reason to use reCAPTCHA. Setup is two keys pasted into the integration screen, with the widget placed at the top of the form by default and a form tag available to move it.
Why the interactive challenge is the part worth removing
The cost of a visible challenge is not evenly distributed. It lands hardest on the people least able to absorb it: anyone using a screen reader, anyone on a slow connection where the widget loads late, anyone whose browser or network configuration makes the risk score look unusual. Those visitors get the hard version of the puzzle repeatedly, and some of them give up on a form that everyone else passes without noticing it exists.
This is why the accessibility line in Cloudflare's plan comparison is worth reading rather than skipping. WCAG 2.2 AAA compliance is listed on the free tier, not held back for Enterprise. The mechanism that makes it possible is the same one that makes Turnstile invisible: the difficulty is tuned per request from signals gathered in the background, so the interactive puzzle is the exception rather than the default step every visitor walks through.
The practical version of that argument is simpler. A challenge nobody sees cannot be failed by the wrong person.
The honeypot, and its blind spot
A honeypot is a hidden field that a human never sees and a bot fills in anyway. Netlify's documentation describes the pattern precisely: mark the form with an attribute naming the hidden field, keep the field in the markup, hide it with CSS or JavaScript, and any submission that arrives with that field completed is rejected quietly. It costs nothing and the respondent's screen does not change.
The blind spot is in the same document. Submissions caught by a honeypot or by a captcha challenge do not even appear in the form's spam list. There is no record. If the hidden field is named something a browser's autofill recognises, such as an address or a name, real people will have it filled in for them and their enquiries will vanish with no trace anywhere. Name the field something autofill ignores, and test it with autofill switched on.
Content scoring, and what a spam check actually counts
Akismet is the default in this layer, and Contact Form 7 describes Akismet filtering as the centrepiece of its spam prevention strategy while recommending that several types of protection be combined.
The billing unit is the thing to understand before estimating cost. Akismet's pricing page defines a spam check, also called an API call, as happening each time Akismet checks a comment, form submission, or other content for spam. It is counted per check, not per enquiry that turns out to be real, so a form under attack burns through the allowance faster than the enquiry volume suggests. The Personal plan is pay what you can. The commercial Pro tier covers one site with 500 spam checks per month, scaling up in steps to four sites with 2,000 checks, and Business covers unlimited sites with 5,000 monthly spam checks. Akismet notes that protection keeps working if you occasionally exceed the monthly allowance.
Automated scoring is never perfect, which makes the reporting path part of the evaluation. Contact Form 7 requires the Flamingo plugin before false detections can be reported back, for a revealing reason: Contact Form 7 does not store submission data in the database at all. Without somewhere to keep the submission, there is nothing to reclassify.
Word and IP blocklists
When the same text or the same source keeps arriving, a blocklist stops it today. In WordPress this is the disallowed list, which Contact Form 7 borrows from the comment system: Settings then Discussion, the Disallowed Comment Keys box, one word or one IP address per line. Anything matching is treated as spam and never delivered. To find the source address, the plugin offers a mail tag that prints the sender's IP in the notification email.
The limitation is structural. Text can be rewritten and an IP address can be changed. Treat a blocklist as the thing that stops the current wave while the entry layer gets sorted out, and keep generic words out of it. A blocklist entry for a common commercial term will silently eat real enquiries.
The options side by side
Prices are as published on each vendor's own pages in September 2026.
| Option | Layer | Cost | Respondent effort | Are rejections visible |
|---|---|---|---|---|
| Cloudflare Turnstile | Entry | Free plan, unlimited challenges, 20 widgets | None in managed mode | No |
| reCAPTCHA Essentials | Entry | Free to 10,000 assessments per organization | None with v3 | No |
| Honeypot field | Entry | Free, self implemented | None | No |
| Akismet | Content | Personal pay what you can, Pro from 500 checks per month | None | Yes, in a spam list |
| WordPress disallowed list | Blocklist | Free | None | No |
| Form tool with response management | Triage | Varies | None | Yes, with status and owner |
The pattern in that last column is the argument for the fourth layer. Three of the six approaches reject things without leaving any evidence, which means a drop in submissions cannot be interpreted. Fewer enquiries could mean the bots stopped, or it could mean real people are being turned away.
Netlify's arrangement is a good model for what triage looks like: every submission passes through Akismet, the ones that pass appear in a verified list, the ones that fail appear in a separate spam list, and a submission's state can be switched either way. Applied to your own intake, that means keeping the invisible entry checks loose because they leave no record, being stricter in the content layer because that one does, and reading the spam list once a week.
Proving the filter works
Content scoring can be tested directly. Contact Form 7 documents two reserved strings for this: submit the form with the name field set to viagra-test-123, or the email field set to [email protected], and Akismet must return a spam verdict, which the plugin shows as an orange bordered error. Running that once catches a mistyped key before it matters.
Entry checks cannot be tested from a browser, so the evidence has to be counted instead. Split submissions into real and junk for two weeks before the change and two weeks after, and compare both numbers. A single total is useless here. It falls when the bots are blocked and it falls when the humans are, and those need different responses. That is also the argument for keeping intake somewhere each submission carries an owner and a status, as set out under what a response record holds, rather than in an inbox where the count is the only thing you can see.
What to change first
Add a honeypot with a name autofill ignores, then put content scoring in front of a spam list you can actually open, rather than one that deletes. Only tighten the entry layer once you can see what the filter is rejecting, which is the part a form tool with response management is for, and which is worth checking against Halict or anything built the same way.
Q1. Is a honeypot enough on its own?
For low volume forms it often is, because most automated submissions fill every field they find. It stops being enough when a form is targeted specifically, since a script written against one site can be told to skip the hidden field. Pair it with content scoring, which inspects the text rather than the arrival.
Q2. Does removing the captcha increase spam a lot?
It depends on which layer replaces it. Swapping a visible challenge for Cloudflare Turnstile changes almost nothing about what gets through, since Turnstile runs the same kind of non-interactive checks in the background. Removing the challenge with nothing in its place is what produces the jump.
Q3. Is Cloudflare Turnstile really free?
Cloudflare's plan page lists a Free tier with unlimited challenges, up to 20 widgets per account, 10 hostnames per widget and seven days of analytics. The paid tier exists for unlimited widgets, 200 hostnames per widget, 30 days of analytics, ephemeral IDs and removing Cloudflare branding, none of which a contact form typically needs.
Q4. Will a spam filter reject genuine enquiries?
Yes, at some rate, and the only question is whether you find out. Content scoring services keep the rejected submissions where you can review and reclassify them. Honeypots and captcha challenges discard them with no record at all, so a false positive there is invisible to everyone except the person who did not get a reply.
Q5. What about blocking submissions by IP address?
It works immediately and stops working as soon as the source changes, so it belongs in the toolkit as a way to stop a wave in progress rather than as a standing defence. In WordPress the list lives in Settings then Discussion, one address per line, and the sender's address can be printed into the notification email with a mail tag.