Skip to content

Spam protection ​

BootForm has four independent layers of spam protection. All four live in the same place - open your form in the dashboard, go to the Settings tab, and look for the Spam protection section. You can turn on any combination of them; they don't conflict with each other.

LayerOn by default?Good for
HoneypotYesBots that fill in every field they find, and bots that post straight to your form's address
Cloudflare Turnstile CAPTCHANoMore sophisticated bots and scripted abuse
IP blocklistNoOne specific abusive sender you've identified
Country restrictionNoTraffic you only expect from certain countries

If you've never touched any of these settings, honeypot is already protecting your form - there's nothing you need to do. The rest of this page walks through each one, what it actually looks like when it catches something, and how to turn it on.

Honeypot ​

A honeypot is an invisible trap. BootForm puts a field in your form that a real person never sees and never fills in. A bot that fills in every field it finds fills that one in too, and a bot that skips your page and posts straight to BootForm doesn't know the field exists, so it never sends it. While the honeypot is on, either one marks the submission as spam: the field filled in, or the field missing.

The hidden field is called honeypot (a form can use another name, see below). If you use the HTML snippet BootForm gives you (from your form's Overview tab, or bootform_get_snippet over MCP), the field is already in it, under your form's name. It looks like this:

html
<!-- Required: BootForm's spam trap. Keep this hidden field and leave it empty. -->
<input type="text" name="honeypot" style="position:absolute;left:-9999px" tabindex="-1" autocomplete="off">

The field is required while the honeypot is on. If you write your own form HTML, copy that input from your form's snippet and put it anywhere inside your <form>. Keep the name exactly as the snippet has it, leave it empty, and keep it positioned off-screen. Don't hide it with display:none or visibility:hidden: some bots skip fields hidden that way. If you send submissions from code (fetch, curl, a server), include the field with an empty value, as in the examples, or turn the honeypot off for that form. You can see the current name under Settings → Spam protection → Honeypot, below the switch.

Why it's called honeypot: the name says what the field is, so whoever edits the page later (you, a colleague, or an AI agent) knows it's the spam trap and doesn't delete it or "fix" it as a field someone forgot. Keep autocomplete="off" on the field so a browser doesn't offer to fill it in.

Changing the name: Settings → Spam protection → Honeypot, then Rename next to the field name (shown while the honeypot is on). Use 1 to 64 letters, digits, underscores or hyphens, starting with a letter. Update the hidden field on your live page first: while the honeypot is on, a submission without the new name goes to spam, and the old name becomes an ordinary field. The dashboard warns you before you save.

Don't give your honeypot the name of a real field. BootForm treats the field with your form's honeypot name as the trap, and only that one, so a real field with the same name would send every genuine message to spam. The honeypot field is never stored, emailed or shown. Any other field is stored like any other field.

When you turn it on: the dashboard shows the field again and reminds you to add it, because a page built while the honeypot was off doesn't have it, and its submissions would otherwise all go to spam.

Which name your form has: a form you create in the dashboard uses honeypot. A form you started from an example (you posted to an ID in your page's HTML before signing up, then claimed it) keeps the name your page already sends. It also sets its honeypot switch from the first submission it received: if that submission carried the hidden field, the honeypot is on; if it didn't, it's off (so a hand-written form keeps working), and the name is set to honeypot, ready for when you turn the honeypot on. Forms you create in the dashboard start with the honeypot on. You can change either setting afterwards.

What happens when it catches something: the sender sees a completely normal "thanks, your submission was received" response. BootForm never tells a bot that it got caught, so it doesn't learn to try something else next time. On your side, the submission shows up under the Spam tab (not All submissions), and it doesn't count against your monthly submission quota. If a real message ever lands there, you can mark it as not spam.

Turning it off: Settings → Spam protection → Honeypot, flip the switch. Do this for a form whose submissions come from code that can't send the field, or if a browser extension or testing tool fills it in by accident on a form you control.

Cloudflare Turnstile CAPTCHA ​

Honeypot catches bots that aren't paying attention. CAPTCHA catches the more careful ones, at the cost of a small, usually-invisible check on the visitor's side. BootForm uses Cloudflare Turnstile - a free CAPTCHA service. You'll need your own free Cloudflare account, since BootForm doesn't run a shared one for every customer; you create your own widget and give BootForm its keys.

Step 1: create a Turnstile widget on Cloudflare ​

  1. Go to the Cloudflare dashboard and log in (or sign up - no credit card needed).
  2. In the left sidebar, click Turnstile.
  3. Click Add widget.
  4. Give it a name - this is just for your own reference inside Cloudflare, e.g. your form's name.
  5. Under Domain, enter the domain(s) where your form actually lives (e.g. mysite.com) - not bootform.com. This has to match the site your visitors will be on when they submit the form.
  6. Leave Widget Mode set to Managed (the default) - Cloudflare decides on its own whether to show a visible challenge, based on how suspicious the visitor looks.
  7. Click Create.
  8. Cloudflare shows you a Site Key and a Secret Key. Copy both somewhere safe now - the Secret Key is only ever shown this once.

Step 2: give BootForm the keys ​

In the BootForm dashboard: open your form → Settings → Spam protection → Cloudflare Turnstile CAPTCHA → Add (+). Paste in the Site Key and Secret Key from step 1, then Save.

If you're using BootForm's own HTML snippet (Settings tab), you're done - the snippet automatically includes everything Turnstile needs as soon as a CAPTCHA is configured, no further edits required.

Step 3 (only if you hand-wrote your own form HTML) ​

If your form's HTML isn't the one BootForm generated for you, add these two things yourself:

html
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>

<form action="https://f.bootform.com/{form_id}" method="POST">
  <input name="email" type="email" required />
  <textarea name="message"></textarea>

  <div class="cf-turnstile" data-sitekey="YOUR_SITE_KEY"></div>

  <button type="submit">Send</button>
</form>

Cloudflare's script finds that <div>, renders the widget in its place, and - once the visitor passes the check - adds a hidden field to the form for you automatically. You don't need to read or handle that value yourself; just make sure the <div> is somewhere inside the <form> before it's submitted. The hidden field is named cf-turnstile-response, so a form you send with fetch() and new FormData(form) carries it automatically; if you build the request body by hand, include that field. Without a valid token the submission is refused with 422 CAPTCHA_FAILED.

Only one CAPTCHA provider can be active per form at a time (Turnstile is the only one BootForm supports today). Editing or removing it later works the same way: Settings → Spam protection → Cloudflare Turnstile CAPTCHA → Edit or Remove.

IP blocklist ​

If you've noticed one specific IP address sending you junk - checked your submissions, seen the pattern, and want it hard-blocked - you can add it here. This is an exact match: blocking 203.0.113.5 does not block 203.0.113.6 or any other address in the same range. There's no support yet for blocking a whole range (a /24, for example) - just individual addresses.

Settings → Spam protection → IP blocklist → Add, type the address, and Save. A submission from a blocked address never reaches your form at all - not stored anywhere, not counted against quota, rejected instantly.

Country restriction ​

Restrict submissions to (or away from) specific countries, based on where the sender's IP address appears to be located. Two modes:

  • Block these countries - accept from everywhere else.
  • Allow only these countries - reject everyone else.

Settings → Spam protection → Country restriction → Add, pick the mode, add one or more countries from the dropdown (it lists every country by name - you don't need to know ISO codes), and Save.

Two things worth knowing:

  • If BootForm can't figure out where a submission is coming from (the lookup times out, or fails for any reason), that submission is never rejected by this rule, in either mode. A restriction you can't reliably enforce is worse than one that occasionally lets an unresolved visitor through - this is a deliberate choice, not a bug.
  • Country lookup works by matching the sender's IP address against a third-party IP-to-country database. Those databases are updated regularly but are never 100% accurate or complete - IP ranges get reassigned between countries, VPNs and proxies can put a visitor's apparent location somewhere they aren't, and mobile carriers in particular can report a country other than the one the visitor is actually in. Treat this as a strong filter, not a guarantee - it won't perfectly catch or exclude every submission from a given country.

The "Spam detected" reminder ​

Once a form has caught its first piece of spam (or has a spam alert) and doesn't yet have a CAPTCHA configured, the dashboard shows a one-time reminder suggesting you turn on Turnstile (or honeypot, if you somehow have it off). Two ways to dismiss it if you're not ready:

  • Remind me later - hides it until tomorrow, on this browser.
  • Never remind me again - hides it for this form for good, everywhere you log in.

Neither of these changes any of the actual protections above - they're purely about whether you see the nudge.

Spam alert ​

Some bots get past the honeypot: they leave every hidden field empty, so their messages land in your inbox like real ones. BootForm watches for that and tells you.

What triggers it. Once a day (07:00 UTC), BootForm looks at the last 7 days of the inbox of every form that is enabled and has no CAPTCHA yet. It counts the messages that look like spam: a link in a field, several messages from the same address within a minute, or the same message sent more than once. If at least 3 messages look like that, and they are at least 30% of the inbox, the form gets a spam alert. One real message with a link never trips it; a steady trickle of link spam does. The spam folder and archived messages don't count.

Nothing is ever moved. The alert is about the form, not any one message. Those messages stay in your inbox, where you can read them. Any check that guesses from what a message says will sometimes guess wrong, and a real message quietly moved to spam is a message you never read. So only fixed rules send a submission to the Spam folder: the honeypot, your own form rules, and your blocked IPs and countries (a failed CAPTCHA is refused before it's stored).

Where you see it. The Spam detected reminder shows on the form's page with what was seen, for example "In the last 7 days, 7 of the 12 messages in this form's inbox contained links", and the form's Submissions tab shows a banner with the same numbers and a Set up Turnstile link. Turnstile is the fix: it stops these bots before they reach you.

One email. When a form is first flagged, BootForm sends one email to your account's email address, with the same numbers (never the messages themselves or any IP address). There are no reminders. The alert ends when a daily check no longer finds the pattern, or when you set up a CAPTCHA or disable the form; if it comes back later, that's a new alert and you get one new email.

Stopping it. Never remind me again on the reminder hides the reminder and the banner for that form and stops its alert emails. Remind me later closes the reminder until tomorrow, on this browser; the one-line banner on Submissions stays. Setting up Turnstile ends the alert for good, since the form is then no longer checked.

Let an AI agent check it ​

If you've connected an AI agent through MCP, tell it you're getting spam. It can look at the form's spam protection and recent submissions, tell you what it sees, and fix the honeypot for you (turn it on, or give it a new name), including the line your page needs. It asks before moving or deleting any submission. Turnstile is the one step that stays here in the dashboard, because its secret key should never pass through an agent.

Response reference ​

The rest of this page is plain-language. If you're the one writing the code that submits to your form (or debugging why a submission didn't arrive), this section has the exact status codes and response bodies each layer produces.

Everything below is a POST https://f.bootform.com/{form_id} response. code is stable and safe to match on in your own code; error is a human-readable string meant for logs, not guaranteed to stay word-for-word identical between versions.

LayerStatuscodeSubmission stored?Counts against quota?
Honeypot200 (looks identical to success)(none - see below)Yes, filed as spamNo
Cloudflare Turnstile422CAPTCHA_FAILEDNoNo
IP blocklist403IP_BLOCKEDNoNo
Country restriction403COUNTRY_BLOCKEDNoNo

Honeypot is the one deliberate exception: the response is a plain {"ok": true} (or a normal redirect for a classic browser POST), identical to a real successful submission - this is the whole point, so a bot never learns it tripped something. There's no error code because, from the sender's point of view, nothing went wrong.

Cloudflare Turnstile:

json
{ "ok": false, "error": "CAPTCHA verification failed.", "code": "CAPTCHA_FAILED" }

IP blocklist:

json
{ "ok": false, "error": "This IP address is blocked for this form.", "code": "IP_BLOCKED" }

Country restriction:

json
{ "ok": false, "error": "Submissions from this country are not accepted for this form.", "code": "COUNTRY_BLOCKED" }

A classic (non-AJAX) browser form POST gets the same rejection as a redirect back to the form's page with ?bootform_error=CODE appended, instead of a JSON body - there's no script running on that request to read one. Send Accept: application/json or _format=json to always get JSON back regardless of how the form was submitted (see Responses and redirects).

Ordering, if more than one layer is configured: IP blocklist and country restriction are checked first (cheapest, no external calls), then honeypot, then CAPTCHA. A submission that would fail more than one check only ever reports the first one it hit.