Guide // Spam

Stop contact form spam without punishing your visitors

CAPTCHA is the reflex answer, and it is the wrong one to reach for first. It taxes every honest visitor to stop a bot that a hidden input would have caught for free, and screen-reader users, people with motor impairments, and anyone on a bad connection pay the highest price. Below are the layers that actually work, in the order you should add them.

The short answer

Most contact form spam comes from bots that fill every field and submit instantly. You stop them with a honeypot field a human never sees, a minimum time-to-submit check, and server-side content filtering. This blocks the large majority of automated spam without a CAPTCHA, which costs real visitors time and fails accessibility for many of them.

The minimal integration

A honeypot is a normal input, hidden from people and left empty by them. Bots fill every field they find, so a non-empty value is a reliable spam signal. Never hide it with `type="hidden"`. Bots skip those; hide it with CSS and keep it out of the tab order.

HTML
<form action="https://mtform.co/f/your-form-key" method="POST">
  <label>
    Name
    <input name="name" autocomplete="name" required>
  </label>

  <label>
    Email
    <input type="email" name="email" autocomplete="email" required>
  </label>

  <label>
    Message
    <textarea name="message" required></textarea>
  </label>

  <!-- Spam trap: hidden from people, tempting to bots. Leave it empty. -->
  <input
    type="text"
    name="_mtf_honeypot"
    tabindex="-1"
    autocomplete="off"
    aria-hidden="true"
    style="position:absolute;left:-9999px"
  >

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

Replace your existing <form> tag, or just change its action attribute. The browser navigates to a branded success page. Configure a redirect in Settings.

Step by step

  1. 01

    Add a honeypot field

    Add a text input that humans never see, positioned off-screen with CSS and marked aria-hidden with tabindex="-1". Any submission that fills it is automated.

  2. 02

    Add a time-to-submit check

    Record when the page rendered in a hidden field. Treat submissions that arrive within a couple of seconds as automated, because no human completes a form that quickly.

  3. 03

    Filter server-side, never in the browser

    Any check that lives only in client JavaScript is trivially bypassed by posting directly to your endpoint. The decision has to happen on the server that receives the POST.

  4. 04

    Lock the endpoint to your own origins

    Restrict which domains may submit to your form. A public endpoint that accepts posts from anywhere is a spam magnet regardless of the other layers.

  5. 05

    Review what was caught, do not just delete it

    Keep filtered submissions in a spam view for a retention window so you can recover a false positive. A filter you cannot audit will eventually eat a real customer enquiry without you ever knowing.

Hidden visually and from assistive technology, removed from the tab order, and with autocomplete off so a browser never fills it on a real visitor’s behalf.

Honeypot field, done correctly
<form action="https://mtform.co/f/your-form-key" method="POST">
  <label for="email">Email</label>
  <input id="email" name="email" type="email" required>

  <label for="message">Message</label>
  <textarea id="message" name="message" required></textarea>

  <!-- Honeypot: invisible to humans, irresistible to bots. -->
  <div aria-hidden="true" style="position:absolute;left:-9999px;">
    <label for="company">Company</label>
    <input id="company" name="_gotcha" type="text" tabindex="-1" autocomplete="off">
  </div>

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

Bots post the instant they parse the page. Stamping render time and rejecting sub-two-second submissions costs a human nothing. Nobody reads and fills a contact form that fast.

Time-to-submit check
<input type="hidden" name="_rendered_at" value="">
<script>
  document.currentScript.previousElementSibling.value = Date.now();
</script>

Common pitfalls

Hiding the honeypot with type="hidden"

Bots specifically skip hidden inputs because they know the trick. The field must be a normal visible-type input that CSS moves off-screen, otherwise it catches nothing.

Using display:none on the honeypot

Some bots parse computed styles and skip anything with display:none. Off-screen positioning is harder to detect and behaves identically for real users.

Silently discarding suspected spam

Every filter has false positives. Discarding without a reviewable spam folder means a legitimate enquiry disappears with no trace and no way to recover it.

Relying on client-side validation alone

A bot posts straight to your endpoint URL and never runs your JavaScript. If the check is not on the server, it is decoration.

Troubleshooting

Troubleshooting by error code
SymptomWhat is happeningFix
still spammedVolume continues after adding a honeypot.Check the field is not type="hidden" and not display:none, and confirm the server actually rejects on a non-empty value rather than only logging it.
false positivesReal enquiries are landing in spam.A password manager may be filling the honeypot. Add autocomplete="off" and give it an unusual name that no autofill heuristic recognises.
403Submissions rejected after adding origin rules.The posting domain is not on the allowed list. Add every origin you submit from, including the www and non-www variants.

Frequently asked questions

Do I need a CAPTCHA to stop contact form spam?

Usually not. A honeypot field, a time-to-submit check, and server-side filtering stop the large majority of automated spam. CAPTCHA adds friction for every legitimate visitor and creates real accessibility barriers, so it is worth trying as a last resort rather than a first line.

Is a honeypot field bad for accessibility?

Not when implemented correctly. Position it off-screen with CSS, set aria-hidden="true" on its wrapper, and give it tabindex="-1" so keyboard and screen-reader users never encounter it. Avoid display:none, which some bots detect.

Why am I getting spam when my form has JavaScript validation?

Because bots post directly to your form endpoint and never load your page or run your scripts. Client-side validation improves the experience for real users but provides no spam protection at all. The filtering has to happen server-side.

Should spam be deleted automatically?

No. Keep it in a reviewable spam view for a retention window. Every filter produces false positives eventually, and without a spam folder a legitimate enquiry is lost silently.

Ship this form for real

Create an endpoint, paste it in, and watch the first submission land in your inbox, in under three minutes.

Create free endpoint