Skip to main content

Get Your First reCAPTCHA Working

This quickstart guide will get you from zero to a working reCAPTCHA v3 integration in just a few minutes. We’ll use the recommended useGoogleReCaptcha hook approach.
1

Install the package

Install react-google-recaptcha-v3 using your preferred package manager:
npm install react-google-recaptcha-v3
This library requires React 16.3 or higher. Check your package.json to ensure compatibility.
2

Get your reCAPTCHA site key

  1. Visit the Google reCAPTCHA admin console
  2. Click the + button to register a new site
  3. Enter a label for your site (e.g., “My React App”)
  4. Select reCAPTCHA v3 as the type
  5. Add your domain(s) - use localhost for development
  6. Accept the terms of service
  7. Click Submit
  8. Copy your Site Key (you’ll need this in the next step)
Make sure you select reCAPTCHA v3, not v2. The two versions are not compatible.
3

Add the provider to your app

Wrap your application with GoogleReCaptchaProvider at the root level. This loads the reCAPTCHA script and provides access to the verification function throughout your app.
App.tsx
import React from 'react';
import { GoogleReCaptchaProvider } from 'react-google-recaptcha-v3';
import LoginForm from './LoginForm';

function App() {
  return (
    <GoogleReCaptchaProvider reCaptchaKey="YOUR_RECAPTCHA_SITE_KEY">
      <div className="app">
        <h1>My Application</h1>
        <LoginForm />
      </div>
    </GoogleReCaptchaProvider>
  );
}

export default App;
Store your site key in an environment variable (e.g., REACT_APP_RECAPTCHA_SITE_KEY or VITE_RECAPTCHA_SITE_KEY) rather than hardcoding it.
4

Execute reCAPTCHA on user actions

Use the useGoogleReCaptcha hook to verify user actions. Here’s a complete login form example:
LoginForm.tsx
import React, { useState, useCallback } from 'react';
import { useGoogleReCaptcha } from 'react-google-recaptcha-v3';

function LoginForm() {
  const { executeRecaptcha } = useGoogleReCaptcha();
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [loading, setLoading] = useState(false);
  const [message, setMessage] = useState('');

  const handleSubmit = useCallback(async (e: React.FormEvent) => {
    e.preventDefault();
    
    // Check if executeRecaptcha is available
    if (!executeRecaptcha) {
      setMessage('reCAPTCHA not yet loaded');
      return;
    }

    setLoading(true);
    setMessage('');

    try {
      // Execute reCAPTCHA with action name 'login'
      const token = await executeRecaptcha('login');
      
      // Send token to your backend for verification
      const response = await fetch('/api/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          email,
          password,
          recaptchaToken: token
        })
      });

      const data = await response.json();

      if (response.ok) {
        setMessage('Login successful!');
        // Redirect or update app state
      } else {
        setMessage(data.error || 'Login failed');
      }
    } catch (error) {
      setMessage('An error occurred. Please try again.');
      console.error('Login error:', error);
    } finally {
      setLoading(false);
    }
  }, [executeRecaptcha, email, password]);

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="email">Email:</label>
        <input
          id="email"
          type="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          required
        />
      </div>
      
      <div>
        <label htmlFor="password">Password:</label>
        <input
          id="password"
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          required
        />
      </div>

      <button type="submit" disabled={loading}>
        {loading ? 'Logging in...' : 'Log In'}
      </button>

      {message && <p>{message}</p>}
    </form>
  );
}

export default LoginForm;
The action parameter (e.g., 'login') helps you understand which actions generated which scores in the reCAPTCHA admin console analytics.
5

Verify the token on your backend

Critical: Always verify reCAPTCHA tokens on your backend. Here’s an example using Node.js/Express:
server.js
const express = require('express');
const fetch = require('node-fetch');

const app = express();
app.use(express.json());

const RECAPTCHA_SECRET_KEY = process.env.RECAPTCHA_SECRET_KEY;

app.post('/api/login', async (req, res) => {
  const { email, password, recaptchaToken } = req.body;

  // Verify reCAPTCHA token with Google
  const verifyUrl = `https://www.google.com/recaptcha/api/siteverify`;
  const verifyResponse = await fetch(verifyUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: `secret=${RECAPTCHA_SECRET_KEY}&response=${recaptchaToken}`
  });

  const verifyData = await verifyResponse.json();

  // Check if verification was successful
  if (!verifyData.success) {
    return res.status(400).json({ error: 'reCAPTCHA verification failed' });
  }

  // Check the score (0.0 to 1.0, higher is better)
  if (verifyData.score < 0.5) {
    return res.status(400).json({ 
      error: 'Suspicious activity detected',
      score: verifyData.score 
    });
  }

  // Proceed with login logic
  // ... authenticate user with email/password ...

  res.json({ success: true, message: 'Login successful' });
});

app.listen(3000, () => console.log('Server running on port 3000'));
Never expose your reCAPTCHA secret key in client-side code! Store it securely in environment variables on your server.

Test Your Integration

After completing the steps above, test your integration:
  1. Open your app in a browser and navigate to your login form
  2. Fill out the form and click submit
  3. Check the network tab in your browser’s developer tools - you should see a request to recaptcha/api.js
  4. Verify your backend receives and validates the token
  5. Visit the reCAPTCHA admin console to view analytics and scores
During development, you may see lower scores. reCAPTCHA learns over time and considers factors like browsing history and mouse movements.

Understanding Scores

reCAPTCHA v3 returns a score between 0.0 and 1.0:
  • 1.0 - Very likely a legitimate user
  • 0.5 - Neutral (recommended threshold)
  • 0.0 - Very likely a bot
You can adjust the threshold based on your needs. For example:
  • 0.7+ for high-security actions (password changes, payments)
  • 0.5+ for medium-security actions (login, contact forms)
  • 0.3+ for low-risk actions (newsletter signup)

Common Pitfalls

This happens when the reCAPTCHA script hasn’t loaded yet. Always check if executeRecaptcha is available before calling it:
if (!executeRecaptcha) {
  console.log('Execute recaptcha not yet available');
  return;
}
Using inline functions for callbacks can cause infinite renders. Use useCallback:
// ❌ Bad - inline function
const handleVerify = async (token) => { ... };

// ✅ Good - memoized with useCallback
const handleVerify = useCallback(async (token) => { ... }, [dependencies]);
Make sure you’re using a v3 site key, not v2. They are not interchangeable. Check your key in the reCAPTCHA admin console.

Next Steps

Components

Learn about all available components and their props

Guides

Explore advanced features like Enterprise and custom containers

Examples

Browse more real-world usage examples

API Reference

Dive into the complete API documentation

Need Help?

Build docs developers (and LLMs) love