TL;DR: A honeypot is a hidden form field that bots fill out and humans don't. When the field contains data, you reject the submission. It's invisible, requires no user interaction, and blocks most automated spam.
Your contact form is getting hammered. Dozens of spam submissions per day. You could set up a CAPTCHA, but that means integrating a third-party service, managing API keys, and dealing with the UX cost: 15% of users abandon forms when faced with a CAPTCHA challenge.
Honeypots are simpler. A few lines of HTML and CSS, a server-side check, and you're done. No external dependencies, no API costs, no user friction. They won't stop every bot, but they'll stop most of them, and your legitimate users won't notice they exist.
How It Works
A honeypot exploits a fundamental difference between humans and bots:
- Humans fill out visible fields and ignore what they can't see
- Bots parse HTML and fill out every field they find
You add a form field that's hidden via CSS. Humans never see it. Bots fill it out. If the field has a value when the form is submitted, you reject it.
<form action="/submit" method="POST">
<label for="email">Email</label>
<input type="email" name="email" id="email" required />
<!-- Honeypot: hidden from humans, visible to bots -->
<div class="form__alt" aria-hidden="true">
<label for="website">Website</label>
<input type="text" name="website" id="website" tabindex="-1" autocomplete="off" />
</div>
<button type="submit">Subscribe</button>
</form>
<style>
.form__alt {
position: absolute;
left: -9999px;
width: 1px;
height: 1px;
overflow: hidden;
}
</style>
Server-side validation:
[HttpPost("subscribe")]
public IActionResult Subscribe([FromForm] SubscribeRequest request)
{
// Honeypot check: if filled, it's a bot
if (!string.IsNullOrEmpty(request.Website))
{
logger.LogWarning("Honeypot triggered from {IP}", HttpContext.Connection.RemoteIpAddress);
// Return 200 to avoid revealing the trap
return Ok();
}
// Process legitimate submission
await subscriptionService.AddAsync(request.Email);
return Ok(new { success = true });
}
Implementation Details That Matter
Field Naming
Don't name your field honeypot or trap. Bots look for obvious names and skip them.
| Bad Names | Good Names |
|---|---|
honeypot |
website |
trap |
company |
spam |
fax |
bot-check |
mobile |
Use names that look like legitimate optional fields. Bots expect forms to have fields like website or company and will fill them.
Hiding Techniques
Don't use:
-
type="hidden": Bots know to skip these -
display: noneinline: Bots detect inline styles -
visibility: hidden: Easily detected
Do use:
- External CSS with positioning off-screen
-
aria-hidden="true"for accessibility -
tabindex="-1"so keyboard users skip it -
autocomplete="off"to prevent browser autofill
Response Strategy
When a honeypot catches a bot, return a success response. If you return an error, the bot operator learns their submission was detected and can adjust.
// Good: Silent rejection
if (isHoneypotFilled)
{
return Ok(); // Bot thinks it succeeded
}
// Bad: Reveals the trap
if (isHoneypotFilled)
{
return BadRequest("Bot detected"); // Bot operator learns to avoid this
}
Adding Time-Based Detection
Bots submit forms instantly. Humans need time to read and type.
Add a timestamp when the page loads. Check how long the submission took. Reject anything faster than a reasonable threshold.
<input type="hidden" name="form_time" value="1703894400" />
[HttpPost("contact")]
public IActionResult Contact([FromForm] ContactRequest request)
{
var submissionTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var loadTime = request.FormTime;
var elapsed = submissionTime - loadTime;
// Reject if submitted in less than 3 seconds
if (elapsed < 3)
{
logger.LogWarning("Form submitted too fast: {Seconds}s", elapsed);
return Ok();
}
// Honeypot check
if (!string.IsNullOrEmpty(request.Website))
{
return Ok();
}
// Process legitimate submission
// ...
}
The Laravel Honeypot package uses a 1-second default threshold. For complex forms, 5-10 seconds is reasonable.
When Honeypots Work
Honeypots are effective against:
| Bot Type | Effectiveness |
|---|---|
| Basic scrapers | High: Fill every field blindly |
| Form-filling scripts | High: Don't execute CSS |
| Spam services | Medium: Some have learned to skip hidden fields |
| Headless browsers | Low: Can execute CSS and detect hidden fields |
Studies report 80% reduction in basic spam with honeypots alone. Combined with time-based checks, some implementations block over 99% of automated submissions.
When Honeypots Fail
Honeypots won't catch:
Sophisticated bots that execute JavaScript and respect CSS. Headless browsers like Puppeteer can detect which fields are visible.
Human spam from click farms or paid operators. If a human fills out the form, the honeypot won't trigger.
Targeted attacks where the attacker inspects your form structure. Once they identify the honeypot, they skip it.
Password manager autofill that fills hidden fields. This is a documented issue, covered in our companion post on password manager ignore attributes.
Layered Protection
Honeypots work best as one layer in a defense stack:
| Layer | Catches |
|---|---|
| Honeypot | Basic bots that fill all fields |
| Time check | Bots that submit instantly |
| Rate limiting | High-volume automated attacks |
| Cloudflare Turnstile | Sophisticated bots, headless browsers |
For most contact forms and newsletter signups, honeypot + time check provides adequate protection without user friction. Add Turnstile or server-side validation (like Akismet) for high-value forms.
Framework Integrations
Most form libraries have built-in honeypot support:
| Framework | Package/Feature |
|---|---|
| Laravel | spatie/laravel-honeypot |
| WordPress | Contact Form 7 Honeypot plugin |
| React | Manual implementation or remix-utils for Remix |
| ASP.NET | Manual implementation (see examples above) |
Summary
Honeypots trade sophistication for simplicity. They won't stop every bot, but they'll stop most of them, and your users won't know they're there.
| Technique | What It Catches |
|---|---|
| Hidden field | Bots that fill all fields |
| Time threshold | Bots that submit instantly |
| Deceptive naming | Bots that skip obvious traps |
For forms where user experience matters more than bulletproof security, honeypots are the right tool. For authentication, payments, or high-value actions, combine them with stronger measures.
Related: Why Your Honeypot Catches Humans (Not Bots), on preventing password managers from filling honeypot fields.
Honeypots are one layer of defense. For comprehensive bot protection, see Cloudflare Turnstile or Cloudflare Bot Management.
Top comments (0)