This is the personal blog of Neil Ang. Simple and interesting technology articles written by a developer for developers. Feel free to comment on posts or link to this site. Constructive feedback is always welcomed.

Outsmarting comment spam

Posted: 13 January 2008

It is often hard to find the right balance between stopping comment spam, and encouraging users to leave comments. For example, although captcha's are effective, I don't like asking my users to enter a (sometimes cryptic) code to leave a comment.

I put a lot of effort into making sure comment spam doesn't make it on my web site. However, late 2007 I started receiving comment spam from a spam-bot who wasn't selling anything, or linking back to their site, it was just nonsense that didn't get caught by my anti-spam methods.

To counter-act this annoying comment spam, I wrote a very simple piece of JavaScript that inserted the comment form dynamically. This meant that unless the spam-bot could interpret JavaScript, it wouldn't detect the embedded form on the page and attempt to spam it.

Heres what the JS looks like:

function insertCommentForm(){
  var parent = document.getElementById('myCommentForm');

  var form = document.createElement('form');
  form.setAttribute('action', '');
  form.setAttribute('method', 'post');
  
  var fieldset = document.createElement('fieldset');
  
  // Input: Name
  var nameLabel = document.createElement('label');
  var nameText = document.createTextNode('Name ');
  var nameInput = document.createElement('input');
  nameInput.setAttribute('name', 'name');
  nameInput.setAttribute('value', document.getElementById('myComment-name').value);
  nameLabel.appendChild(nameText);
  nameLabel.appendChild(nameInput);
  
  //Input: Email
  var emailLabel = document.createElement('label');
  var emailText = document.createTextNode('Email ');
  var emailNote = document.createElement('small');
  emailNote.innerHTML = 'Required but never displayed';
  var emailInput = document.createElement('input');
  emailInput.setAttribute('name', 'email');
  emailInput.setAttribute('value', document.getElementById('myComment-email').value);
  emailLabel.appendChild(emailText);
  emailLabel.appendChild(emailNote);
  emailLabel.appendChild(emailInput);
        
        
  //Input: Website        
  var websiteLabel = document.createElement('label');
  var websiteText = document.createTextNode('Website ');
  var websiteNote = document.createElement('small');
  websiteNote.innerHTML = 'http://';
  var websiteInput = document.createElement('input');
  websiteInput.setAttribute('name', 'website');
  websiteInput.setAttribute('value', document.getElementById('myComment-url').value);
  websiteLabel.appendChild(websiteText);
  websiteLabel.appendChild(websiteNote);
  websiteLabel.appendChild(websiteInput);
  
  //Input: Comment
  var commentLabel = document.createElement('label');
  var commentText = document.createTextNode('Comment ');
  var commentTextarea = document.createElement('textarea');
  commentTextarea.setAttribute('name', 'comment');
  commentTextarea.setAttribute('rows', '12');
  commentTextarea.setAttribute('cols', '24');
  commentLabel.appendChild(commentText);
  commentLabel.appendChild(commentTextarea);
      
  //Hidden: Section        
  var sectionHiddenInput = document.createElement('input');
  sectionHiddenInput.setAttribute('type', 'hidden');
  sectionHiddenInput.setAttribute('name', 'section');
  sectionHiddenInput.setAttribute('value', 'entries');
  
  //Hidden: Remember
  var rememberHiddenInput = document.createElement('input');
  rememberHiddenInput.setAttribute('type', 'hidden');
  rememberHiddenInput.setAttribute('name', 'remember');
  rememberHiddenInput.setAttribute('value', 'on');
  
  //Hidden: Entry Handle
  var rememberHiddenInput = document.createElement('input');
  rememberHiddenInput.setAttribute('type', 'hidden');
  rememberHiddenInput.setAttribute('name', 'entry-handle');
  rememberHiddenInput.setAttribute('value', document.getElementById('myComment-entry').value);
  
  //Hidden: Submit
  var submitInput = document.createElement('input');
  submitInput.setAttribute('type', 'submit');
  submitInput.setAttribute('id', 'submit');
  submitInput.setAttribute('value', 'Post Comment');
  submitInput.setAttribute('name', 'action[comment]');
  
  fieldset.appendChild(nameLabel);
  fieldset.appendChild(emailLabel);
  fieldset.appendChild(websiteLabel);
  fieldset.appendChild(commentLabel);
  fieldset.appendChild(sectionHiddenInput);
  fieldset.appendChild(rememberHiddenInput);
  fieldset.appendChild(submitInput);
  
  form.appendChild(fieldset);
  
  document.getElementById('myCommentWarning').style.display='none';
  
  parent.appendChild(form);
}

Since using this JS I haven't received any comment spam. And until spam-bots evolve to read JavaScript, this is a simple and effective technique to reduce time spent dealing with spam.

Also, if you use Symphony, this JS will work with your comment forms too. Contact me if you would like the updates to the XSL you will need to make this work.

Your comments (subscribe)

Gravatar

Dean Robinson 13 Jan 08 at 7:54pm

Its probably worth trying out on my blog since my spam count is rapidly approaching 20,000 and averaging about 100 new spam every day.

…now I just need to write a spam bot that can read Javascript…

Gravatar

Adrian 14 Jan 08 at 8:34am

I guess this is an indication of how little traffic my blog gets but my spam count rarely gets above 20 before it gets deleted.

Cool script though. I dare say this is gonna be popular.

Gravatar

Tony 16 Jan 08 at 11:43pm

This is a great idea – I don't have any spam control at all at the moment (which, like Adrian, probably means my site isn't getting that many hits).

*sigh* My decommissioned http://VirtueDesktops.info/ site gets more hits than my blog.

Gravatar

read 29 Jan 08 at 10:21am

I will try the script 'cause I'm sick of deleting it. Thanks

Gravatar

Neil 29 Jan 08 at 10:28am

Building the whole form in JS has it's drawbacks (e.g. maintenance), and advantages (e.g. the user must have JS to post). Another method, which I might post about later, could be to create a HTML form with a phoney action attribute, then use JS to switch the 'action' attribute onload.

Post a comment

Comment Guidelines

  • You can subscribe to the comments on this entry via RSS.
  • Have no more than 2 links, otherwise your comment will be flagged as spam.
  • Links are automagically generated.
  • <em>text</em> to make text italic.
  • <strong>text</strong> to make text bold.

JavaScript needs to be enabled to comment.