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
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.
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:
- Handle REST API calls
- Validate the reCAPTCHA score
- 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.