All articles

Lead Generation

Stop Spam Form Submissions: 5 Contractor Filters

Your form spam is three problems, not one. A captcha solves the smallest, and Google's free tier fails open at 10,000 checks a month.

Om Patel 16 min read
Photo: Pawel Czerwinski / Unsplash

The short answer

Contractor form spam splits into three piles: scripted bots, paid humans in click farms, and agencies soliciting you. A captcha only catches the first. Layer a honeypot and timing check, an invisible challenge, and three content rules that work because a homeowner's message has a predictable shape, then keep the junk out of Google Ads.

Contractor form spam is not one problem. It is three arriving through one box, and the control most people install first solves only the smallest.

Pile one is scripted bots. Pile two is human beings paid to fill in forms. Pile three is agencies, SEO resellers and lead brokers soliciting you through the form you built to receive customers. A captcha is built for pile one. If you added one and the junk kept coming, nothing is broken. You just spent your effort on the smallest pile.

Generic guides also get one thing wrong for a trade. They are written for web developers and software marketers, whose inbound is patient. Yours is not. The most valuable message your form will ever receive comes from someone standing under a leak at eleven at night, and every second of friction you add to catch a bot is charged to that person first.

Sort the spam into three piles first

Open your last twenty junk submissions and label each one. The pile determines the fix.

PileWhat it looks likeWhat actually stops it
Scripted botsGibberish names, mismatched geography, links in the message, submitted in under two secondsHoneypot, timing check, invisible challenge
Paid humansPlausible but vague, real typing cadence, passes every automated checkRate limiting, content rules, making the attack uneconomic
SolicitationsFluent English pitching SEO, web design, financing or leads, addressed to you rather than about a jobContent rules, removing the contact page from search results

Most contractors have a pile three problem and have been buying pile one solutions. The tell: if the messages are grammatical, addressed to your company by name and selling something, no bot detection will help. There is no bot.

The constraint nobody writes for: your best lead is in a hurry

Cloudflare, publishing in 2021 on why it wanted to eliminate CAPTCHAs, estimated that humanity wastes about 500 years per day solving them. For most websites that is an abstract cost. For a trade it is a specific one, because your highest value inbound is also your least patient. A homeowner with water coming through a ceiling will not identify traffic lights. They will close the tab and call whoever answers.

So the rule for a contractor is stricter than the rule for everyone else: filtering belongs on the server, not in front of the customer. A developer on r/ProWordPress, laying out an anti spam stack built over years, ended on exactly that principle: "spam is the site owner's problem, not the user's, so spam prevention should not be a burden on the user." That eliminates image puzzles, math questions, multi step forms and email confirmation loops, which all work against bots and all cost you emergency calls. What follows is ordered so the controls that cost the customer nothing come first.

Filter 1: the honeypot and the clock

These two catch the majority of pile one, cost nothing, and are invisible to every real customer.

A honeypot is a field hidden from humans by CSS but present in the HTML. Scripts read the raw markup and fill everything they find. If it arrives populated, discard the submission.

Two details decide whether it works. Name it plausibly: bots skip fields called honeypot or nospam, so use a name a form would genuinely have, like middle_name, phone_ext or company_website. The last is nice judo on a contractor site, since a bot pitching you SEO is unusually eager to fill in a website field. And hide it with CSS, not type="hidden", because a hidden input is a standard field that well built scripts recognise and leave alone.

The clock is the other half. Stamp the time when the page renders, check it on the server when the form posts, and reject anything completed faster than a person could type. Three seconds is a safe floor. One developer on r/webdev does this with no third party at all, round tripping an HMAC signed timestamp: "The user will never know its even there, you collect 0 user information, and bots always get caught."

Tip

Both checks must run on the server. A validation that only runs in the browser is skipped entirely by anything posting directly to your endpoint, which is what a script does. If your form builder only offers client side validation, the check is decorative.

Filter 2: the invisible challenge, and what Google's does when you hit the cap

If you want a challenge layer, read this part carefully, because the default choice has a failure mode almost nobody knows about.

Google moved reCAPTCHA Classic onto Google Cloud. Its migration documentation sets out the timeline plainly: new Classic keys stopped being issued in Q3 2024, automated migration began in Q4 2025, and Q1 2026 was "Complete automated migration. API access locked for keys without a Google Cloud project." The part that matters operationally is further down the same page. The free tier is 10,000 assessments per month. Above that you must enable billing on a Google Cloud project. And here is the behaviour to understand before you rely on it:

Watch out

Google's documentation states that over quota SiteVerify requests fail open. They "return success:true with a score of 0.9", plus an error message noting the quota was exceeded. The stated reason is to avoid blocking valid users.

Read that as a contractor. If a spam run pushes you past 10,000 checks in a month and you have no billing account attached, your captcha does not start blocking. It starts approving everything, at a confident score, silently. The flood that exhausts the quota is the same flood the quota was meant to stop, and nothing on your site appears broken, so you find out from your inbox. CreateAssessment requests fail closed with a 429 instead, so which failure you get depends on the integration your form plugin uses.

Cloudflare Turnstile answers the same need differently. Its plan documentation lists the free plan with unlimited challenges and no monthly assessment cap to exhaust. Cloudflare's overview docs add three points that matter here: it embeds "without sending traffic through Cloudflare", so you do not move your DNS; it has an invisible widget mode; and it "does not access, store, or transmit user communications, form entries, or other page inputs."

reCAPTCHA on Google CloudCloudflare Turnstile (Free)
Free tier10,000 assessments per monthUnlimited challenges
Over quota behaviourSiteVerify fails open at score 0.9No assessment cap
Requires a cloud console projectYes, API locked without one from Q1 2026No
Invisible modeYes (v3 scoring)Yes
Accesses form contentsNot statedExplicitly does not

Practitioner reports line up. The top reply on an r/webdev thread asking for reCAPTCHA alternatives, at 60 upvotes, called Turnstile "the best state-of-art anti-bot protection currently". Another in the same thread had run both: "Even with hcaptcha we had tons of bot submissions on our forms, with turnstile we get none, even without the widget."

Most contractor forms are a generic contact box bolted onto a template, which is why they collect spam as efficiently as they collect customers. We build the lead generation system around a dedicated conversion page and a qualifying form that arrives with the answers already attached, so a real job is distinguishable from noise before anyone picks up the phone.

Get a lead plan

Filter 3: three content rules that only work for a trade

This is where most of your remaining spam dies, and it is the section a generic guide cannot write. Every business gets told to filter on content, and for most of them it is a blunt instrument, because a legitimate inquiry to a software company or a design agency can contain almost anything. A real inquiry to a trade has a narrow, predictable shape, and that predictability is an asset nobody is telling you to spend.

Rule one: reject any message containing a URL. Think about who sends you links. A homeowner whose furnace is making a noise describes the noise. They do not paste a website. An SEO reseller, a lead broker, a financing pitch and a link building bot all need you to click something, so a link is close to mandatory for them and close to unheard of for your customers. A developer on r/webdev put it bluntly: "If your contact form does not need links, just reject anything that looks like a URL, including the usual hxxp style obfuscation, and a lot of them will give up fast."

For a general contact form this is too aggressive, which is why you rarely see it recommended. For a residential trade it is close to a free win. If you also serve commercial clients who send plan links, apply it to the quote form only.

Rule two: require a service address, and validate it against your service area. Real work happens at a property. Spam has no address, because there is no job. A required postal code or street address, checked server side against the areas you actually serve, removes the entire category of submissions that are not about a location. It also catches the geographically absurd ones contractors keep reporting: the r/Contractor operator who restarted paused Google Ads and immediately got quote requests from "city/towns not even in my area or state." If your leads arrive from the wrong places for reasons other than bots, the channel by channel diagnosis is in why all your leads come from outside your service area.

Rule three: watch for procurement vocabulary. This is the newest pattern and the one that will matter most over the next year. A specialty residential contractor posted to r/Contractor that bid requests through their site were "getting better and better at sounding like a legitimate person", and named the tells: vagueness about the project and the site location, plus "verbiage that a normal person wouldn't use, like 'seeking a reputable company to handle the installation,' or 'scope of work to include, but not limited to.'"

That is what an AI written inquiry sounds like. A real homeowner writes "my AC is blowing warm and it's 30 degrees". They do not write "scope of work to include, but not limited to." A short list of formal procurement phrases, scored rather than blocked outright, catches a category that passes every technical check because a language model wrote it and a human pressed submit.

Filter 4: score, do not block

Score and quarantine. Do not delete. A developer on r/ProWordPress described the working version: assign points for each suspicious signal, then reject above a threshold. A link might be decisive by itself, while a .ru address, non English characters on an English only site, or an all caps subject line are each worth one point and conclusive together.

Two rules make this safe for a contractor. Route rejects to a folder, not the bin, and review it for a week: a false positive on a $14,000 job costs more than a hundred spam messages do. And fail quietly, showing a normal success page while dropping the submission server side. Telling a spammer they were blocked tells them what to change. As one r/webdev commenter put it, "silently ignore the contact form if it's from a given IP address. They won't notice likely and you won't be bothered by the extra form submissions."

Filter 5: keep the junk out of Google Ads

If you run ads, this is where form spam actually costs money, and blocking it at the form does not finish the job. Your form submission fires a conversion. Smart Bidding reads conversions as evidence the click that produced them was worth buying. Every fake submission is therefore a vote for more of whatever traffic produced it, and the algorithm obliges. You are not just wasting time reading junk. You are paying to train the system to buy more of it.

The trigger is consistent: it starts when a campaign launches or is unpaused. One r/PPC commenter explained why, noting that "fresh ad URLs tend to get scraped fast, and bots flood your forms with junk submissions that look like real conversions in Google Ads." The r/Contractor operator quoted earlier saw exactly this after unpausing a campaign that had previously delivered three or four legitimate quote requests a week.

Four things to check, in order of impact:

  1. Turn off Search Partners and Display expansion on search campaigns. This was the most upvoted answer on the r/PPC thread and removes a large share of low quality placements.
  2. Set location targeting to presence, not presence or interest. It is a per campaign setting, not an account level one.
  3. Stop counting unqualified submissions as conversions. Do not fire the conversion tag when the honeypot tripped, the timing check failed, or the address fell outside your service area.
  4. Send real outcomes back with offline conversion import. This fixes the cause rather than the symptom. As one practitioner put it, either move away from a conversion focused campaign "or implement offline conversion tracking and stop sending conversion data back to Google for fake/junk leads." When bidding optimises against booked jobs instead of form fills, spam cannot steer it at all.

When the spammer is a person

If grammatical, plausible messages still arrive after all of the above, you are past bots. Two things are happening.

Click farms. One r/webdev commenter described the labour model: "Some spam companies hire humans to fill in contact forms. The humans have to video record themselves filling in X amount of contact form to get their money." An engineer from hCaptcha, on the same thread, reframed the fix as economics rather than detection. Click farms "rely on speed to make money, so the best fix is to mess with their margins", and "if it costs too much to run the attack, they'll just move on to an easier target." You are not trying to identify them, you are trying to be the annoying target. Rate limiting is the cheapest version: two submissions per IP per hour is invisible to a real customer and ruins a farm's throughput.

Solicitations. These are people selling you marketing services who found you through search. The least known fix comes from an r/webdev operator who still had spam despite reCAPTCHA and two honeypot fields: they added noindex to the contact page and "was rid of the problem for six months." Your contact page does not need to rank, since customers reach it from your home page and services pages, so removing it from the index costs you nothing that matters. Whether to run a form at all is covered in contact form vs phone number on your website.

The setup, in order

Roughly 45 minutes, ordered by return per minute.

  1. Add a CSS hidden honeypot named company_website, rejected server side if filled.
  2. Add a server side timestamp check rejecting anything submitted in under three seconds.
  3. Add Cloudflare Turnstile in invisible or non interactive mode.
  4. Reject messages containing URLs on your residential quote form.
  5. Require a service address and validate it against your service area.
  6. Score a short list of procurement phrases and spam words. Quarantine, do not delete.
  7. Rate limit to two submissions per IP per hour.
  8. Add noindex to your standalone contact page.
  9. Turn off Search Partners and Display expansion, and set location targeting to presence.
  10. Stop firing conversions on submissions that failed any check above.

Review the quarantine folder daily for a week, then weekly.

What not to do

Do not add fields to slow bots down. Every extra field costs you real inquiries, and bots fill fields faster than customers do. You are taxing the wrong party. The same goes for blocking whole countries: a landlord arranging a repair from abroad is a real job.

Do not post a legal threat next to the form. The notice charging spammers a "convenience charge" circulates in small business communities periodically. Nobody consents to anything by submitting a form, no spammer will pay it, and it is the first thing a genuine customer reads before deciding whether you are easy to deal with.

Do not remove your email address and hope. A contractor on r/Contractor stripped their email from every platform and immediately named the cost: "some people do prefer to email and i might loose a few potential jobs from it." You do not win this by being harder to contact. You win it by being harder to automate against.

The bottom line

Sort the spam before you install anything, because the pile determines the fix. Put the honeypot and the timing check on the server, where they cost your customers nothing. If you use a challenge, know that Google's free tier fails open at 10,000 assessments a month and Cloudflare's does not cap challenges at all. Then use the advantage no other industry has: your customers describe a problem at an address, and almost nobody else filling in your form does.

Once the junk stops, the question becomes which surviving leads are real, which has its own tells. The four checks that answer it are in how to tell if a lead is fake.

Frequently asked questions

How do I stop spam form submissions on my contractor website?
Layer four cheap controls in order: a hidden honeypot field, a server side timing check that rejects submissions completed in under three seconds, an invisible challenge such as Cloudflare Turnstile, and content rules tuned to your trade. The single highest yield rule for a contractor is rejecting any message containing a URL, because homeowners describing a broken furnace do not paste links and marketing spammers almost always do.
Is reCAPTCHA free for a small contractor site?
Up to a point. Google's documentation puts the reCAPTCHA Enterprise free tier at 10,000 assessments per month, after which you have to enable billing on a Google Cloud project. Most contractor sites never come close, but a sustained spam flood counts against that same quota, which is exactly when you do not want to hit a cap.
What happens if I go over the reCAPTCHA free limit?
Google's migration documentation states that SiteVerify requests exceeding quota fail open. They return success true with a score of 0.9 plus an error message about the quota. In plain terms your captcha starts approving everything, including the bots, and nothing on your site visibly breaks. CreateAssessment requests behave the opposite way and fail closed with a 429 error.
Is Cloudflare Turnstile better than reCAPTCHA for a small business site?
For most contractors, yes. Cloudflare's plan documentation lists unlimited challenges on the free plan with no monthly assessment cap, it does not require routing your site through Cloudflare, and it offers an invisible widget mode. Cloudflare also states Turnstile does not access, store or transmit form entries, which removes a privacy question you would otherwise have to answer.
Will a captcha cost me real leads?
Interactive ones will. Cloudflare estimated in 2021 that humanity wastes roughly 500 years per day solving CAPTCHAs, and your inbound is more time sensitive than most: someone with water coming through a ceiling will close a puzzle and call the next company. Use invisible or non interactive modes and put your filtering on the server, where it costs the customer nothing.
Why did the spam start right after I turned on Google Ads?
Fresh ad landing page URLs get scraped quickly, and contractors on r/PPC and r/Contractor report junk submissions arriving within days of a campaign launching or being unpaused. Check whether Search Partners and Display expansion are enabled on the campaign, since those placements are a common source, and confirm your location targeting is set to presence rather than presence or interest.
Do spam form fills actually waste my ad budget?
Indirectly, and it is the expensive part. If your form submission fires a conversion, every fake one teaches Smart Bidding that the traffic which produced it was valuable, so the algorithm buys more of it. Blocking the spam at the form is only half the fix. The other half is sending qualified outcomes back to Google through offline conversion import so bidding optimises against real jobs.
What if a real person is filling out my form by hand?
That is a click farm or a solicitation, and no captcha will stop it because there is no bot to detect. An hCaptcha engineer responding on r/webdev framed the fix as economics rather than detection: these operations run on speed, so adding dynamic friction when something looks suspicious makes the attack cost more than it returns and they move to an easier target. Rate limiting, content rules and removing your contact page from search results all work on the same principle.
Done-for-you lead generation: a dedicated conversion page, a qualifying form that arrives with the answers attached, and lead-to-sale tracking, fed by targeted outreach and Meta ad campaigns we build and run.
Get a lead plan

Free tools

Find out what your site is costing you.

Enter your address and we check the real page. Scores are free and the itemised report lands in your inbox. No account, and we change nothing on your site.