In this article, we’ll demonstrate how to implement reCAPTCHA v2 in a React application and how to verify user tokens in a Node.js backend.
To follow along with the examples in the tutorial portion of this article, you should have a foundational knowledge of:
CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart) is a type of challenge-response security measure designed to differentiate between real website users and automated users, such as bots.
Many web services use CAPTCHAs to help prevent unwarranted and illicit activities such as spamming and password decryptions. CAPTCHAs require users to complete a simple test to demonstrate they are human and not a bot before giving them access to sensitive information.
There are several types of CAPTCHA systems, but the most widely used system is reCAPTCHA, a tool from Google. Luis von Ahn, the co-founder of Duolingo, created the tool back in 2007 and is being used by more than six million websites, including BBC, Bloomberg, and Facebook.
The first version of reCAPTCHA was made up of randomly generated sequences of distorted alphabetic and numeric characters and a text box.
To pass the test, a user needs to decypher the distorted characters and type them into the text box. Although computers are capable of creating images and generating responses, they can’t read or interpret information in the same way a person can to pass the test.
reCAPTCHA generates a response token for each request a user makes and sends it to Google’s API for verification. The API returns a score that determines if the user is human or an automated program.
reCAPTCHA currently has two working versions: v2 and v3. Although v3 is the most recent version of reCAPTCHA (released in 2018), most websites still use reCAPTCHA v2, which was released in 2014.
reCAPTCHA v2 has two variants: checkbox and invisible. The checkbox variant, which is also known as “I’m not a robot”, is the most popular. one option for this variant displays a checkbox widget that users can interact with to verify their identity.
The invisible variant displays a reCAPTCHA badge, indicating that the service is running in the background.
In some cases where a user’s behavior triggers suspicion, reCAPTCHA v2 will serve up a challenge that the user must pass to prove they’re not a bot.
Now that we understand what reCAPTCHA is, let’s see how we can implement it in a React app. But first, we need to sign our app up for an API key in the Google reCAPTCHA console. The key pair consists of two keys: site key and secret key.
The site key invokes the reCAPTCHA service in our app. The secret key verifies the user’s response. It does this by authorizing the communication between our app’s backend and the reCAPTCHA server.
Go ahead and create your key pair here.
First, you’ll need to sign in with your Google account. Then, you’ll be redirected to the admin console. Next, you’ll fill out the registration form on the page to generate your site’s key pair.
The registration is fairly straightforward, but for clarity, I’ll explain what each form field means and how to fill each field.
For the label field, provide a name to help you recognize the purpose of the key pair that you’re creating. If you have more than one key pair set up on your account, the labels will help you distinguish between them.
The type selector refers to the version of reCAPTCHA that you want to use on your site. You can choose either v3 or v2. Since this tutorial will only cover v2 implementation, go ahead and choose v2 and the “I am not a robot” variant.
The domains field is where you’ll set the domain names that will work with your reCAPTCHA. You can input a valid domain name or “localhost” if your project is still in development, and click + to add the domain.
The owner field is where you can provision access to your app’s reCAPTCHA to others. By default, you’ll be the owner, but you can add more individuals by providing their Google emails.
Once you’ve completed the form fields, check the necessary boxes and click Submit.
Now you should be able to see your site key and secret key. They will look similar to the ones shown here:
Next, we‘ll set up a React sample project and implement reCAPTCHA using the key pairs we just created.
To verify a user’s input with reCAPTCHA we require a server that’ll communicate with Google’s API. So we‘ll need to keep that in mind when setting up the project.
First, create a folder. For this sample project, I will name the folder react-node-app
, but you can use a different name of your choosing.
Next, open the folder in your preferred IDE and run the following command:
npm init -y
This will create a package.json
file that will help us manage our dependencies and keep track of our scripts.
Go ahead and bootstrap a React app with create-react-app
by typing the following command in your terminal:
npx create-react-app my-app
This command will create a my-app
folder inside the react-node-app
folder and will install React inside the my-app
folder.
After installation, open the my-app
folder and clean up the unnecessary boilerplate codes and files in the project folder, then create a Form.js
component within the src
folder.
Next, add the following code into the form component and import it inside the App.js
main component.
const Form = () =>{ return( <form> <label htmlFor="name">Name</label> <input type="text" id="name" className="input"/> <button>Submit</button> </form> ) } export default Form
The above code is a simple login form with an input
element and a Submit
button.
Styling the form component isn’t necessary, but if you’d like to add a little flair, add the following CSS code inside the App.css
file in the project folder.
.input{ width: 295px; height: 30px; border: rgb(122, 195, 238) 2px solid; display: block; margin-bottom: 10px; border-radius: 3px; } .input:focus{ border: none; } label{ display: block; margin-bottom: 2px; font-family: 'Courier New', Courier, monospace; } button{ padding: 7px; margin-top: 5px; width: 300px; background-color: rgb(122, 195, 238); border: none; border-radius: 4px; }
Now, start the development server with the command npm start
in the terminal.
You should see a form similar to this displayed on your browser:
N.B., It is recommended to use a framework that has support for SSR (server-side-rendering), like Next.js or Remix, when creating something similar for production.
react-google-recaptcha
The react-google-recaptcha
library enables the integration of Google reCAPTCHA v2 in React. The package provides a component that simplifies the process of handling and rendering reCAPTCHA in React with the help of useful props.
To install react-google-recaptch
a, type and run the following command:
npm install --save react-google-recaptcha
After installing react-google-recaptcha
, head over to the form.js
component file and import it, like so:
import reCAPTCHA from "react-google-recaptcha"
Now add the reCAPTCHA
component to the form, just before or after the Submit
button. Your placement of the component is optional, the reCAPTCHA widget will appear wherever the reCAPTCHA
component is placed in the form when rendered.
<form > <label htmlFor="name">Name</label> <input type="text" id="name" className="input"/> <reCAPTCHA /> <button>Submit</button> </form>
As mentioned previously, the reCAPTCHA
component accepts several props. However, the sitekey
prop is the only prop we need to render the component. This prop facilitates the connection between the site key we generated earlier from the reCAPTCHA key pair and the reCAPTCHA
component.
Here are other optional props of the reCAPTCHA
component:
theme
: changes the widget’s theme to light
or dark
size
: changes the size or type of CAPTCHAonErrored
: fires a callback function if the test returns an errorbadge
: changes the position of the reCAPTCHA badge (bottomright
, bottomleft
, or inline
)ref
: used to access the component instance API<reCAPTCHA sitekey={process.env.REACT_APP_SITE_KEY} />
Here we add a sitekey
prop to the reCAPTCHA
component and pass it an environment variable with the reCAPTCHA site key.
To do the same in your project, create a .env
file in the root folder of your project. Next, add the following code to the file:
/*.env*/ REACT_APP_SECRET_KEY = "Your secret key" REACT_APP_SITE_KEY = "your site key"
This way, you can use your secret keys safely in your app by referencing the variable names where they’re needed.
Now, if save your code and go to the browser, a reCAPTCHA box should appear where the reCAPTCHA component is placed in your code. In this example, it appears before the submit button.
After each verification, we need to reset the reCAPTCHA for subsequent checks. To accomplish this, we need to add a ref
prop to the reCAPTCHA
component.
To use the ref
prop, first, import the useRef
hook from React:
import React, { useRef } from 'react';
Next, store the ref
value in a variable, like so:
const captchaRef = useRef(null)
Then, add the ref
prop to the reCAPTCHA
component and pass it the captchaRef
variable:
<reCAPTCHA sitekey={process.env.REACT_APP_SITE_KEY} ref={captchaRef} />
Here’s the entire code in our Form
component up to this point:
import ReCAPTCHA from "react-google-recaptcha" const Form = () =>{ return( <form> <label htmlFor="name">Name</label> <input type="text" id="name" className="input"/> <reCAPTCHA sitekey={process.env.REACT_APP_SITE_KEY} ref={captchaRef} /> <button>Submit</button> </form> ) } export default Form
Now that we have a working widget, we just need to complete three steps to get reCAPTCHA functioning:
reCAPTCHA
componentreCAPTCHA
component for subsequent checksWe can also use the ref
prop to get the generated token from our reCAPTCHA. All we have to do is get the value of the ref
with the following code:
const token = captchaRef.current.getValue();
If we add the above code to the form component, it will actually cause an error. This is because the value of the ref
is still null, since the reCAPTCHA is in an unchecked state. To solve this issue, we we’ll add an onSubmit
event handler to the form with a function that encapsulates the code:
const handleSubmit = (e) =>{ e.preventDefault(); const token = captchaRef.current.getValue(); captchaRef.current.reset(); } return( <form onSubmit={handleSubmit} > … </form> )
In the above code, we created a handleSubmit
function. Inside this function, we added the token
variable for getting the response token from reCAPTCHA, as well as a code that resets the reCAPTCHA each time the form is submitted.
This way, the getValue()
method will only attempt to get the ref’s value, which is the response token, when the submit button is clicked.
Now if you log the token
variable to the console, check the reCAPTCHA box, and submit the form, you should see a generated response token similar to the one below in your console:
The token we generated in the previous section is only valid for two minutes, which means we need to verify it before it expires. To do so, we’ll need to set up our app’s backend and send the token to Google’s API to check the user’s score.
To set up a Node.js server, navigate back to the react-node-app
folder, create a new folder, and name it server
. Inside the server
folder, create a new file and name it index.js
. This file will serve as the entry point for our Node app.
Next, cd into the server
folder and run the following command to install Express.js and Axios:
npm i express axios cors dotenv --save
Now, add the following code inside the index.js
file:
const express = require("express"); const router = express.Router(); const app = express(); const cors = require("cors"); const axios = require("axios"); require("dotenv").config(); const port = process.env.PORT || 2000; //enabling cors app.use(cors()); //Parse data app.use(express.json()); app.use(express.urlencoded({ extended: true })); //add router in express app app.use("/", router); //POST route router.post("/post", async (req, res) => { ////Destructuring response token and input field value from request body const { token, inputVal } = req.body; try { // Sending secret key and response token to Google Recaptcha API for authentication. const response = await axios.post( `https://www.google.com/recaptcha/api/siteverify?secret=${process.env.SECRET_KEY}&response=${token}` ); // Check response status and send back to the client-side if (response.data.success) { res.send("Human 👨 👩"); } else { res.send("Robot 🤖"); } } catch (error) { // Handle any errors that occur during the reCAPTCHA verification process console.error(error); res.status(500).send("Error verifying reCAPTCHA"); } }); app.listen(port, () => { console.log(`server is running on ${port}`); });
In the above code, we set up an Express server and created a POST
API endpoint for the /post
route. Inside the endpoint function, we destructured the request body to get the token
and inputVal
data that will be sent from the client.
Then we created an axios.post
request to Google’s API with our SECRET_KEY
passed in as an environment variable, as well as the token
from the client side.
To set up an environment variable in Node.js, cd back to the react-node-app
folder and run the following command:
npm install dotenv --save
After installation, create a .env
file within the react-node-app
folder, open the file, then add your site’s secret key.
Beneath the axios.post
request is an if
statement that checks the status of the response returned by the API and sends it to the client side.
Ok, let’s move on. Navigate back to the react-node-app
folder, open the package.json
file, and replace the script command with the following:
… "scripts": { "start": "node server/index.js" }, …
The above code will let us start our server using the npm start
command when we run it in the terminal.
Save the project. Then, go to your terminal, open a new terminal tab, cd into the server
folder, and start the server by running npm start
.
Next, we’ll send an axios.post
request from the client side (React app) to our server, with the generated token as the data.
To do this, navigate back to your React app and paste the following code inside the handleSubmit
function we created earlier:
const handleSubmit = async (e) =>{ e.preventDefault(); const inputVal = await e.target[0].value; const token = captchaRef.current.getValue(); captchaRef.current.reset(); await axios.post(“http://localhost:2000/post”, { inputVal, token }) .then(res => console.log(res)) .catch((error) => { console.log(error); }) }
This code is an axios.post
request that sends the generated token and input field value from reCAPTCHA and input field to the Node.js backend.
If you save your code and run the app, you should see a reCAPTCHA form similar to this:
Similarly, attempting to submit the form without verifying the widget should yield the following outcome.
reaptcha
wrapperreact.captcha (Reaptcha) is an alternative solution for implementing reCAPTCHA in React. The library shares similar features with react-google-recaptcha, but unlike the former, Reaptcha handles reCAPTCHA’s callbacks inside React components and automatically injects the reCAPTCHA script into the head DOM element.
This way, your applications would not have to depend on the library and directly communicate with the reCAPTCHA API when deployed.
To install Reaptcha, run the following command within your terminal:
npm install --save reaptcha
After installation, go to the form.js
file and import the Reaptcha component like so:
import Reaptcha from 'reaptcha';
The Reaptcha component provides several props that can be used to customize the rendering. Here is a list of the available props:
sitekey
: Accepts the client key (site key we generated earlier in this article)theme
: Optional prop for changing the widget’s appearance (light or dark)onLoad
: Optional callback function that gets called when the Google reCAPTCHA script has been loadedonVerify
: Optional callback function that gets called when a user completes the captchaonExpire
: Optional callback function that gets called when the challenge is expired and has to be redoneexplicit
: Optional prop that allows the widget to be rendered explicitly, i.e., invisiblesize
: Optional prop that allows you to change the widget’s size to compact, normal, or invisibleref
: Used for accessing the component’s instance methodsAlthough most of these props look similar to the ones exposed by the react-google-recaptcha’s component, not all of them work as you’d expect. The ref
prop for one doesn’t have a method like getValue()
for getting the response token. Instead, it uses a getResponse()
instance method that returns the token with a promise.
Therefore, adding the component to the form component and retrieving the response token will be as follows:
const [captchaToken, setCaptchaToken] = useState(null); const captchaRef = useRef(null); const verify = () =>{ captchaRef.current.getResponse().then(res => { setCaptchaToken(res) }) } return( <form onSubmit={handleSubmit} > <Reaptcha sitekey={process.env.REACT_APP_SITE_KEY} ref={captchaRef} onVerify={verify} > </form> ) }
Here, we created a verify
function. Inside it, we’re fetching the response token from the ref
variable using the getResponse()
instance method. Since the method returns a promise, we chained a then
method to it and pass the response to the captchaToken
state variable.
We also pass the verify
function to the onVerify
prop on the component so that the function will only attempt to fetch the responses token when a user completes the captcha.
The component’s instance methods are utility functions that can be called to perform certain actions. Just as we used the getResponse
method to grab the response token earlier, we can use other methods to perform different actions, like resetting the widget after every form submission. Here is a list of available instance methods:
reset
renderExplicitly
execute
getResponse
Visit the documentation to learn more about these methods and the Reapatcha library.
That’s it! You’ve successfully implemented a working Google reCAPTCHA and a backend server that verifies users’ responses in React.
In this article, we examined what reCAPTCHA is and how it works. We also walked through a tutorial to demonstrate how to implement reCAPTCHA in a React application and how to verify a user’s response token with a Node.js backend server.
I hope this article will help you build secure and bot-free React applications.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowCompare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
13 Replies to "How to implement reCAPTCHA in a React application"
Great post. I ran into some trouble after naming my component in lower case and React wasnt reconizing it as a component until i changed it lo upper case.
Thank you, Mark. React components always start with uppercase letters. The library treats any component with lowercase initials as HTML elements.
Hi I ran into an issue that form still submit even when reCaptcha is not clicked
Hi Rasam, you have to perform a conditional check based on the response you get from the server. If it’s positive, submit the form. If not, do otherwise. I hope this helps.
Something’s wrong with the backend here – the form does not verify the secret key or token and always shows that its human – regardless if you click the checkbox or not
Hi Laura, I would like to express my apologies for any inconvenience you may have experienced. The handling of the Google API response was not executed correctly. However, I have rectified the issue and I hope you can continue with your work without any further issues. happy hacking!
Using nodejs for the captcha verification process is totally unnecessary.
Just use const [isVerified, setVerified] = useState(false);
And create an onChange handler and add it to your recaptcha component
All the onChange handler has to do is check for a token and if there is a token set “isVerified” to true
This approach of yours only checks for a token. Node.js is for verifying the generated token with Google’s API.
Does anyone know how the ‘reaptcha’ library works? I’ve looked through their example code but I can’t see where they’re verifying the captcha with Google’s servers.
And if they are handling verification with Google, how are they doing it without the secret key? AFAIK and according to this article, it’s essential to the verification process.
Perhaps this will help you clarify your dilemma: https://developers.google.com/recaptcha/docs/verify
Nice article dave.
Thanks for this tutorial. It seems that this tutorial has some errors:
– For the server, the `npm i` command should also include `cors` (besides `express`, `axios`, `dotenv`)
– In the updated `handleSubmit` function that makes the request to the server, the `axios.post` call should take the arguments `(“http://localhost:2000/post”, { inputVal, token })`, instead of `(inputVal, token)`
Thanks Jason, I’ve made the correction.