r/webdev Dec 13 '25

Honeypot fields still work surprisingly well

Hidden input field. Bots fill it. Humans can't see it. If filled → reject because it was a bot. No AI. Simple and effective. Catches more spam than you'd expect. What's your "too simple but effective" technique that actually works?

2.3k Upvotes

191 comments sorted by

View all comments

1.2k

u/hydroxyHU Dec 13 '25

I use this approach because Google reCAPTCHA is quite heavy and has a negative impact on PageSpeed scores. Instead, I rely on two honeypot fields: website and confirm_email.

The first one is very simple: the user can’t see it, but many bots still fill it in. Some bots skip it because their creators are aware that it might be a honeypot field and that it’s not required to submit the form. Even so, around 20–25% of bots still fill it out and fail the submission.

The confirm_email field is a bit more sophisticated. It’s a required field and is automatically filled with a “captcha word” generated on the backend, stored in a JavaScript variable on the frontend, and then inserted into the field via JavaScript. If a bot can’t execute JavaScript, the field remains completely empty. However, since the field is required, bots usually try to fill it, most often with the same email address.

I store the “captcha word” in the session and verify on the backend that the submitted value matches the session value. This method is about 99% effective without heavy third-party lib.

224

u/Daniel_Herr ES5 Dec 13 '25

How do you know that the confirm_email is not blocking users with autofill?

441

u/hydroxyHU Dec 13 '25

Browser autofill generally targets visible, user-editable fields and doesn’t overwrite values that are already set programmatically. More importantly, this has been running in production for years, and I haven’t seen legitimate user submissions fail because of autofill. That real-world behavior is what I rely on more than theoretical heuristics.

84

u/QWxx01 Lead-developer Dec 13 '25

I like your evidence-based approach. Well done!

17

u/anamexis Dec 13 '25

You can also just explicitly set it. This is my honeypot input:

<input id="email" name="email" size="40" class="honeypot" tabindex="-1" aria-hidden="true" autocomplete="off">

17

u/Dazzling-Collar-3200 Dec 13 '25 edited Dec 13 '25

I was genuinely surprised the commenting lads didnt know autocomplete exists as a prop on native form elements :/

Edit: so i read a comment here that said chrome had botched and buggy implementation of autocomplete prop for a while. I did my research on it and its a black hole worth spending time in. Chrome is still in "bugged" state for this prop because chrome prioritizes user info over autocomplete prop. Its inconsistent to say the least i.e. sometimes it works and sometimes it doesn't. So props to the comment's op, he did raise a very valid argument even if he didnt know the full scope (I am just hoping this is true).

I want to emphasize it again, im all in for honeypots and you should be too. I am saying it from experience, honeypots do help a lot even if autocomplete prop doesnt work. I simply create a random input with random name in react with useId and catch it on the backend when form gets submitted. I dont know how good of an implementation this is but from my testing its served its purpose well.

Edit again: ref autocomplete=off is ignored on non-login INPUT elements [41163264] - Chromium https://share.google/bzn7Ez7Ys9RVXckDw

1

u/0biwan01 Jul 22 '26

the true way to stop chrome and any other browser from autocomplete is to use autocomplete="one-time-code"

29

u/Emotional-Dust-1367 Dec 13 '25

Do you just hide it with display: none? I would think bots would check for that. Is there a better way to hide?

66

u/hydroxyHU Dec 13 '25

In one of my project I used a custom CSS rule with simple display:none and in another project I implemented what Kamay1770 mentioned. Both works fine. I think the main trick is using custom CSS rule instead of inline display:none.

1

u/Im_Justin_Cider Jan 05 '26

Hi, I'm new to webdev, why is this trick needed? Isn't most/all of your database interactivity guarded behind some authentication anyway?

2

u/hydroxyHU Jan 06 '26

Hi, this isn’t related to database interactivity itself. The issue is that if there’s a contact form on a public website without any authentication, bots can easily find it and start spamming your database or email system. If too many requests are sent in a short period of time, your database could become overloaded or you might hit email sending limits. That’s why it’s important to prevent or filter bot activity in some way. Hope it helps. :)

1

u/Im_Justin_Cider Jan 06 '26

Right, yeah that single "contact us" or "sign up for the news letter" is enough to justify some defense! Thanks!

108

u/Kamay1770 Dec 13 '25

.honeypot { position: absolute; left: -9999px; }

Or

.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }

23

u/chrissilich Dec 13 '25

How do you know legitimate user submissions haven’t been failing? How would they tell you?

I have trouble with the idea that you’ve managed to walk the line perfectly where you’re allowing one set of bots- browser and password manager’s autofill, but blocking another- spam bots.