A React library for Google reCAPTCHA integration with both hooks and components supporting v2 and v3
npm install google-recaptcha-v3A clean, modern React library for Google reCAPTCHA integration with both hooks and components supporting v2 and v3.
``bash`
npm i google-recaptcha-v3
tsx
import { useGoogleRecaptcha } from "google-recaptcha-v3";
`$3
`tsx
import { GoogleRecaptcha } from "google-recaptcha-v3";
`Hook Usage (v3 only)
$3
`tsx
import React from "react";
import { useGoogleRecaptcha } from "google-recaptcha-v3";const YourComponent = () => {
const siteKey = "YOUR_SITE_KEY";
const action = "submit";
const { token, error, isLoading } = useGoogleRecaptcha(siteKey, action);
if (isLoading) {
return
Loading reCAPTCHA...;
} if (error) {
return
Error: {error};
} // You can use token to send request to API
return (
{token && reCAPTCHA token generated successfully!
}
);
};export default YourComponent;
`Component Usage
$3
`tsx
import React, { useRef } from "react";
import { GoogleRecaptcha, GoogleRecaptchaRef } from "google-recaptcha-v3";const YourComponent = () => {
const recaptchaRef = useRef(null);
const siteKey = "YOUR_SITE_KEY";
const handleSubmit = async () => {
if (recaptchaRef.current) {
const token = await recaptchaRef.current.execute();
if (token) {
console.log("reCAPTCHA token:", token);
// Send request to your API with the token
}
}
};
const handleChange = (token: string | null) => {
console.log("reCAPTCHA token changed:", token);
};
return (
ref={recaptchaRef}
sitekey={siteKey}
onChange={handleChange}
onExpired={() => console.log("reCAPTCHA expired")}
onErrored={(error) => console.error("reCAPTCHA error:", error)}
/>
);
};export default YourComponent;
`$3
`tsx
import React, { useRef } from "react";
import { GoogleRecaptcha, GoogleRecaptchaRef } from "google-recaptcha-v3";const YourComponent = () => {
const recaptchaRef = useRef(null);
const siteKey = "YOUR_SITE_KEY";
const handleSubmit = async () => {
const token = recaptchaRef.current?.getResponse();
if (token) {
// Send request to your API with the token
console.log("Submitting with token:", token);
} else {
alert("Please complete the reCAPTCHA");
}
};
const handleReset = () => {
recaptchaRef.current?.reset();
};
return (
ref={recaptchaRef}
sitekey={siteKey}
theme="dark"
size="compact"
hl="vi" // Vietnamese
onChange={(token) => console.log("Token:", token)}
onExpired={() => {
console.log("reCAPTCHA expired");
handleReset();
}}
onErrored={(error) => console.error("Error:", error)}
style={{ margin: "20px 0" }}
/>
);
};export default YourComponent;
`$3
`tsx
import React, { useRef } from "react";
import { GoogleRecaptcha, GoogleRecaptchaRef } from "google-recaptcha-v3";const YourComponent = () => {
const recaptchaRef = useRef(null);
const siteKey = "YOUR_SITE_KEY";
const handleSubmit = async () => {
try {
const token = await recaptchaRef.current?.executeAsync();
if (token) {
console.log("v3 token:", token);
// Send request to your API with the token
}
} catch (error) {
console.error("Failed to get token:", error);
}
};
return (
ref={recaptchaRef}
sitekey={siteKey}
version="v3"
action="submit"
onLoad={() => console.log("reCAPTCHA v3 loaded")}
onErrored={(error) => console.error("reCAPTCHA error:", error)}
/>
);
};export default YourComponent;
`$3
`tsx
import React, { useRef } from "react";
import { GoogleRecaptcha, GoogleRecaptchaRef } from "google-recaptcha-v3";const YourComponent = () => {
const recaptchaRef = useRef(null);
const siteKey = "YOUR_SITE_KEY";
const handleSubmit = async () => {
try {
// For invisible reCAPTCHA, execute when user submits
const token = await recaptchaRef.current?.executeAsync();
if (token) {
console.log("Invisible reCAPTCHA token:", token);
// Send request to your API with the token
}
} catch (error) {
console.error("Failed to execute invisible reCAPTCHA:", error);
}
};
return (
ref={recaptchaRef}
sitekey={siteKey}
size="invisible"
badge="bottomright"
onLoad={() => console.log("Invisible reCAPTCHA loaded")}
onErrored={(error) => console.error("Error:", error)}
/>
);
};export default YourComponent;
`$3
`tsx
import React from "react";
import { useGoogleRecaptcha, ReCaptchaOptions } from "google-recaptcha-v3";const YourComponent = () => {
const siteKey = "YOUR_SITE_KEY";
const action = "submit";
const options: ReCaptchaOptions = { language: "vi" }; // Vietnamese language
const {
token,
error,
isLoading,
refreshToken,
executeRecaptcha
} = useGoogleRecaptcha(siteKey, action, options);
const handleSubmit = async () => {
try {
const newToken = await executeRecaptcha();
if (newToken) {
// Send request to your API with the token
console.log("New token:", newToken);
}
} catch (err) {
console.error("Failed to get reCAPTCHA token:", err);
}
};
return (
{error && Error: {error}
}
{token && Token ready!
}
);
};export default YourComponent;
`API Reference
$3
####
useGoogleRecaptcha(siteKey, action, options?)##### Parameters:
-
siteKey (string): Your Google reCAPTCHA v3 site key
- action (string): The action name for this reCAPTCHA execution
- options (ReCaptchaOptions, optional): Configuration options
- language (string, optional): Language code (default: "en")##### Returns:
-
token (string | null): The reCAPTCHA token
- error (string | null): Error message if something went wrong
- isLoading (boolean): Loading state
- refreshToken (function): Function to refresh the token
- executeRecaptcha (function): Function to manually execute reCAPTCHA$3
####
Props##### Required Props:
-
sitekey (string): Your Google reCAPTCHA site key##### Optional Props:
-
version ("v2" | "v3"): reCAPTCHA version (default: "v2")
- theme ("light" | "dark"): Visual theme (v2 only, default: "light")
- size ("compact" | "normal" | "invisible"): Widget size (default: "normal")
- type ("image" | "audio"): Challenge type (v2 only, default: "image")
- action (string): Action name for v3 (default: "submit")
- hl (string): Language code (default: "en")
- badge ("bottomright" | "bottomleft" | "inline"): Badge position for invisible (default: "bottomright")
- tabindex (number): Tab index for accessibility
- isolated (boolean): Isolated mode
- className (string): CSS class name
- style (React.CSSProperties): Inline styles##### Callback Props:
-
onChange ((token: string | null) => void): Called when token changes
- onExpired (() => void): Called when token expires
- onErrored ((error: Error) => void): Called when error occurs
- onLoad (() => void): Called when reCAPTCHA loads#### Component Ref Methods
When using
useRef:-
execute(): Promise - Execute reCAPTCHA and get token
- executeAsync(): Promise - Execute reCAPTCHA and get token (throws on failure)
- reset(): void - Reset the reCAPTCHA widget (v2 only)
- getResponse(): string | null - Get current response token (v2 only)TypeScript Support
This package includes full TypeScript support with exported interfaces:
`tsx
import { useGoogleRecaptcha, ReCaptchaResponse, ReCaptchaOptions } from "google-recaptcha-v3";
`Features
$3
- ✅ Clean and modern React hook
- ✅ Full TypeScript support
- ✅ Automatic script loading and cleanup
- ✅ Error handling
- ✅ Loading states
- ✅ Manual token refresh
- ✅ Language support
- ✅ Zero dependencies (peer dependency: React >=16.8.0)$3
- ✅ Supports both reCAPTCHA v2 and v3
- ✅ Full component-based implementation with ref support
- ✅ All reCAPTCHA v2 props (theme, size, type, etc.)
- ✅ Invisible reCAPTCHA support
- ✅ Comprehensive callback handling (onChange, onExpired, onErrored, onLoad)
- ✅ Imperative API through refs (execute, reset, getResponse)
- ✅ Flexible styling and positioning options
- ✅ Language and localization support
- ✅ Full TypeScript interfaces and type safetyBackend Integration
Verify reCAPTCHA token from React with NestJS Back-End:
$3
`bash
nest generate middleware recaptcha
`$3
`ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import axios from 'axios';@Injectable()
export class RecaptchaMiddleware implements NestMiddleware {
private key = 'YOUR_SITE_SECRET_KEY';
async use(req: Request, res: Response, next: NextFunction) {
const recaptchaToken = req.body.recaptchaToken;
if (!recaptchaToken) {
return res.status(400).json({ message: 'Missing recaptchaToken' });
}
try {
const response = await axios.post(
https://www.google.com/recaptcha/api/siteverify?secret=${this.key}&response=${recaptchaToken},
{},
); const { success } = response.data;
if (!success) {
return res.status(401).json({ message: 'Invalid recaptchaToken' });
}
next();
} catch (error) {
console.error('Recaptcha verification error:', error);
return res.status(500).json({ message: 'Internal Server Error' });
}
}
}
``Licensed under the MIT License