How to implement reCAPTCHA v3 in React
Today we’ll show you how to implement reCAPTCHA v3 in React. There are many libraries that are available to add Google reCAPTCHA to the React application, but if possible the functionality should be implemented without external packages.
Here, we will use Google reCAPTCHA official document in a slightly different way. We have to finish this functionality in two parts. In this part, we will show you how to generate google reCAPTCHA v3 keys and how to implement them in the react application. Whereas in the second part, we will show you how to verify the response in the backend.
Google reCAPTCHA v3
- Part 1 – Implement reCAPTCHA v3 in React (You are here…)
- Part 2 – Verify Google reCAPTCHA v3 using Node.js
Steps to implement reCAPTCHA v3 in React
- Generate google reCAPTCHA v3 keys
- Create a react application
- Add google reCAPTCHA in component
- Call a backend API to verify reCAPTCHA response
- Output
1. Generate google reCAPTCHA v3 keys
First, we have to generate reCAPTCHA v3 keys from which we will use the SITE KEY for the client side integration and the SECRET KEY for the server side integration. Use this link to generate keys. The following image will help you to create keys.
Note: Don’t forget to add localhost
in the Domains section for local development.
2. Create a react application
Let’s create a simple react application using the create-react-app
package. Run the following command to create a react app.
1 | npx create-react-app react-recaptcha-v3 |
3. Add google reCAPTCHA in component
First, we’ll create a simple form in the react component. We will submit the form data along with the reCAPTCHA token.
App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import { useState } from 'react'; function App() { const [name, setName] = useState(''); const [email, setEmail] = useState(''); const [loading, setLoading] = useState(false); const [response, setResponse] = useState(null); const handleOnClick = e => { } return ( <div className="App"> <h3>reCAPTCHA v3 in React - <a href="https://www.cluemediator.com/" target="_blank" rel="noopener noreferrer">Clue Mediator</a></h3> <div className="box"> <label>Name: </label> <input type="text" onChange={e => setName(e.target.value)} value={name} /> </div> <div className="box"> <label>Email: </label> <input type="text" onChange={e => setEmail(e.target.value)} value={email} /> </div> <button onClick={handleOnClick} disabled={loading}>{loading ? 'Submitting...' : 'Submit'}</button> <br /><br /> {response && <label>Output:<br /><pre>{JSON.stringify(response, undefined, 2)}</pre></label>} </div> ); } export default App; |
Use the following CSS to design the form.
index.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | body { margin: 0; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } .box { margin: 15px; } .box label { width: 50px; display: inline-block; text-align: right; margin-right: 7px; } .box input { padding: 5px 7px; border-radius: 3px; border: 1px solid #aaa; width: 200px; } button { cursor: pointer; padding: 5px 10px; margin-left: 73px; border-radius: 3px; border: 1px solid #aaa; } button:hover { background: #ddd; } |
Now, we have to dynamically load the JavaScript API with your site key.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | const SITE_KEY = "<YOUR_SITE_KEY>"; ... ... useEffect(() => { const loadScriptByURL = (id, url, callback) => { const isScriptExist = document.getElementById(id); if (!isScriptExist) { var script = document.createElement("script"); script.type = "text/javascript"; script.src = url; script.id = id; script.onload = function () { if (callback) callback(); }; document.body.appendChild(script); } if (isScriptExist && callback) callback(); } // load the script by passing the URL loadScriptByURL("recaptcha-key", `https://www.google.com/recaptcha/api.js?render=${SITE_KEY}`, function () { console.log("Script loaded!"); }); }, []); |
Now, we have to execute the google reCAPTCHA on the submit button click. Once we receive the token we will submit the data.
1 2 3 4 5 6 7 8 9 10 11 12 13 | const handleOnClick = e => { e.preventDefault(); setLoading(true); window.grecaptcha.ready(() => { window.grecaptcha.execute(SITE_KEY, { action: 'submit' }).then(token => { submitData(token); }); }); } const submitData = token => { // call a backend API to verify reCAPTCHA response } |
4. Call a backend API to verify reCAPTCHA response
In the final step, we have to call a backend API to pass the reCAPTCHA response along with the form data. Whereas in the backend, we have to verify the response using SECRET KEY. We’ll show you that step in the upcoming article.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | const submitData = token => { // call a backend API to verify reCAPTCHA response fetch('http://localhost:4000/verify', { method: 'POST', headers: { "Content-Type": "application/json" }, body: JSON.stringify({ "name": name, "email": email, "g-recaptcha-response": token }) }).then(res => res.json()).then(res => { setLoading(false); setResponse(res); }); } |
5. Output
Let’s combine all code together and see how it looks.
App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | import { useEffect, useState } from 'react'; const SITE_KEY = "<YOUR_SITE_KEY>"; function App() { const [name, setName] = useState(''); const [email, setEmail] = useState(''); const [loading, setLoading] = useState(false); const [response, setResponse] = useState(null); useEffect(() => { const loadScriptByURL = (id, url, callback) => { const isScriptExist = document.getElementById(id); if (!isScriptExist) { var script = document.createElement("script"); script.type = "text/javascript"; script.src = url; script.id = id; script.onload = function () { if (callback) callback(); }; document.body.appendChild(script); } if (isScriptExist && callback) callback(); } // load the script by passing the URL loadScriptByURL("recaptcha-key", `https://www.google.com/recaptcha/api.js?render=${SITE_KEY}`, function () { console.log("Script loaded!"); }); }, []); const handleOnClick = e => { e.preventDefault(); setLoading(true); window.grecaptcha.ready(() => { window.grecaptcha.execute(SITE_KEY, { action: 'submit' }).then(token => { submitData(token); }); }); } const submitData = token => { // call a backend API to verify reCAPTCHA response fetch('http://localhost:4000/verify', { method: 'POST', headers: { "Content-Type": "application/json" }, body: JSON.stringify({ "name": name, "email": email, "g-recaptcha-response": token }) }).then(res => res.json()).then(res => { setLoading(false); setResponse(res); }); } return ( <div className="App"> <h3>reCAPTCHA v3 in React - <a href="https://www.cluemediator.com/" target="_blank" rel="noopener noreferrer">Clue Mediator</a></h3> <div className="box"> <label>Name: </label> <input type="text" onChange={e => setName(e.target.value)} value={name} /> </div> <div className="box"> <label>Email: </label> <input type="text" onChange={e => setEmail(e.target.value)} value={email} /> </div> <button onClick={handleOnClick} disabled={loading}>{loading ? 'Submitting...' : 'Submit'}</button> <br /><br /> {response && <label>Output:<br /><pre>{JSON.stringify(response, undefined, 2)}</pre></label>} </div> ); } export default App; |
Run the project and check the output in the browser.
That’s it for today.
Thank you for reading. Happy Coding..!!
Thanks a lot!
Can you advise how to implement the back-end function? Perhaps in Firebase?
You can use the
firebase.auth.RecaptchaVerifier
to verify the reCAPTCHA.This just worked, thanks a lot!
Works like a charm! Thank you!
Glad it helped!
Thank you sir!