How I Reduce Contact Form Spam for My Clients

Use Case: Solving Spam - Enough Said!

Spam is a problem. It's annoying, it kills productivity, it clogs up our inboxes, and it's even potentially dangerous to both our personal lives and systems.

But it's also a challenge because it's not easy to get rid of. Sure, we can set up CAPTCHAs to attempt to block bots and web crawlers but that really doesn't work ...

Also, it's not just bots that submit forms these days - there are a lot of real people hired by companies that fill out and submit website forms all day.

Unfortunately, there isn't one global fix for this. However, here are the 6 things that I've done to all but remove the spamming problem entirely.

Hidden URL Field

To stop any bots that may crawl your page and submit your form, create a phony input field that, when filled out, will be an obvious spam attempt.

Do this by creating a text field and calling it "url" (because spammers love to give you a URL). We can hide this field (display:none;) when rendered in the browser because we're just targeting bots here and we don't want to confuse our users. What we should do, however, is create a paragraph element next to our input field that says simply "Leave empty" in case, for some reason, the user does end up seeing the input.

Then, on the server side, check if this field contains a value. If it does, then we know that it was generated a value by a web crawler and we can ignore the submission.

<div class='antispam'>
	<p>Leave empty:</p>
	<input type='text' name='url'>
</div>

Messages Containing HTML

To control the formatting of their submitted messages, many spammers will submit form inquiries as HTML, including tags such as <p>,<a href='#'> and <strong>.

We can safely assume that a legitimate user of ours wouldn't do that, so we'll ignore submissions that include HTML. We can determine this by using a regular expression in JavaScript. If the message does not contain HTML, then submit:

if (!/<[a-z][\s\S]*>/i.test(message)) {
	// Submit
}

Messages Containing Vulgar or Promotional Language

Some spammers won't be very discrete and will instead just submit a form inquiry with explicit language. Some of these words and phrases (I'll spare you an example) are clearly not appropriate regardless of your business or industry. However, for some it may be difficult to know for sure and you wouldn't want to filter out legitimate submissions.

So we'll confidently ignore any submissions containing obvious vulgar language and take other promotional language on a case-by-case basis.

We can do this by creating a function in JavaScript that iterates through each word/phrase in an array and returning false if the message isn't "clean" and returning true if it is.

function cleanInquiryString(string) {
	const ignoreWords = ['dropship','promote your website', 'build links', ...]
	for (let word of ignoreWords) {
		if (string.includes(word)) { 
			return false
		}
	}
	return true
}

Messages Not in English

I had a client once that received contact form spam in Chinese and Russian. It was clearly not relevant for this particular business so I added a filter to ignore contact form submissions that were not primarily in the English language.

Node.js has a great module called Node Language Detect that, when passed a string, returns an array of the languages discovered in the string ordered by relevance. If the top language isn't English, I'll ignore the submission. You can do this the opposite way by just ignoring certain languages.

var language = lngDetector.detect(message)[0][0]

if (language == 'english') {
// Submit
}

Track IP Address

If the form submission passes the previous filters, then I'll insert it into the database and email the administrator/client. However, understanding that spam could still make its way through, I'll record the IP address of the sender. By recording this, I can then block the IP address. That wouldn't be enough to stop the initial submission, but it would allow me to block any and all future submissions - at least those belonging to the same IP address.

We'll create a hidden input field in our form and then leverage the API at jsonip.com to get the client's IP address and populate the hidden input. Then we'll submit this with our form and save it to the database.

async function getIp(url){
	try {
		const response = await fetch(url)
		const json = await response.json()
		inputIp[0].value = json.ip
	} catch (error) {
		return null
	}
}

var inputIp = document.getElementsByClassName('input-ip')
if (inputIp.length) {
	getIp("https://jsonip.com")
}

Confirmation Screen Regardless

The final step to my submission cleansing is the return screen. Regardless of whether or not the spam makes it through the filters, it's important that the person submitting the spam thinks it did.

I'll send a confirmation screen with a "Thanks, Tyler. Your message has been received." or something like that so that the spammer will feel like his or her job is complete and move on. See, I can play games too!

So that's my form filtering program. It's not completely objective - there are parts that need to be modified depending on the client/situation, but we've been happy with the results till now.

Let me know what you've tried that works!

Tweet me @tylerewillis

Or send me an email: