The useGoogleReCaptcha hook provides programmatic access to the reCAPTCHA validation function. This is the recommended approach for most use cases as it gives you full control over when validation occurs.
This hook must be used within a component that is wrapped by GoogleReCaptchaProvider.
Installation
npm install react-google-recaptcha-v3
Basic Usage
import { useCallback } from 'react';
import { GoogleReCaptchaProvider, useGoogleReCaptcha } from 'react-google-recaptcha-v3';
function YourComponent() {
const { executeRecaptcha } = useGoogleReCaptcha();
const handleSubmit = useCallback(async () => {
if (!executeRecaptcha) {
console.log('Execute recaptcha not yet available');
return;
}
const token = await executeRecaptcha('submit');
// Send token to your backend
console.log('Token:', token);
}, [executeRecaptcha]);
return <button onClick={handleSubmit}>Submit</button>;
}
function App() {
return (
<GoogleReCaptchaProvider reCaptchaKey="YOUR_RECAPTCHA_SITE_KEY">
<YourComponent />
</GoogleReCaptchaProvider>
);
}
import { useCallback } from 'react';
import { GoogleReCaptchaProvider, useGoogleReCaptcha } from 'react-google-recaptcha-v3';
function YourComponent() {
const { executeRecaptcha } = useGoogleReCaptcha();
const handleSubmit = useCallback(async () => {
if (!executeRecaptcha) {
console.log('Execute recaptcha not yet available');
return;
}
const token = await executeRecaptcha('submit');
// Send token to your backend
console.log('Token:', token);
}, [executeRecaptcha]);
return <button onClick={handleSubmit}>Submit</button>;
}
function App() {
return (
<GoogleReCaptchaProvider reCaptchaKey="YOUR_RECAPTCHA_SITE_KEY">
<YourComponent />
</GoogleReCaptchaProvider>
);
}
Return Value
The hook returns an object with the following properties:
executeRecaptcha
((action?: string) => Promise<string>) | undefined
Function to execute reCAPTCHA validation and get a token.
- Returns: A Promise that resolves to a reCAPTCHA token string
- Parameter:
action (optional) - A string describing the action being performed
- Value:
undefined until the reCAPTCHA script has loaded successfully
Always check if executeRecaptcha is defined before calling it, as it will be undefined until the reCAPTCHA script loads.
container
string | HTMLElement | undefined
Reference to the custom container element if one was specified in the GoogleReCaptchaProvider.This is only relevant if you’re using a custom badge container.
Examples
import { useCallback, FormEvent } from 'react';
import { useGoogleReCaptcha } from 'react-google-recaptcha-v3';
function LoginForm() {
const { executeRecaptcha } = useGoogleReCaptcha();
const handleSubmit = useCallback(async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!executeRecaptcha) {
console.log('Execute recaptcha not yet available');
return;
}
// Get the token
const token = await executeRecaptcha('login');
// Get form data
const formData = new FormData(e.currentTarget);
const email = formData.get('email');
const password = formData.get('password');
// Send to backend with token
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();
console.log('Login response:', data);
}, [executeRecaptcha]);
return (
<form onSubmit={handleSubmit}>
<input name="email" type="email" required />
<input name="password" type="password" required />
<button type="submit">Login</button>
</form>
);
}
import { useCallback, useState } from 'react';
import { useGoogleReCaptcha } from 'react-google-recaptcha-v3';
function VerifyButton() {
const { executeRecaptcha } = useGoogleReCaptcha();
const [token, setToken] = useState<string>('');
const [loading, setLoading] = useState(false);
const handleClick = useCallback(async () => {
if (!executeRecaptcha) {
console.log('Execute recaptcha not yet available');
return;
}
setLoading(true);
try {
const token = await executeRecaptcha('verify_button');
setToken(token);
console.log('Verification successful:', token);
} catch (error) {
console.error('Verification failed:', error);
} finally {
setLoading(false);
}
}, [executeRecaptcha]);
return (
<div>
<button onClick={handleClick} disabled={loading || !executeRecaptcha}>
{loading ? 'Verifying...' : 'Verify'}
</button>
{token && <p>Token: {token.substring(0, 20)}...</p>}
</div>
);
}
Validation on Component Mount
import { useEffect, useCallback, useState } from 'react';
import { useGoogleReCaptcha } from 'react-google-recaptcha-v3';
function AutoVerifyComponent() {
const { executeRecaptcha } = useGoogleReCaptcha();
const [verified, setVerified] = useState(false);
const handleVerify = useCallback(async () => {
if (!executeRecaptcha) {
return;
}
const token = await executeRecaptcha('page_view');
// Verify on backend
const response = await fetch('/api/verify', {
method: 'POST',
body: JSON.stringify({ token })
});
const data = await response.json();
setVerified(data.success);
}, [executeRecaptcha]);
useEffect(() => {
handleVerify();
}, [handleVerify]);
return (
<div>
{verified ? 'Verified!' : 'Verifying...'}
</div>
);
}
Multiple Actions with Different Contexts
import { useCallback } from 'react';
import { useGoogleReCaptcha } from 'react-google-recaptcha-v3';
function MultiActionForm() {
const { executeRecaptcha } = useGoogleReCaptcha();
const handleSaveDraft = useCallback(async () => {
if (!executeRecaptcha) return;
const token = await executeRecaptcha('save_draft');
await fetch('/api/save-draft', {
method: 'POST',
body: JSON.stringify({ token, /* draft data */ })
});
}, [executeRecaptcha]);
const handlePublish = useCallback(async () => {
if (!executeRecaptcha) return;
const token = await executeRecaptcha('publish');
await fetch('/api/publish', {
method: 'POST',
body: JSON.stringify({ token, /* publish data */ })
});
}, [executeRecaptcha]);
const handleDelete = useCallback(async () => {
if (!executeRecaptcha) return;
const token = await executeRecaptcha('delete');
await fetch('/api/delete', {
method: 'DELETE',
body: JSON.stringify({ token })
});
}, [executeRecaptcha]);
return (
<div>
<button onClick={handleSaveDraft}>Save Draft</button>
<button onClick={handlePublish}>Publish</button>
<button onClick={handleDelete}>Delete</button>
</div>
);
}
With Loading and Error States
import { useCallback, useState } from 'react';
import { useGoogleReCaptcha } from 'react-google-recaptcha-v3';
function RobustForm() {
const { executeRecaptcha } = useGoogleReCaptcha();
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string>('');
const handleSubmit = useCallback(async () => {
if (!executeRecaptcha) {
setError('ReCAPTCHA not loaded yet');
return;
}
setLoading(true);
setError('');
try {
const token = await executeRecaptcha('submit_form');
const response = await fetch('/api/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token })
});
if (!response.ok) {
throw new Error('Verification failed');
}
const data = await response.json();
if (data.score < 0.5) {
setError('Verification score too low. Please try again.');
return;
}
console.log('Success!');
} catch (err) {
setError(err instanceof Error ? err.message : 'An error occurred');
} finally {
setLoading(false);
}
}, [executeRecaptcha]);
return (
<div>
<button onClick={handleSubmit} disabled={loading || !executeRecaptcha}>
{loading ? 'Processing...' : 'Submit'}
</button>
{error && <p style={{ color: 'red' }}>{error}</p>}
{!executeRecaptcha && <p>Loading reCAPTCHA...</p>}
</div>
);
}
Dynamic Action Names
import { useCallback, useState } from 'react';
import { useGoogleReCaptcha } from 'react-google-recaptcha-v3';
function DynamicActionExample() {
const { executeRecaptcha } = useGoogleReCaptcha();
const [action, setAction] = useState('homepage');
const [token, setToken] = useState('');
const handleExecute = useCallback(async () => {
if (!executeRecaptcha) return;
const result = await executeRecaptcha(action);
setToken(result);
}, [executeRecaptcha, action]);
return (
<div>
<select value={action} onChange={(e) => setAction(e.target.value)}>
<option value="homepage">Homepage</option>
<option value="login">Login</option>
<option value="signup">Signup</option>
<option value="checkout">Checkout</option>
</select>
<button onClick={handleExecute}>Execute</button>
{token && <p>Token: {token.substring(0, 30)}...</p>}
</div>
);
}
Best Practices
Always Check for Undefined: The executeRecaptcha function will be undefined until the reCAPTCHA script loads. Always check before calling:if (!executeRecaptcha) {
console.log('Not ready yet');
return;
}
Use Meaningful Action Names: Choose descriptive action names that represent the user action being protected:
"login", "signup", "purchase"
"submit_comment", "send_message"
"reset_password", "change_email"
Wrap in useCallback: When using executeRecaptcha in event handlers or effects, wrap your functions with useCallback to prevent unnecessary re-renders:const handleSubmit = useCallback(async () => {
// ...
}, [executeRecaptcha]);
Verify on Server: Never trust the token on the client side alone. Always send it to your backend server and verify it using Google’s siteverify API.
Token Expiration: reCAPTCHA tokens expire after a few minutes. Generate them right before you need them, not ahead of time.
Error Handling: Always wrap executeRecaptcha calls in try-catch blocks to handle potential errors gracefully.
Common Patterns
function Form() {
const { executeRecaptcha } = useGoogleReCaptcha();
return (
<button disabled={!executeRecaptcha} type="submit">
Submit
</button>
);
}
Show Loading State
function Form() {
const { executeRecaptcha } = useGoogleReCaptcha();
if (!executeRecaptcha) {
return <div>Loading reCAPTCHA...</div>;
}
return <form>{/* form content */}</form>;
}
Execute Without Action
// Action is optional
const token = await executeRecaptcha();
// or with action
const token = await executeRecaptcha('my_action');
TypeScript Types
interface IGoogleReCaptchaConsumerProps {
executeRecaptcha?: (action?: string) => Promise<string>;
container?: string | HTMLElement;
}
const useGoogleReCaptcha: () => IGoogleReCaptchaConsumerProps;
When to Use This Hook
Use useGoogleReCaptcha when:
- You need manual control over validation timing (recommended)
- You want to trigger validation on button clicks or form submissions
- You need to execute validation multiple times
- You’re using functional components (most modern React)
Use GoogleReCaptcha component when:
- You want automatic validation on mount
- You prefer a declarative API
- Validation should happen based on prop changes
Use withGoogleReCaptcha HOC when:
- You’re working with class components
- You can’t use hooks
Implementation Details
Under the hood, useGoogleReCaptcha is a simple wrapper around React’s useContext hook:
// From source: src/use-google-recaptcha.tsx:1
import { useContext } from 'react';
import { GoogleReCaptchaContext } from './google-recaptcha-provider';
export const useGoogleReCaptcha = () => useContext(GoogleReCaptchaContext);
It provides access to the context created by GoogleReCaptchaProvider, which includes the executeRecaptcha function that calls Google’s reCAPTCHA API.
See Also