How it works
Many form bots do not render the page. They read the HTML, find the form, and put a value in every input so that no required field is left empty. A honeypot exploits that habit: one extra input, hidden from people, that only a program would think to fill.
Your server checks it before anything else. Empty means the form probably came from a person. Filled means it certainly came from a program.
Building one that people never trip
The hard part is not catching bots. It is making sure no real person ever fills the field, because each one who does is a lost message you never hear about. Four details matter:
- Move it off screen rather than using
type="hidden"ordisplay: none. Bots that skip hidden inputs skip those too. - Take it out of the way of assistive technology:
aria-hidden="true"on its wrapper so screen readers do not announce it, andtabindex="-1"so a keyboard user never tabs into it. - Give it a name that autofill has no value for. Browsers and password managers fill fields that look like a name, an email or an address, and a person whose browser filled your honeypot looks exactly like a bot. Add
autocomplete="off", and try the form with the password managers your visitors use. - Fail quietly. Answer a filled honeypot the way you answer a real message, and throw it away. A bot told it failed can be adjusted.
<style> .hp { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }</style><form action="/contact" 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> <!-- The honeypot: people never see it, bots fill it in --> <div class="hp" aria-hidden="true"> <label for="website">Website</label> <input id="website" name="website" type="text" tabindex="-1" autocomplete="off" /> </div> <button type="submit">Send</button></form>server.post("/contact", async (req, res) => { // Anything in the honeypot means a bot filled it in. Answer as if it // worked, so the bot learns nothing, and keep nothing. if (req.body.website) { return res.redirect(303, "/thanks"); } // ...handle the real message});A second trap: time
A person takes at least a few seconds to fill in a form. Many bots take none. Recording when the page was served and refusing a submission that comes back too fast catches another slice of simple bots.
Two cautions. Sign the timestamp on the server, or the bot simply sends an older one. And keep the minimum short, because autofill and a short message can make a real person fast too.
Where honeypots fail
A honeypot only works on a bot that falls for it. These do not:
- Bots that drive a real browser. A headless browser renders the page, can tell which inputs are visible, and fills only those.
- Bots written for your form. Anyone who looks at the page source once can see the field and leave it out.
- People. Spam typed by people never touches a field the sender cannot see; see why spam gets past your CAPTCHA.
It can also fail the other way, which is worse because nobody notices: an autofill tool or a browser extension fills the field, and a real enquiry is discarded as a bot. Watch how many submissions the honeypot catches. A sudden change in either direction is worth a look.
Honeypot or CAPTCHA?
Both, usually, in that order. The honeypot costs nothing and removes the laziest bots before anything else runs. A challenge handles the bots the honeypot cannot see.
A classic CAPTCHA does that by asking the visitor to solve a puzzle, which brings back the friction a honeypot avoids. Challenge keeps it invisible: when the visitor presses Send, their browser runs a small proof-of-work check and the solution travels with the form. There is no field for a bot to discover and leave out. A bot that skips the check is refused, and one that runs it pays CPU time on every submission. It does not stop headless browsers outright; the proof-of-work explainer explains why.
For what a person typed, the layer is a content classifier such as Classify. The full stack, from honeypot to review queue, is in the guide to stopping contact form spam, and both products start free on one plan; see pricing.