Spam filtering

How a submission is checked before it reaches your inbox, what each layer does with a match, and which ones you can tune.

Works on every planUpdated Sep 22, 2026

The layers, in order

Every submission passes through the same checks, cheapest first. Most of them answer a bot with an ordinary success response, so it never learns which rule caught it. You see the result on the form's Spam tab.

LayerDefaultWhat happens to a match
Rate limitAlways onRefused with 429. See Rate limits.
HoneypotOnSuccess response, nothing stored, not billed.
Your block rulesNoneSuccess response, nothing stored, not billed.
Disposable emailOffSuccess response, nothing stored, not billed.
Turnstile challengeOffRefused with challenge_failed (403).
Content scoringStandardNear-certain spam: success response, nothing stored. Borderline: stored in the Spam tab.

Refused attempts never become submissions, so they cannot fill your inbox or use your quota. The top of the Spam tab counts them over the last 30 days, by reason, so an empty list of diverted messages does not mean nothing is happening.

Honeypot

A hidden text input that people never see and form-filling bots fill anyway. It is on for every new form. Add it to your markup and it starts working:

HTML
<input
  type="text"
  name="_mtf_honeypot"
  tabindex="-1"
  autocomplete="off"
  aria-hidden="true"
  style="position:absolute;left:-9999px"
>

Hide it off-screen as above. Do not use display:none or type="hidden", which many bots skip, and never mark it required. If you are moving from another service, the names _gotcha, _honeypot and _honey are treated as the honeypot too, so existing markup keeps working without an edit.

A caught submission still looks successful. The browser lands on the plain success page rather than your redirect, and a JSON caller gets a normal 201 body. If a test submission never shows up, check that your browser's autofill has not put a value in the hidden field.

Your own block rules

Under Block list on the Spam tab, add rules for things you already know you never want. A rule is an instruction, not a signal: a match is refused outright, whatever the score would have said. There are 5 kinds:

KindHow it matches
Word or phraseBlocks a submission if this appears anywhere in its text. Case-insensitive, and matched inside longer words.
Email domainBlocks any email field ending in this domain. Subdomains included, so blocking example.com also blocks mail.example.com.
IP addressBlocks a single exact IP address.
IP rangeBlocks a whole IPv4 range in CIDR notation, such as 203.0.113.0/24. One rule instead of the 256 an exact-address rule would need.
CountryBlocks every submission the edge places in this country, by two-letter code. Nothing is blocked when the edge cannot say where a request came from.

Each rule shows how many submissions it has matched and when it last did, so a rule that never fires is easy to spot. Each diverted message on the Spam tab also offers a Block action for its email domain or country.

Separately, you can refuse addresses from 69 known throwaway email providers. It is off by default, because a support desk or bug tracker has good reasons to accept one. Turn it on under Protection, then Adjust.

Turnstile challenge

For a form under sustained attack, turn on Cloudflare Turnstile. It is verified on our side before the submission is accepted, and it fails closed: if Cloudflare cannot be reached, the submission is refused rather than let through.

  • Create a Turnstile site in your own Cloudflare account and add every domain the form is embedded on. The keys are yours because Cloudflare ties a site key to hostnames.
  • Paste both keys into the Cloudflare Turnstile panel on the Spam tab. The secret is stored encrypted.
  • Put the widget snippet the panel shows inside your form. It writes the token to _mtf_turnstile_token; Cloudflare's default cf-turnstile-response works too.
  • Turn the challenge on only after the widget is live on every page.
Order matters. Once the challenge is on, any page posting without a token gets challenge_failed. Server-side calls made with an API key skip the challenge.

Content scoring and sensitivity

Every submission that gets this far is scored from 0 to 100 on signals such as link count, known spam phrases and repeated values. Two thresholds decide what happens, and you pick which pair applies under Protection, then Adjust:

SensitivitySpam tab fromRefused fromWhat you will see
Lenient90neverNothing is ever refused outright, and only near-certain spam is diverted. For forms that legitimately receive links, code, or long technical messages.
Standard8095The default. Obvious bulk spam is refused, borderline messages go to the Spam tab for you to check.
Strict5585Diverts anything with several links, sales phrasing, or the shape of a template. Expect to check the Spam tab, and to find the occasional real message in it.

A submission in the review band is stored with status spam. It sends no email, fires no webhook, Slack message or autoresponder, and waits on the Spam tab. Restoring one moves it to the inbox.

What counts against your quota

  • Anything refused (rate limit, honeypot, block rule, disposable email, challenge, or a score past the refuse threshold) is never counted.
  • A submission diverted to the Spam tab is stored so you can review it, but it is not counted. It still needs room under your limit to be stored, and restoring it to the inbox does not charge it later.
  • If an ordinary inbox submission turns out to be spam, Mark spam hands its unit back, once. Toggling it back and forth does not refund it again.

Next steps