Spam filtering

Formward applies several independent layers of spam protection. They run in order, and a submission stopped by an early layer does not proceed to later ones.

Layer 1: Origin allowlist

Before inspecting the submission body at all, Formward checks the request Origin header against the allowed origins list you configure per form. If the list is non-empty and the origin is not on it, the request is rejected with 403 immediately.

If the allowed-origins list is empty, any origin is accepted. That is useful during development, but not recommended for production forms.

Layer 2: Per-IP + per-form rate limiting

After the origin check, Formward counts recent submissions from the same hashed IP address to the same form within a rolling time window. If the count meets or exceeds the configured limit, the request is rejected with 429 Too Many Requests.

Rate limiting is applied before any submission is persisted to the database, so a flooding bot cannot fill your submissions table even while triggering the honeypot.

Layer 3: Honeypot (_gotcha)

If the rate limit passes, Formward checks the _gotcha field. If it is non-empty (i.e. a bot filled it in), the submission is stored with status: spam and a success response is returned, giving the bot no signal that it was caught. The submission never reaches the notification email and does not count against your monthly quota.

See Special fields for how to add the honeypot to your form.

Layer 4: AI spam scoring (Pro)

On Pro plans, submissions that pass the three layers above are enriched by the AI worker. The AI assigns a spam score from 0 to 100 and an isSpam boolean. If isSpam is true or the score is 80 or above, the submission is marked as spam and no notification email is sent. The submission remains visible in your dashboard with its spam verdict so you can review edge cases.

AI spam scoring is not available on the Free plan. Free-plan submissions are never sent to the AI provider.

Layer 5: Cloudflare Turnstile (optional)

Turnstile is a free, privacy-friendly CAPTCHA alternative from Cloudflare. Unlike Google reCAPTCHA it does not track your visitors across the web, and it is invisible or near-invisible for real users while stopping bots effectively.

To enable it:

  1. Go to your form's Settings, enable Bot protection (Turnstile), and paste your Cloudflare Turnstile secret key. You get both keys for free at dash.cloudflare.com → Turnstile.
  2. Add the Turnstile widget to your form HTML using your site key:
<!-- 1. Load the Turnstile script once, e.g. in <head> -->
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>

<!-- 2. Place the widget inside your <form> -->
<form action="https://formward.io/f/YOUR_FORM_ID" method="POST">
  <!-- ...your fields... -->

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

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

Note: Cloudflare rotates the Turnstile script continuously and does not publish a stable SRI hash for it. Adding integrity= would break the widget on every update. The security guarantee is server-side: Formward verifies the token directly with Cloudflare's API, so a tampered or absent widget response is rejected regardless of what runs in the browser.

When the widget is rendered it automatically appends a hidden cf-turnstile-response field to the POST body. Formward verifies this token with Cloudflare's API server-side. If the token is missing or invalid the submission is rejected with 403 Forbidden before any data is stored. Real users never see a challenge (they see nothing at all, or at most a brief animation).

Turnstile is available on all plans. When disabled (the default), no token is required and the field is ignored if present.

IP address privacy

Formward never stores raw IP addresses. On receipt the IP is immediately hashed with SHA-256 (truncated to 32 hex characters) and only the hash is written to the database. The hash enables rate limiting and abuse detection across requests without retaining a value that could identify an individual. Raw IP addresses are never written to disk or logs.

Summary

LayerMechanismPlans
1Origin allowlist - 403 if origin not permittedFree + Pro
2Per-IP + per-form rate limit - 429 on excessFree + Pro
3Honeypot (_gotcha) - silent spam mark, success response to clientFree + Pro
4AI spam score ≥ 80 - marked spam, no emailPro only
Form spam filtering, no reCAPTCHA | Formward Docs