The idea, in plain English
Spam bots are lazy readers. They don't look at your page the way a person does — most of them fetch the raw HTML, find the <form>, and stuff a value into every input they can see in the code. Name, email, message, whatever's there: filled, submitted, on to the next site. Thousands of forms an hour.
A honeypot exploits exactly that laziness. You add one extra field to your form and hide it with CSS so no human ever sees it:
- A real visitor fills in the fields they can see and submits. The hidden field arrives empty.
- A bot reads the HTML, sees what looks like one more field, fills it, and submits. The hidden field arrives with a value.
The server-side rule is then a single line of logic: if the hidden field has anything in it, throw the submission away. No puzzle for users to solve, no third-party scripts, no privacy implications — the bot convicts itself. The name comes from security research, where a "honeypot" is a decoy set out so attackers reveal themselves by touching it.
A complete working example
Here's a contact form with a honeypot, in full. The trap is the botcheck field:
<form action="https://splitforms.com/api/submit" method="POST">
<input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
<!-- The honeypot: humans never see this -->
<input
type="text"
name="botcheck"
class="hp-field"
tabindex="-1"
autocomplete="off"
aria-hidden="true"
/>
<!-- The real fields -->
<input type="text" name="name" placeholder="Your name" required />
<input type="email" name="email" placeholder="Your email" required />
<textarea name="message" placeholder="Your message" required></textarea>
<button type="submit">Send</button>
</form>And the CSS that hides the trap — in your stylesheet, not inline (more on why below):
.hp-field {
position: absolute;
left: -9999px;
top: -9999px;
height: 0;
width: 0;
opacity: 0;
pointer-events: none;
}Three attributes on the input do quiet but important work: tabindex="-1" keeps keyboard users from tabbing into an invisible field, aria-hidden="true" keeps screen readers from announcing it, and autocomplete="off" stops browser autofill from accidentally springing your own trap on a real visitor.
If you point this form at splitforms, you're already done — there's no server code to write. The backend recognizes botcheck as a honeypot name and silently rejects any submission that arrives with it filled, before it ever hits your inbox or dashboard.
What to name the field (it matters)
The honeypot only works if a bot takes the bait, so the field name should look worth filling. Two naming strategies, both effective:
- Mimic a real field. Names like
confirm_email,website, orphone2are irresistible to bots that pattern-match field names to known data types.confirm_emailis particularly effective — bots happily paste their email into it. - Use a conventional trap name. The industry has converged on a recognizable set:
_gotcha(popularized by form services),botcheck,hp,honey,trap,do_not_fill,leave-blank. These are what form backends look for automatically.
splitforms checks all of the above server-side — botcheck, confirm_email, _gotcha, hp, honey, trap, do_not_fill, and leave-blank — so whichever you pick from that list, the rejection logic is already wired up.
One name to avoid: honeypot itself. The better-written spam scripts maintain skip-lists of obvious trap names, and you don't want your trap labeled as one.
How to hide it (and how not to)
Hiding technique determines which bots you catch. Ordered from weakest to strongest:
type="hidden"— don't use this for the trap. Bots know hidden inputs carry tokens and IDs they should preserve, not fill. Many will leave it untouched, and your trap catches nothing. (Hidden inputs are for things like your access key.)- Inline
style="display:none"— works, but visible. It defeats the naive bots, but the hiding is announced right there in the HTML, where a slightly smarter script can read it and skip the field. - A CSS class in your stylesheet — better. Now the bot has to fetch your CSS, parse it, and connect the class to the rule before it can tell the field is hidden. The overwhelming majority of spam scripts don't bother.
- Off-screen positioning — best.
position: absolute; left: -9999pxdoesn't even use the words "hidden" or "none." The field is technically rendered, just nowhere a human can see — only a bot running a full layout engine can detect it.
Whichever level you choose, pair it with the accessibility trio from the example above (tabindex="-1", aria-hidden="true", autocomplete="off"), and consider a visually-hidden label reading "leave this field empty" as a final safety net for anyone who encounters it through assistive tech.
The honest limitations
A honeypot stops the high-volume, low-effort majority of form spam — which is most of it by count. Here's what it doesn't stop:
- Headless-browser bots. Bots built on real browser engines apply your CSS, see the page as a human would, and only fill visible fields. They sail past any honeypot.
- Targeted scripts. If someone writes a bot for your form specifically (common once a site is worth attacking), they inspect it once, note the trap, and hardcode around it.
- AI-generated spam. The modern wave — LLM-written messages that read like genuine inquiries — often arrives through the visible form exactly as a human would submit it. No field-level trick detects it; you need content-level analysis. (More on this in AI form spam detection.)
- Human spam farms. Paid humans filling forms see what humans see. The honeypot stays empty.
This is why honeypot-vs-CAPTCHA is the wrong framing — the real answer is layers. A typical production stack: honeypot (catches dumb bots, zero user friction) + time-trap (a submission completed in under two seconds wasn't typed by a human — splitforms enforces this with its form_loaded_at timestamp) + rate limiting per IP + content classification for the spam that looks human. splitforms ships all four on every plan, including free, which is how it avoids making your visitors solve traffic-light puzzles. For the comparison with CAPTCHA approaches, see honeypot vs reCAPTCHA and reCAPTCHA alternatives.
Implementation checklist
The whole technique, compressed into something you can verify in two minutes:
- Add one text input with a tempting or conventional trap name (
botcheck,confirm_email,_gotcha). - Hide it with off-screen positioning from a stylesheet — not
type="hidden". - Add
tabindex="-1",aria-hidden="true",autocomplete="off". - Reject server-side on any non-empty value — silently. Return the normal success response so bots don't learn they were caught. (Using splitforms? This step is already done.)
- Test both paths: submit normally and confirm delivery; then fill the trap via dev tools and confirm the submission is dropped.
- Layer it: time-trap, rate limiting, and content filtering for everything the honeypot can't see. The full checklist lives in server-side form spam protection.
FAQ
What is a honeypot field in one sentence?
A honeypot is a form field that's hidden from human visitors but visible in the page's code — real people leave it empty because they never see it, while spam bots auto-fill every field they find, so the server can safely discard any submission where the honeypot arrives with a value.
Why is it called a honeypot?
It borrows the name from security research, where a 'honeypot' is a deliberately attractive decoy — a fake server or account set up to lure attackers so they reveal themselves. The form-field version is the same idea in miniature: the hidden input is bait. A bot can't resist filling in a field named 'email' or 'website', and the moment it does, it has identified itself as a bot.
Will a honeypot ever block real users?
Almost never, but there are two edge cases worth knowing. First, aggressive browser autofill can occasionally populate a hidden field if it's named like a real field (one more reason to set autocomplete='off' on the trap). Second, some screen-reader users could encounter the field if it's hidden with the wrong technique — which is why you hide it with positioning or display:none plus aria-hidden and tabindex=-1, and label it 'leave this field empty' as a safety net. Done properly, the false-positive rate is effectively zero, which is exactly why honeypots beat CAPTCHAs on user experience.
Should I use display:none or off-screen positioning to hide the honeypot?
Both work today; off-screen positioning is the slightly stronger choice. Naive bots don't apply CSS at all, so either defeats them. A more careful bot might parse inline style='display:none' and skip the field — moving the hiding rule into a stylesheet, or positioning the field off-screen with position:absolute; left:-9999px, makes the trap harder to detect programmatically. Whichever you choose, add tabindex='-1', aria-hidden='true', and autocomplete='off' so keyboard users, screen readers, and autofill all stay out of it.
What should I name a honeypot field?
Something a bot wants to fill and a script won't flag as decorative. Two schools: tempting names that mimic real fields ('confirm_email', 'website', 'phone2') and conventional trap names used across the industry ('_gotcha', 'botcheck', 'hp', 'honey', 'do_not_fill', 'leave-blank'). splitforms watches for a whole set server-side — botcheck, confirm_email, _gotcha, hp, honey, trap, do_not_fill, and leave-blank — so any of those names works out of the box. Avoid naming it literally 'honeypot', which sophisticated bots are trained to skip.
Do honeypots still work against modern AI spam bots?
Against the bulk of spam — yes, because most spam still comes from cheap, high-volume scripts that POST to every form they find without rendering the page. Against the sophisticated tail — headless browsers that apply CSS and only fill visible fields, AI-written messages submitted through the real form, and human spam farms — a honeypot is blind by design. That's why production systems layer defenses: honeypot for the cheap bots, time-traps for the fast ones, rate limiting for the persistent ones, and content classification for spam that looks human.
Do I need to build a honeypot myself if I use a form backend?
With splitforms, no server code is needed: add one hidden input named from its recognized list (for example 'botcheck') to your form, and the backend automatically rejects any submission that arrives with that field filled — before it reaches your inbox or dashboard. It's one line of HTML. splitforms also layers a time-trap and an AI spam classifier on top, so the honeypot is the first filter rather than the only one.
Keep going on spam defense: stop contact form spam, the complete spam protection guide, best CAPTCHA options, and the splitforms security page.
Want a honeypot that works without any server code? Get a free splitforms access key — add one hidden input named botcheck and every submission is filtered server-side.