Invisible Human Check for Web Form Validation

What’s the ideal check to protect your web forms from spambots?

No one really likes having to copy squiggly letters from a CAPTCHA image, but is there a better alternative?

The ideal check would be one that most people don’t ever notice, but which effectively keeps out all spambots.

In this tutorial, I describe a technique that uses Javascript to recognise human activity based on screen events, which works very well for us.

In a discussion on Scratch Forums on the merits of CAPTCHA, one of our members suggested a possible alternative that detected JavaScript events (mouse events, keystrokes) to show that it’s a human completing the form.

I took on the challenge of creating a simple JS-based alternative to CAPTCHA, which I’ll explain below.

High-level Requirements

  1. The form should record certain events to prove human involvement.
  2. If JavaScript is not enabled, there needs to be a fallback solution.
  3. The tests should be invisible to the user where possible.
  4. It should not be possible for a bot to discover the test and to spoof the results.

Am I Human?

First of all, our form will need some way of sending the answer to “am I human” through to the back-end script.

For this, I’ll just use a hidden field. Note, following requirement 4 above, this field could be named anything. If bots learn the likely name for this field, they could send the correct value through and bypass the system.

I’ll put the hidden field before the closing form tag (but you could put it anywhere in the form).

<input type=”hidden” name=”imahuman” id=”imahuman” value=”0″ />

The value of this field is zero by default, which means “no – not a human”.

Switch it For Humans

We want to set the value of “imahuman” (or your own name, please) when certain events take place, which we’ll detect using Javascript.

Following best practice, the function that sets up the event detection should be called by an event handler, and that event handler should be attached using an external Javascript file, not written into your HTML code. Like this…

// Set up
addEvent(window, “load”, setUpHumanTest, false);
function setUpHumanTest() {
var myforms = document.getElementsByTagName(“form”) ;
for (var i=0; i<myforms.length; i++) {
addEvent(myforms[i], “focus”, markAsHuman, false);
addEvent(myforms[i], “click”, markAsHuman, false);

// Identify a human
function markAsHuman() {
document.getElementById(“imahuman”).value = “1″;

// Generic cross-browser code for attaching events to elements
// You should really have this in a separate common JS file
var addEvent;
if (document.addEventListener) {
addEvent = function(element, type, handler) {
element.addEventListener(type, handler, null);
if (element.href) element.href=”javascript:void(”);” ;
else if (document.attachEvent) {
addEvent = function(element, type, handler) {
element.attachEvent(“on” + type, handler);
if (element.href) element.href=”javascript:void(”);” ;
else {
addEvent = new Function; // not supported

What’s happening here (working from bottom upwards):

  • The addEvent stuff at the bottom means you can simply call a single addEvent(what element, what event, function you want to run, escalation) command in almost any browser.
  • The function markAsHuman will be called when we think we have a human. It simply changes the value of the hidden field from zero to 1.
    • Note, it might be sensible to change these values to something less obvious.
  • function setUpHumanTest() actually runs through every form on the page (why not?) and attaches 2 javascript event handlers to the form:
    • If the form receives the focus, we fire the markAsHuman() function;
    • Same if the form receives a click.
    • Both these events only happen in the browser window, so a code/spambot wouldn’t be able to reproduce them.
  • Finally, at the very top, the addEvent() call tells the browser to run the setUpHumanTest() function when the page has loaded.

Testing Results with Script

Your form will submit to a middleware script (PHP, ASP etc.) You’ll simply need to tell this script to reject any submissions that still have “imahuman” (or equivalent) set to zero (or whatever you use).

Personally, I like to pretend that the script has worked, and forward the bot to the success page, but not do whatever is supposed to happen with a valid input. I figure that there’s no reason to tell a bot that you’ve twigged its game and draw attention to your site.

What About When JavaScript is Off?

Clearly, we need to handle the (approximately 10%) minority that don’t use JS. This now includes some mobile browsers and text-to-speech readers, not just people exercising their choice for a diminshed browsing experience.

It’s very easy to show extra special HTML when JS is not working: you just use the <noscript></noscript> tag.

Here’s what I do:

<dt>What is three plus four?</dt>
<dd><input type=”text” maxlength=”1″ name=”althuman” /></dd>

This is really simple, but you could replace it with a CAPTCHA test if you prefer.

(Note, we usually use definition lists for form layout these days. Not the strictest semantic application of the tag type, but I think it’s OK, in the broader application of name/value pairs.)

The field only allows a one-character response, so you have to type “7″. This is also easy to change.

The back-end script would then need to test first whether “imahuman” is set “on”, OR if the alternative human check is correct. If either is OK, we’re OK.

I hope you find this technique easy to implement and useful on your own sites.

this post from


About The Author