What is a honeypot field?
It's a form field no human sees, most bots can't resist, and it costs you nothing — until you meet a bot that reads CSS.
Contents
A honeypot field is a form input that no human ever sees. You hide it with CSS, mark it inert for assistive tech, and leave it empty. Real visitors never touch it because their browser never shows it to them. Automated bots, which read the raw HTML and fill in every field they find, walk straight into it. When a submission arrives with that field filled, you have your answer: not a person. Drop it, and move on.
It is the cheapest bot filter you will ever ship. No CAPTCHA, no puzzle, no third-party script, no cookie banner. Boundstone's own waitlist form runs one — a hidden website field that a real signup leaves blank. This post covers how it works, how to build it, and the exact line where it stops being useful.
Why the trick works
A naive bot does not look at your page the way a person does. It fetches the HTML, walks the DOM, and fills every input it can find — text fields, email fields, anything with a name. Then it submits. It never renders your CSS, never respects visibility, and never wonders why there is a "Website" box on a newsletter signup.
A human does the opposite. They fill in what they can see and ignore the rest, because the rest is invisible to them. So a filled hidden field is a near-certain sign of automation. You are not blocking bots by being clever; you are letting them announce themselves.
Building one
Add a field that looks tempting and hide it off-screen. Do not use type="hidden" — some bots skip hidden inputs on purpose. Position it out of view instead, and mark it aria-hidden with tabindex="-1" so keyboard and screen-reader users never land on it either.
<form method="post" action="/waitlist">
<label for="email">Email</label>
<input id="email" name="email" type="email" required>
<!-- Honeypot: hidden from people, tempting to bots. Stays empty. -->
<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">Join the waitlist</button>
</form>
.hp {
position: absolute;
left: -9999px;
width: 1px;
height: 1px;
overflow: hidden;
}
Now check it on the server. This has to be server-side — a client-side check is trivially bypassed, since the bot never runs your JavaScript anyway. When the honeypot arrives non-empty, return a normal-looking success response and store nothing. Answering with an error tells the bot it tripped a trap; a bland 200 teaches it nothing.
export default {
async fetch(request) {
const form = await request.formData();
// A person can't fill a field they were never shown.
if (form.get("website")) {
// Look successful, save nothing, tell the bot nothing.
return new Response("OK", { status: 200 });
}
const email = form.get("email");
// Real submission: validate it, store it, send it.
return new Response("OK", { status: 200 });
},
};
That is the whole mechanism. A few lines of HTML, a rule of CSS, one if.
The limits, said out loud
A honeypot catches the lazy majority of bots and nothing more. A crawler that renders your page, respects visibility, or was hand-tuned for your specific form will read the trap and skip it. Raise the value of getting through your form, and the bots that show up get smarter.
It also catches exactly zero human fraud. A person typing a burner address by hand leaves the honeypot empty and sails through, because they never saw it — the trap was never aimed at them. The honeypot tells you a submission was automated. It tells you nothing about whether the data inside it is real.
That distinction is the point. Treat the honeypot as a first, free filter, not a wall.
Validate what got through
This is where Boundstone fits — and it is worth being precise about what it does and does not do. Boundstone does not detect bots and does not provide honeypots. You build those yourself with the few lines above. What Boundstone does is validate the email, phone, or IP that the form collected, and report exactly which checks it ran.
Run the surviving email through the API from your server, using your secret key:
curl https://api.boundstone.io/v1/verify/email \
-H "Authorization: Bearer bs_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com"}'
{
"valid_syntax": true,
"domain": "example.com",
"mx_found": true,
"disposable": false,
"role_account": false,
"free_provider": false,
"checks": {
"performed": ["syntax", "mx", "disposable_list", "role_list"],
"not_performed": ["smtp_mailbox", "catch_all"]
}
}
The checks object is the honesty contract. performed lists ["syntax", "mx", "disposable_list", "role_list"] — the API confirmed the address parses, the domain has mail records, it is not on a disposable-domain list, and it is not a role address like admin@. not_performed lists ["smtp_mailbox", "catch_all"] — it did not knock on the mailbox, and it did not test for catch-all domains. That second list is the reason you can trust the "valid": you know precisely what was and was not checked, so nothing is dressed up as more than it is.
Layer the signals
One weak signal plus another weak signal beats either alone. The honeypot answers "was this automated?" Validation answers "does this address parse, and can its domain even receive mail?" A disposable-domain flag answers "does this person want to be found?" None of them is decisive; together they sort your inbox from your garbage.
We go deeper on stacking these in multi-signal signup fraud and on the broader pattern in how to detect fake signups. If you are wiring this into a real signup flow, the signup-fraud use case walks the whole path end to end.
The short version
- A honeypot is a form field hidden from humans that bots fill automatically; a non-empty value means bot — drop the submission.
- It is free and frictionless. No CAPTCHA: hide the field off-screen, check it server-side, and silently succeed on a hit.
- It catches naive bots only. Sophisticated bots read the trap, and human fraud never touches it.
- Pair it with input validation. Boundstone does not detect bots — it validates the email, phone or IP the form collected, and lists every check it ran and skipped.
- The free tier is 250 credits a month, no card, and credits never expire — enough to validate a small form's traffic and see the contract for yourself.