/reCAPTCHA, nodejs, expressjs, Google

Add reCAPTCHA to NodeJS and ExpressJS app with AJAX form

Google's reCAPTCHA is great for getting rid of those pesky bots spamming your contact forms. Implementing reCAPTCHA on your site is very easy, albeit somewhat confusing if you try to follow official documentation.
Below example assumes you're using NodeJS with ExpressJS for back-end and Pug (formerly Jade) templating engine on the front-end. General principle is the same regardless of languages used.
I'll assume you've already set up your reCAPTCHA API keys. If you haven't just go to https://www.google.com/recaptcha/ and follow onscreen instructions.

Template files

Open up your template file where you want to use reCAPTCHA, in my case index.pug. Add reference to reCAPTCHA JavaScript file as mentioned in official documentation.

script(src='https://www.google.com/recaptcha/api.js')

Then copy the submit button code from official docs and paste it in your template, or in case of Pug, make it similar to below.

button.btn.btn-default.g-recaptcha(data-sitekey="your_site_key", data-callback="contactSubmit") Submit

Remember to change your_site_key to your actual Site Key. If you're copying and pasting code from reCAPTCHA website, it should have your key already filled in.

JavaScript to submit the form

Notice data-callback="contactSubmit" in the above code for the button. Copying code for the button directly from documentation may have a different callback function name. I called mine contactSubmit.
All you need to do is create a function in your JS file to handle form submission, making sure you pass the token value to it as an agrument and then pass it down the line to the server. Below is a pretty standard AJAX form submission example. I kept it to minimum to illustrate just the reCAPTCHA variable.

function contactSubmit(token) {
	var name = $('#contactForm #name'),
		email = $('#contactForm #email'),
		message = $('#contactForm #message');
	
	// check if the form fields are not empty
	if (name.val() !== '' && email.val() !== '' && message.val() !== '') {
		$.ajax({
			type: 'POST',
			url: '/handlecontact',
			data: {
				name: name.val(),
				email: email.val(),
				message: message.val(),
				recaptcha: token
			},
			dataType: 'json',
			error: function (data) {
				$('#contactForm #formFeedback')
                    .removeClass()
                    .addClass('alert alert-danger')
                    .html('Something went wrong, please try again')
                    .fadeIn('slow')
                    .delay(10000)
                    .fadeOut('slow');
				return false;
			},
			success : function (data, res) {
				if (data.success === true) {
					$('#contactForm #formFeedback')
                        .removeClass()
                        .addClass('alert alert-success')
                        .html(data.msg)
                        .fadeIn('slow')
                        .delay(5000)
                        .fadeOut('slow');
					// clean up form fields
					name.val('');
					email.val('');
					message.val('');
					return true;
				} else {
					$('#contactForm #formFeedback')
                        .removeClass()
                        .addClass('alert alert-danger')
                        .html(data.msg)
                        .fadeIn('slow')
                        .delay(10000)
                        .fadeOut('slow');
					return false;
				}
			}
		});
	} else {
		$('#contactForm #formFeedback')
            .removeClass()
            .addClass('alert alert-warning')
            .html('Please fill in all fields')
            .fadeIn('slow')
            .delay(10000)
            .fadeOut('slow');
		return false;
	}
}

ExpressJS - server side

Open ExpressJS file in which you handle your form data on the server side. In my case it's index.js, and add https module at the top to handle captcha verification request.

var https = require('https');

Then in the method handling your form data verify if user has passed captcha verification.
All you really need to do is send the reCAPTCHA token back to Google for verification. That's what we need https module for.

app.post('/handlecontact', function (req, res) {
	// verify recaptcha
	if (req.body.recaptcha === undefined || req.body.recaptcha === '' || req.body.recaptcha === null) {
		res.send({success: false, msg: 'Please select captcha first'});
		return;
	}
	const secretKey = 'your_secret_key';
	const verificationURL = `https://www.google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${req.body.recaptcha}&remoteip=${req.connection.remoteAddress}`;
	
	https.get(verificationURL, (resG) => {
		let rawData = '';
		resG.on('data', (chunk) => { rawData += chunk })
		resG.on('end', function() {
			try {
				var parsedData = JSON.parse(rawData);
				if (parsedData.success === true) {
					// All good, send contact email or perform other actions that required successful validation
					res.send({success: true, msg: 'Your message has been sent. Thank you.'});
					return;
				} else {
					res.send({success: false, msg: 'Failed captcha verification'});
					return;
				}
			} catch (e) {
				res.send({success: false, msg: 'Failed captcha verification from Google'});
				return;
			}
		});
	});
});

When testing reCAPTCHA make sure you refresh the page between "submit" button clicks. Otherwise Google may think you're a bot for clicking too many times and not submit the form at all.