<div><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>

 
 
</p><p>Honeypots are fields that developers use to prevent spam submissions.</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p><strong>They still work in 2025.</strong></p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>So you don’t need <a href=”https://cloud.google.com/security/products/recaptcha” rel=”noopener”>reCAPTCHA</a> or other annoying mechanisms.</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>But you got to set a couple of tricks in place so spambots can’t detect your honeypot field.</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><span id=”more-388560″/><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>


</p><h3 class=”wp-block-heading” id=”use-this”><a href=”#aa-use-this” aria-hidden=”true” class=”aal_anchor” id=”aa-use-this”><svg aria-hidden=”true” class=”aal_svg” height=”16″ version=”1.1″ viewbox=”0 0 16 16″ width=”16″><path fill-rule=”evenodd” d=”M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z”/></svg></a>Use This</h3><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>


</p><p>I’ve created a <a href=”https://splendidlabz.com/docs/svelte/forms/honeypot/” rel=”noopener”><code>Honeypot</code> component</a> that does everything I mention below. So you can simply import and use them like this:</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><pre rel=”Svelte” class=”wp-block-csstricks-code-block language-markup” data-line=””><code markup=”tt”>

<honeypot name=”honeypot-name”/></code></pre><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>Or, if you use Astro, you can do this:</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><pre rel=”Astro” class=”wp-block-csstricks-code-block language-javascript” data-line=””><code markup=”tt”>—
import { Honeypot } from ‘@splendidlabz/svelte’
—

<honeypot name=”honeypot-name”/></code></pre><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>But since you’re reading this, I’m sure you kinda want to know what’s the necessary steps.</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>


</p><h3 class=”wp-block-heading” id=”preventing-bots-from-detecting-honeypots”><a href=”#aa-preventing-bots-from-detecting-honeypots” aria-hidden=”true” class=”aal_anchor” id=”aa-preventing-bots-from-detecting-honeypots”><svg aria-hidden=”true” class=”aal_svg” height=”16″ version=”1.1″ viewbox=”0 0 16 16″ width=”16″><path fill-rule=”evenodd” d=”M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z”/></svg></a>Preventing Bots From Detecting Honeypots</h3><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>


</p><p>Here are two things that you must <em>not</em> do:</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><ol class=”wp-block-list”>
<li>Do not use <code><input type=”hidden”/></code>.</li>



<li>Do not hide the honeypot with inline CSS.</li>
</ol><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>Bots today are already smart enough to know that these are traps — and they will skip them.</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>Here’s what you need to do instead:</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><ol class=”wp-block-list”>
<li>Use a <code>text</code> field.</li>



<li>Hide the field with CSS that is <em>not</em> inline.</li>
</ol><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>A simple example that would work is this:</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><pre rel=”HTML” class=”wp-block-csstricks-code-block language-markup” data-line=””><code markup=”tt”><input class=”honeypot” type=”text” name=”honeypot”/>

</code></pre><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>For now, placing the <code/> tag near the honeypot seems to work. But you might not want to do that in the future (more below).</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>


</p><h3 class=”wp-block-heading” id=”unnecessary-enhancements”><a href=”#aa-unnecessary-enhancements” aria-hidden=”true” class=”aal_anchor” id=”aa-unnecessary-enhancements”><svg aria-hidden=”true” class=”aal_svg” height=”16″ version=”1.1″ viewbox=”0 0 16 16″ width=”16″><path fill-rule=”evenodd” d=”M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z”/></svg></a>Unnecessary Enhancements</h3><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>


</p><p>You may have seen these other enhancements being used in various honeypot articles out there:</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><ul class=”wp-block-list”>
<li><code>aria-hidden</code> to prevent screen readers from using the field</li>



<li><code>autocomplete=off</code> and <code>tabindex=”-1″</code> to prevent the field from being selected</li>
</ul><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><pre rel=”HTML” class=”wp-block-csstricks-code-block language-markup” data-line=””><code markup=”tt”><input ...=”” aria-hidden=”” autocomplete=”off” tabindex=”-1″/></code></pre><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>These aren’t necessary <a href=”https://css-tricks.com/hiding-content-responsibly/”>because <code>display: none</code> itself already does the things these properties are supposed to do</a>.</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>


</p><h3 class=”wp-block-heading” id=”future-proof-enhancements”><a href=”#aa-future-proof-enhancements” aria-hidden=”true” class=”aal_anchor” id=”aa-future-proof-enhancements”><svg aria-hidden=”true” class=”aal_svg” height=”16″ version=”1.1″ viewbox=”0 0 16 16″ width=”16″><path fill-rule=”evenodd” d=”M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z”/></svg></a>Future-Proof Enhancements</h3><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>


</p><p>Bots get smarter everyday, so I won’t discount the possibility that they can catch what we’ve created above. So, here are a few things we can do today to future-proof a honeypot:</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><ol class=”wp-block-list”>
<li>Use a legit-sounding <code>name</code> attribute values like <code>website</code> or <code>mobile</code> instead of obvious honeypot names like <code>spam</code> or <code>honeypot</code>.</li>



<li>Use legit-sounding CSS class names like <code>.form-helper</code> instead of obvious ones like <code>.honeypot</code>.</li>



<li>Put the CSS in another file so they’re further away and harder to link between the CSS and honeypot field.</li>
</ol><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>The basic idea is to trick spam bot to enter into this “legit” field.</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><pre rel=”HTML” class=”wp-block-csstricks-code-block language-markup” data-line=””><code markup=”tt”><input class=”form-helper” ...=”” name=”occupation”/>

<!– Put this into your CSS file, not directly in the HTML –>
</code></pre><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>There’s a very high chance that bots won’t be able to differentiate the honeypot field from other legit fields. </p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>


</p><h3 class=”wp-block-heading” id=”even-more-enhancements”><a href=”#aa-even-more-enhancements” aria-hidden=”true” class=”aal_anchor” id=”aa-even-more-enhancements”><svg aria-hidden=”true” class=”aal_svg” height=”16″ version=”1.1″ viewbox=”0 0 16 16″ width=”16″><path fill-rule=”evenodd” d=”M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z”/></svg></a>Even More Enhancements</h3><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>


</p><p>The following enhancements need to happen on the <code><form/></code> instead of a honeypot field.</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>The basic idea is to detect if the entry is potentially made by a human. There are many ways of doing that — and all of them require JavaScript:</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><ol class=”wp-block-list”>
<li>Detect a <code>mousemove</code> event somewhere.</li>



<li>Detect a keyboard event somewhere.</li>



<li>Ensure the the form doesn’t get filled up super duper quickly (‘cuz people don’t work that fast).</li>
</ol><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>Now, the simplest way of using these (I always advocate for the simplest way I know), is to use <a href=”https://splendidlabz.com/docs/svelte/forms/form/” rel=”noopener”>the <code>Form</code> component</a> I’ve created in <a href=”https://splendidlabz.com” rel=”noopener”>Splendid Labz</a>:</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><pre rel=”Svelte” class=”wp-block-csstricks-code-block language-markup” data-line=””><code markup=”tt”>

<form>
 <honeypot name=”honeypot”/>
</form></code></pre><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>If you use Astro, you need to enable JavaScript with a client directive:</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><pre rel=”Astro” class=”wp-block-csstricks-code-block language-javascript” data-line=””><code markup=”tt”>—
import { Form, Honeypot } from ‘@splendidlabz/svelte’
—

<form client:idle=””>
 <honeypot name=”honeypot”/>
</form></code></pre><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>If you use vanilla JavaScript or other frameworks, you can use the <code>preventSpam</code> utility that does the triple checks for you:</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><pre rel=”JavaScript” class=”wp-block-csstricks-code-block language-javascript” data-line=””><code markup=”tt”>import { preventSpam } from ‘@splendidlabz/utils/dom’

let form = document.querySelector(’form’)
form = preventSpam(form, { honeypotField: ‘honeypot’ })

form.addEventListener(’submit’, event =>; {
 event.preventDefault()
 if (form.containsSpam) return
 else form.submit()
})</code></pre><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>And, if you don’t wanna use any of the above, the idea is to use JavaScript to detect if the user performed any sort of interaction on the page:</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><pre rel=”JavaScript” class=”wp-block-csstricks-code-block language-javascript” data-line=””><code markup=”tt”>export function preventSpam(
 form,
 { honeypotField = ‘honeypot’, honeypotDuration = 2000 } = {}
) {
 const startTime = Date.now()
 let hasInteraction = false

 // Check for user interaction
 function checkForInteraction() {
 hasInteraction = true
 }

 // Listen for a couple of events to check interaction
 const events = [’keydown’, ‘mousemove’, ‘touchstart’, ‘click’]
 events.forEach(event =>; {
 form.addEventListener(event, checkForInteraction, { once: true })
 })

 // Check for spam via all the available methods
 form.containsSpam = function () {
 const fillTime = Date.now() – startTime
 const isTooFast = fillTime <; honeypotDuration
 const honeypotInput = form.querySelector(`[name=”${honeypotField}”]`)
 const hasHoneypotValue = honeypotInput?.value?.trim()
 const noInteraction = !hasInteraction

 // Clean up event listeners after use
 events.forEach(event =>;
 form.removeEventListener(event, checkForInteraction)
 )

 return isTooFast || !!hasHoneypotValue || noInteraction
 }
}</code></pre><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>


</p><h3 class=”wp-block-heading” id=”better-forms”><a href=”#aa-better-forms” aria-hidden=”true” class=”aal_anchor” id=”aa-better-forms”><svg aria-hidden=”true” class=”aal_svg” height=”16″ version=”1.1″ viewbox=”0 0 16 16″ width=”16″><path fill-rule=”evenodd” d=”M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z”/></svg></a>Better Forms</h3><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>


</p><p>I’m putting together a solution that will make HTML form elements much easier to use. It includes the standard elements you know, but with easy-to-use syntax and are highly accessible.</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>Stuff like:</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><ul class=”wp-block-list”>
<li>Form</li>



<li>Honeypot</li>



<li>Text input</li>



<li>Textarea</li>



<li>Radios</li>



<li>Checkboxes</li>



<li>Switches</li>



<li>Button groups</li>



<li>etc.</li>
</ul><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p><a href=”https://splendidlabz.com/solutions/forms/” rel=”noopener”>Here’s a landing page</a> if you’re interested in this. I’d be happy to share something with you as soon as I can.</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>


</p><h3 class=”wp-block-heading” id=”wrapping-up”><a href=”#aa-wrapping-up” aria-hidden=”true” class=”aal_anchor” id=”aa-wrapping-up”><svg aria-hidden=”true” class=”aal_svg” height=”16″ version=”1.1″ viewbox=”0 0 16 16″ width=”16″><path fill-rule=”evenodd” d=”M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z”/></svg></a>Wrapping Up</h3><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>


</p><p>There are a couple of tricks that make honeypots work today. The best way, likely, is to trick spam bots into thinking your honeypot is a real field. If you don’t want to trick bots, you can use other bot-detection mechanisms that we’ve defined above.</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p>Hope you have learned a lot and manage to get something useful from this!</p><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>



</p><p/><p style=”display: inline;” class=”WPAuto_Base_Readability-styled”>

 
 </p></div>
Categories
Programming & Tech
Building a Honeypot Field That Works | CSS-Tricks
