# How to stop Webflow form spam

> Protect a Webflow form that posts to a form backend, where Webflow's own spam settings never run, with an off-screen honeypot and a human check.

Published 2026-10-25 · https://ikiform.com/guides/spam-protection/webflow

Webflow's reCAPTCHA, bot blocking and spam filter only work on submissions Webflow itself receives. If your form uses a custom action to post to a form backend, those settings never see the post, so the protection has to happen at the backend. Add an off-screen honeypot in the Designer, set your domains and rate limit on the backend, and turn on its human check, which works with the normal Webflow post and no code.

## What's different on Webflow

Webflow has its own spam tools: reCAPTCHA v2, a bot blocking setting that runs Cloudflare Turnstile, and a spam filter that reads each submission's content. They all live on Webflow's side, so they only act on posts that reach Webflow. The moment you set a form's **Send to** to a custom action, the browser posts straight to that URL. Webflow never sees the submission, so none of its checks run, however they are set.

Diagram: Where spam checks run for a Webflow form, with and without a custom action

1. When Webflow handles the form, the post goes to Webflow, which runs reCAPTCHA, bot blocking and its spam filter before storing it.
2. With a custom action, the browser posts the same form straight to Ikiform.
3. Webflow's checks never see that post, whatever their settings.
4. Ikiform runs the honeypot, scoring, rate limit and human check, then stores the post as received or spam.

Moving a form to a custom action moves its spam protection too. Set it up on the backend the same day.

## Webflow's own settings, after the switch

| Webflow setting | With a custom action | What to do |
| --- | --- | --- |
| reCAPTCHA element and validation | Not verified by anyone. Its `g-recaptcha-response` value arrives as an extra field | Remove the element. Turn reCAPTCHA validation off only if no form Webflow still handles needs it, because the setting covers every form on the site |
| Bot blocking | Doesn't apply to posts that go elsewhere | Leave it for any forms Webflow still handles |
| Spam filtering | Doesn't apply | Use the backend's content scoring instead |
| Form submission limits and notifications | Don't apply | The backend stores and emails instead |

The [Webflow guide](https://ikiform.com/docs/guides/webflow.md) in the docs covers pointing the Form Block at Ikiform. The steps below add the spam protection on top.

## Add the honeypot in the Designer

Webflow's quick way to hide an input is **Display: none**. Some bots skip fields hidden that way, so put the trap in an off-screen wrapper instead. It takes a minute and needs no paid plan:

- Inside the form, add a **Div Block** and give it a class such as `hp`. In the Style panel set **Position** to **Absolute**, **Left** to `-10000px`, **Width** and **Height** to `1px`, and **Overflow** to **Hidden**.
- In the Div Block's **Custom attributes**, add `aria-hidden` set to `true`, so screen readers skip everything inside it.
- Put a **Label** with the text **Leave this empty** and an **Input** inside the Div Block. Set the Input's **Name** to `_gotcha`, and add the custom attributes `tabindex` = `-1` and `autocomplete` = `off`.
- Don't tick **Required** on it. A required field nobody can see blocks every honest submit.

A filled `_gotcha` adds 5 to Ikiform's spam score, enough to reach the threshold of 5 by itself. You can rename the field per form under **Honeypot field** if a template you use already has a trap with another name.

## Name the fields for scoring

Webflow names each input after its label, so you get `Name`, `Email` and `Field 2`. Rename them in each input's settings to `name`, `email` and `message`. The names matter for spam scoring as well as for your data:

- A link in a name field, such as `name`, `first_name` or `subject`, adds 3. Spammers often put their URL there, and no real person does.
- An address on a disposable email domain adds 2, read from any field that holds an email address.
- Three or more links across the form add 2, and a known spam phrase adds 2.

## Turn on the human check

In the Ikiform form's settings, set **Spam check** to **Ikiform**. Nothing changes in Webflow. When the form posts the normal way, Ikiform answers with a short **Checking you're human** page on ikiform.com that runs Cloudflare Turnstile and sends the fields on, then the visitor lands on your **Redirect after submit** page. No Cloudflare account, keys or custom code.

If you added the docs' script to keep Webflow's success and error blocks, it posts with `fetch`, and a `fetch` post without a token gets `403 challenge_required`. This version handles that: it falls back to a normal post for the human check, and shows the wait time when a visitor hits the rate limit.

`Before </body> tag`:

```html
<script>
  document.querySelectorAll('form[action^="https://ikiform.com/f/"]').forEach((form) => {
    const wrapper = form.closest(".w-form");
    const done = wrapper?.querySelector(".w-form-done");
    const fail = wrapper?.querySelector(".w-form-fail");
    const button = form.querySelector('[type="submit"]');

    function showError(text) {
      const slot = fail?.querySelector("div") ?? fail;
      if (slot) slot.textContent = text;
      if (fail) fail.style.display = "block";
    }

    form.addEventListener("submit", async (event) => {
      event.preventDefault();
      const label = button?.value;
      if (button) {
        button.disabled = true;
        button.value = button.dataset.wait || label;
      }
      try {
        const response = await fetch(form.action, {
          method: "POST",
          headers: { Accept: "application/json" },
          body: new FormData(form),
        });
        const result = await response.json();
        if (result.ok) {
          form.style.display = "none";
          if (fail) fail.style.display = "none";
          if (done) done.style.display = "block";
          return;
        }
        if (result.error.code === "challenge_required") {
          form.submit();
          return;
        }
        showError(
          response.headers.has("Retry-After")
            ? `Too many messages. Try again in ${response.headers.get("Retry-After")} seconds.`
            : result.error.message,
        );
      } catch {
        form.submit();
      } finally {
        if (button) {
          button.disabled = false;
          button.value = label;
        }
      }
    });
  });
</script>
```

- `form.submit()` posts the form without firing the `submit` event, so the fallback never loops back into the script.
- Paste it under **Page settings** > **Custom code** > **Before </body> tag**, or in the site's footer code for every form. Custom code needs a paid site plan and only runs on the published site.
- It only touches forms whose action starts with `https://ikiform.com/f/`, so forms Webflow still handles are left alone.

## Allowed domains and the rate limit

Under the Ikiform form's **Allowed domains**, add your custom domain and your staging address, such as `your-site.webflow.io`. Never add `webflow.io` on its own: every Webflow site would match, including other people's. Posts from anywhere else are stored as spam, or refused if you choose **Reject**.

For a contact form, set **Rate limit** to Strict, 2 every 10 minutes per visitor. Nobody honest writes twice in ten minutes. A signup form on a busy launch day suits Relaxed, 20 a minute per visitor better. Every form starts on Standard, 5 a minute.

> A post judged as spam gets the same success answer as a real one, so a bot learns nothing. It is stored with the status `spam`, sends no notification email and no webhook, doesn't count toward your usage, and is deleted after 30 days. Every Monday, a workspace that blocked spam gets one summary email with the total, the busiest forms and the top reasons.

## Check it works

1. Publish to your `webflow.io` staging domain. Custom actions only post from the published site.
2. Submit the form normally. With the human check on, you see the check page briefly, then your thank-you page.
3. Inspect the published form and confirm the honeypot wrapper has `aria-hidden` and sits off-screen.
4. Post with the honeypot filled in, `_gotcha=bot`. It still gets a success answer, but the submission is stored as spam and sends no email or webhook.
5. Open **Submissions** in the dashboard. The new submission is there with every field you sent.
6. Nothing arrived? Switch the dashboard's status filter to **Spam**. Spam gets the same success answer as a real submission.

## Gotchas

- **Spam with Webflow's settings on.** If spam keeps arriving after you turned on Webflow's tools, check the form's **Send to**. A custom action bypasses all of them.
- **reCAPTCHA left in place.** With fields defined on the Ikiform form, a leftover `g-recaptcha-response` fails with `422 validation_failed` as an unknown field. Remove the element.
- **Duplicated forms.** Copying a form copies the honeypot input but not always its custom attributes. Check `tabindex` and `aria-hidden` on each copy.
- **Interactions on the wrapper.** A Webflow interaction that animates every Div Block in the form can move the honeypot into view. Exclude its class.

## Questions

### Why am I still getting spam on my Webflow form?

If the form uses a custom action, Webflow's reCAPTCHA, bot blocking and spam filter never see the post. Protection has to happen where the form posts. If Webflow handles the form, try turning on bot blocking alongside the spam filter.

### How do I add a honeypot to a Webflow form?

Add a Div Block inside the form, move it off-screen with absolute positioning, and give it aria-hidden true. Put an input named _gotcha inside it with tabindex -1 and autocomplete off, and don't make it required.

### Can I use reCAPTCHA on a Webflow form that posts to Ikiform?

No. Ikiform doesn't verify reCAPTCHA tokens. Remove the element and set the Ikiform form's Spam check to Ikiform, which runs Cloudflare Turnstile with no keys and no code in Webflow.

### Do I need a paid Webflow plan for spam protection?

Not for the honeypot or Ikiform's checks, which work with the plain Webflow form. Custom code, used to keep Webflow's success block on the page, needs a paid site plan.

## More guides

- [Stop contact form spam](https://ikiform.com/guides/spam-protection.md): Stop contact form spam with layers that cost real people nothing: a honeypot, timing, content scoring, rate limits and a human check only where needed.
- [Honeypot field](https://ikiform.com/guides/spam-protection/honeypot.md): Add a honeypot to any form that catches bots without tripping screen readers, keyboards or autofill, with the server check for every stack.
- [reCAPTCHA alternatives](https://ikiform.com/guides/spam-protection/recaptcha-alternatives.md): Compare reCAPTCHA alternatives for forms, from Turnstile and hCaptcha to proof-of-work and no captcha at all, then switch with a small, safe change.
- [Static sites](https://ikiform.com/guides/spam-protection/static-site.md): Stop spam on a static site form even though it can't keep a secret or count posts, with a honeypot partial, a safe script and server-side checks.
- [Cloudflare Turnstile](https://ikiform.com/guides/spam-protection/cloudflare-turnstile.md): Add Cloudflare Turnstile to a plain HTML form: the widget, server-side siteverify, test keys, and a way to run it with no keys or server of your own.
- [Without a captcha](https://ikiform.com/guides/spam-protection/without-captcha.md): Stop most form spam with no captcha at all: a honeypot, a signed render time, a content score and a rate limit, added together instead of used alone.
