How to Use reCAPTCHA v3 With Gatsbyjs and Express

Al Javier
7 min readMay 13, 2020

Here’s a no-nonsense guide of how to do what the title says. I’ve tried to search all of the internet and even the official documentation of Gatsby but to no avail. That’s my motivation here, to let everyone know how to do this and stop that frustrating endless Google search loop.

Requirements

  • Some Node.js because we need to write some Express code
  • A React plugin that allows us to easily incorporate reCAPTCHA v3
  • Google account for reCAPTCHA keys

App Structure

Just a pretty basic app using npx gatsby new your-website . I've omitted a few files that aren't really needed for this example. Create app.json and static.json after starting your project, or just insert them into your existing project. They will be important for later.

your-website
|-- src
| |-- components
| | |-- header.jsx
| | |-- image.jsx
| | |-- layout.css
| | |-- layout.jsx
| | `-- seo.jsx
| |-- pages
| | |-- index.jsx
| | `-- 404.jsx
| `-- server
| `-- app.js
|-- gatsby-browser.js
|-- gatsby-config.js
|-- app.json
`-- static.json
This is what we want

Client-side Integration

In this example, we will use a contact form. You can definitely do this with whatever you want but most will follow this pattern of approach.

First, what you want to do is install that plugin aforementioned.

$ npm install react-google-recaptcha-v3

I’ve tried to do this without the plugin and it’s near impossible. There might be a way to do it but I personally haven’t come to a working solution just yet. If you manage to find a method without a plugin, feel free to share it in the comments. 😃

Open up that gatsby-browser.js file and delete the comments inside. Write this code:

What we’re doing here is wrapping all of your Gatsby app with the reCAPTCHA provider. This is the same approach you would do when you bootstrapped your app with Create React App. Your site key should be inside your Admin Console in Google’s reCAPTCHA site. Don’t forget to whitelist your domain, and localhost for that matter!

Alright so let’s make that Form component. It doesn’t have to be pretty, it can be as ugly as we want for this example. (Or I dunno, use Material UI to make it look good on the get-go)

Create a new file in components called Form.jsx or whatever you want to call it. Then let's take this one step at a time.

So the first thing to get out of the way is to create and export a Functional Component.

Then we create the input hook for our forms:

Or take a less complicated approach and just use useState(''), feel free to use whatever approach you feel more comfortable with.

Inside our functional component we initialize the values of the input hook:

And maybe create a notifications text so we have some feedback:

Let’s create that submit handler:

For now, this does absolutely nothing of value. But let’s test it out. Put it on the homepage:

Testing

If you fire up the website right now with gatsby develop, you'll actually see the reCAPTCHA v3 logo on the bottom right corner. Most tutorials would probably end here and tidy their hands, then tell you to do the rest. It's very important to note that reCAPTCHA requires server-side validation. Finding tutorials for that aspect can be next to impossible, especially for a very specific implementation like Gatsby.

Window squeezed for example purposes

Submitting the form only displays whatever’s on the notification state. This is fine for now. Let's move on to the real meat of this implementation.

reCAPTCHA In The Form Component

Alright, let’s finish the client-side stuff by actually putting in the reCAPTCHA into our Form component, specifically the submit handler.

Import the package first:

Then inside our functional component, we initialize the token state and executeRecaptcha():

Let’s finish building handleSubmit:

That’s about it for client-side. This part should be done now. Let’s move on to the other half of this implementation. Fun fact: the promise chain above is exactly the same on my regular HTML implementation.

The Server

Recall that our file structure actually has a server directory with app.js inside. If you don't have that yet, create it now in the src directory.

Install the requirements:

$ npm install express body-parser request

If you’ve never done this before, this might be a lot to take in. But if you’re a seasoned Node.js veteran, or have done some Udemy courses before, this shouldn’t be too hard.

The App

The objective of the app.js file is primarily to serve web pages from your compiled/built Gatsby site. But it does other things like:

  1. Handle REST API calls
  2. Validate the reCAPTCHA score
  3. Send emails

That’s right, you need to run gatsby build first before doing anything with the server app. So go ahead and do that. On a real project, you may want to finalize designs first so it won't be a pain to test later on.

To begin, we first import all the packages in app.js:

Then perform some configurations for our server, like setting the port and assigning the directory of the compiled Gatsby site:

One very important thing is the private key for your reCAPTCHA. Again, go to your admin console and look for that, then preferably store it inside an environment variable.

const secretKey = process.env.RECAPTCHA_SECRET_KEY

Most good developer-friendly hosting solutions will allow you to set environment variables. On localhost though you can just use .env or set the environment variable every time you start the server, like so:

$ RECAPTCHA_SECRET_KEY=your_actual_key npm run server

We then render some routes (REMEMBER TO PUT THE 404 PAGE AT THE VERY LAST OF THE ROUTE LIST):

And finally the listening server:

Your app.js should be able to run now and render your webpages. Run node src/server/app.js to check. Alternatively, customize your package.json scripts to make development a little easier. Maybe even consider nodemon.

Submit Route

Without a submit route, the forms are still useless, and so is the reCAPTCHA. Let’s build that route now.

This is where body-parser comes into play, we first take the submitted form inputs:

If you’ve noticed, they’re the exact same variable names from the Form component, destructured from the req.body object.

Inside of app.post, we need the verification URL. This is where your need the secret key and that token generated from the client.

Then we check if there was a token submitted at all, to make sure reCAPTCHA wasn’t bypassed:

Now comes the HTTP request to that verification URL above and whatever action you want the form to do. This is where we’ll also validate the score (aka humanity) of the user. Alright, still inside the app.post /submit route, we will now create our HTTP POST request.

The success and score are destructured from the request body. More information regarding these two can be found in the documentation. But in brief, success is a boolean that determines if the user passes the reCAPTCHA test or not. The score on the other hand returns a number between 0.0 to 1.0. Both can be used to validate the request made by the user.

The console.log() there represents any action you want to take when the user succeeds the captcha test. To reiterate, this can be any number of things like subscribing, user registration, login, or in this case, sending an email using the contact form.

Finally, the return statement is just the server sending the msg to the data object to the client. Which in turn will be the notification state.

That’s it, you now have a fully functioning form on Gatsby with reCAPTCHA v3.

What About Those Additional json files?

They will be used for deployment later on. Just copy and paste these into each respective file.

app.json

{
"buildpacks": [
{
"url": "heroku/nodejs"
}
]
}

static.json

{
"root": "public/"
}

Deployment

Time to answer the real question here. Where can you actually use this stack? Many places as it turns out. But I’m most familiar with Heroku. Luckily, I’ll also have an article for that! Deploying Gatsby with Express isn’t that hard as it turns out.

Conclusion

Anyway, thanks for reading this far. I hope this tutorial of sorts was able to help you. If it did, then great! Gimme a clap if you want. If not, kindly tell me in the comments on where you got stuck or where you think I can improve. I’m always happy to learn something new! 😁

For those who want it, the repository is available over here.

Support Me

If you liked this tutorial, you can support me by, well, buying me coffee! By supporting me, I get to post more tutorials, and maybe even post side-content for fun in the near future. For now, my only promise is that I will improve my content.

If you want to collaborate with me or hire a front-end developer, you can do that over at my website.

--

--

Al Javier

Alphonso ‘Al’ Javier is a web developer and rookie entrepreneur that enjoys food, travel, and a good dose of gaming.