# Detect spam form submissions in Google Sheets

`=HUNCH(text, question)` returns the probability, 0 to 1, that a form submission is spam, a fake signup, or a low-quality lead rather than a genuine inquiry. Point it at your form export and every row gets a number to sort on, instead of a name and a message you have to read one by one.

Updated 28 September 2026. Source: https://hunchsheet.app/formulas/detect-spam-form-submissions-google-sheets

## A blocklist only catches what it has already seen

A list of banned words or domains stops the spam pitch you have already read once and rewrites itself into a new one the next week: a new domain, a different opening line, the same offer to guarantee page-one rankings. Reading the submission for what it is asking, rather than for a word it contains, does not need to be rewritten every time the wording changes.

## Combine the fields, then ask

A form export usually carries name, email, and message in separate columns. Combine them into one cell before judging, so the model sees the whole submission at once.

```
=A2&" | "&B2&" | "&C2
```

```
=HUNCH(D2:D500, "Does this form submission look like spam, a fake signup, or a low-quality lead rather than a genuine business inquiry?")
```
In Excel: `=HUNCH.ASK(D2:D500, "Does this form submission look like spam, a fake signup, or a low-quality lead rather than a genuine business inquiry?")`

Column D is the combined text from the formula above; the probability formula points at that column, not at the three original ones separately. Full syntax is on the [HUNCH reference](https://hunchsheet.app/docs/hunch).

## Real outputs

Nine submissions to a contact form on a B2B software site, name, email, and message combined into one line each.

| Submission | Spam probability |
| --- | --- |
| Name: John Smith \| Email: john.smith@acme.co \| Message: Hi, we are looking for a tool to score inbound leads for our 40-person sales team. Can we set up a demo? | 0.17 |
| Name: asdkfj asdf \| Email: test123@mailinator.com \| Message: asdfasdf | 0.96 |
| Name: SEO Expert \| Email: backlinks@rank-boost-service.ru \| Message: I noticed your website could rank higher. We offer guaranteed page 1 rankings, contact us for a free audit. | 0.96 |
| Name: Maria Chen \| Email: maria@northwindlogistics.com \| Message: Following up from the webinar last week, would like pricing for the team plan. | 0.13 |
| Name: 123456 \| Email: xj8k2n@tempmail.com \| Message: | 0.93 |
| Name: Best Loans 4U \| Email: loans@quickcash-approve.info \| Message: Get approved for a business loan today no credit check click here | 0.96 |
| Name: Dave Okafor \| Email: dave.okafor@gmail.com \| Message: Curious if this integrates with Airtable before I buy. | 0.16 |
| Name: Test Test \| Email: test@test.com \| Message: test | 0.94 |
| Name: Priya Patel \| Email: priya@lumenhealth.io \| Message: We filled this out by mistake, please disregard, sorry. | 0.90 |

The row worth reading twice is Priya Patel's: a plausible name, a real-looking company domain, and a message that says the form was filled out by mistake, still scores 0.9. That is not the model mistaking a real person for a bot. The question asks whether the submission is spam, a fake signup, or a low-quality lead rather than a genuine business inquiry, and an accidental, disregard-this submission genuinely is not a business inquiry, even though nobody did anything wrong. If you only want to catch malicious and automated spam, not accidental submissions, narrow the question to say so; as written, it also catches this kind of row on purpose.

## The middle of the range

Six submissions picked to sit away from the obvious extremes.

| Submission | Spam probability |
| --- | --- |
| Name: Growth Partners Agency \| Email: hello@growthpartners.io \| Message: We help SaaS companies with SEO and link building, would love to chat about a partnership. | 0.70 |
| Name: R \| Email: r@r.com \| Message: pricing? | 0.51 |
| Name: Sasha Kim \| Email: sasha.kim@outlook.com \| Message: hi | 0.80 |
| Name: Free Gift Winner \| Email: claim-prize@bonus-reward.top \| Message: You have been selected, claim your free gift card now | 0.97 |
| Name: Tom Becker \| Email: tom@beckerconsulting.com \| Message: Not looking to buy right now, just researching options for next year, can I get on your mailing list? | 0.27 |
| Name: info \| Email: info@info.com \| Message: interested | 0.86 |

"R" asking only "pricing?" lands at 0.51, close enough to the middle that the model is telling you it genuinely cannot decide: a terse name and a one-word question look exactly like a low-effort probe and exactly like a real buyer typing fast on a phone. Compare the two rows with an ordinary-looking name and domain: "hi" with nothing else scores 0.8, while a full sentence explaining a genuine not-yet-ready interest scores 0.27. A plausible name is not enough on its own in either direction; the message still has to say something.

## Set a threshold

In these fifteen rows, genuine inquiries top out at 0.27 and obvious spam starts at 0.93, with the debatable rows, the agency partnership pitch, the bare "hi", the accidental submission, the generic info@ address, spread from 0.51 to 0.9. That gap between roughly 0.3 and 0.9 is wider than a single cutoff can cleanly split, which is exactly why it is a review band and not a hard line.

```
=SORT(FILTER(D2:D500, E2:E500>=0.3, E2:E500<0.9), 2, FALSE)
```

Auto-archive above the top of that range, forward anything below the bottom of it to sales without a second look, and read the middle band yourself for a week before you trust either edge.

> Tip: Read the middle band before you touch the top and bottom. Move the threshold based on what you find there, not on the number itself.

## Limits

- It does not check the email domain against a blocklist or verify deliverability. Combine a REGEXMATCH check against known disposable domains with the probability column for a stronger signal.
- It does not stop a submission at the point of entry. It scores what is already in the sheet; pair it with an Apps Script trigger on form submit if you want a live score on new rows.
- It will not catch everything. No filter does. Use it alongside a honeypot field or reCAPTCHA at the form itself, not instead of one.
- It does not check whether the same message was submitted from ten different addresses in a minute. That pattern lives in your timestamps, not the message text; a COUNTIFS on the message column plus a time window catches it separately.

Copy [the template](https://hunchsheet.app/template) to try this on your own form export. The [lead scoring guide](https://hunchsheet.app/formulas/lead-scoring-google-sheets) covers the same probability pattern for qualifying a lead once it clears this filter, and [REGEXMATCH vs asking a question](https://hunchsheet.app/formulas/regexmatch-vs-asking-a-question) goes deeper on why a keyword match misses cases like the ones above.

## Questions

### Can this replace reCAPTCHA on my form?

No. It scores text after the fact; it does not stop a bot from submitting in the first place. Use both: reCAPTCHA at the form, this column to triage what still gets through.

### Does it check whether the email domain is disposable?

Not directly. Combine a REGEXMATCH check against a list of known disposable domains with the probability column for a stronger combined signal.

### Will a genuine but very short inquiry get flagged as spam?

A short genuine message usually reads lower than an obvious spam pitch, but it also gives the model less to work with. Read anything in your middle band yourself before archiving it.

### Can it score submissions as they arrive instead of in a batch?

Not by itself. Sync new rows to the sheet with a Zapier connection or an Apps Script trigger on form submit, then point the formula at the combined text column as rows land.

### What is worse, marking a real lead as spam or letting spam through?

Missing a real lead usually costs more than a rep spending ten extra seconds on a spam row, so lean the threshold toward under-flagging until you have read a week of your own middle band and know how the two costs compare for your form.

