Spam protection

Every endpoint filters spam automatically, so you get real messages without a captcha. The controls are deliberately fail-open: a signal only fires when its field is actually present, so a plain third-party embed that sends none of them still submits normally.

When a submission is judged to be spam it is silently accepted and dropped. The bot gets a success envelope so it does not retry or fall back, but nothing is stored, nothing is delivered, and the form's blocked-spam counter goes up.

Honeypot field

Add a hidden _hp input that a human never sees. Any submission that arrives with a non-empty value was filled in by a bot auto-completing every input:

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

This is on by default and can be turned off per form in the dashboard.

Fill timing

Stamp the page's render time (epoch seconds) into a _ts field. A submission that arrives less than 2 seconds later is machine-fast and is dropped:

<input type="hidden" name="_ts" value="">
<script>document.querySelector('[name=_ts]').value = Math.floor(Date.now() / 1000);</script>

The check only applies when the field is present.

Proof-of-JS token

GET /!<form_id>/token returns a short-lived signed token that only JavaScript on your page can fetch:

const { token } = await fetch("https://sendform.net/!a8Kz3mXq12/token", {
  headers: { Accept: "application/json" },
}).then(r => r.json());
// send it as the `antibot` field alongside the rest of the form

The token is stateless (HMAC-signed) and CORS-enabled, so it works cross-origin with no session. Two modes:

Form setting Behaviour
Require JS off (default) A token that is present must be valid; no token at all is accepted, so plain embeds keep working.
Require JS on A valid token is mandatory. Anything without one is dropped.

Submission cooldown

Contact forms enforce a 6-hour cooldown per email address per form. A repeat submission inside that window comes back with the cooldown error and a remaining_seconds value. This is always on and cannot be disabled.

Feedback forms use a different key: one vote per form, page and IP address per 12 hours. A repeat vote is answered with {"success": true, "duplicate": true} so the widget still shows its thank-you.

Email verification

A form's notification email must be verified before anything is delivered. Until then every submission is turned away with the unverified error, and SendForm nudges the form owner about it at most once a day. Extra (CC) recipients must be verified individually, and outgoing mail is DKIM/SPF signed.