npm.io
1.1.3 • Published 6 months ago

google-recaptcha-v3

Licence
MIT
Version
1.1.3
Deps
0
Size
45 kB
Vulns
0
Weekly
0

React Google Recaptcha

A clean, modern React library for Google reCAPTCHA integration with both hooks and components supporting v2 and v3.

Install:

npm i google-recaptcha-v3

Import to React:

Hook (v3 only):
import { useGoogleRecaptcha } from "google-recaptcha-v3";
Component (supports both v2 and v3):
import { GoogleRecaptcha } from "google-recaptcha-v3";

Hook Usage (v3 only)

Basic Hook Usage
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 <div>Loading reCAPTCHA...</div>;
  }

  if (error) {
    return <div>Error: {error}</div>;
  }

  // You can use token to send request to API
  return (
    <div>
      {token && <p>reCAPTCHA token generated successfully!</p>}
    </div>
  );
};

export default YourComponent;

Component Usage

reCAPTCHA v2 - Basic Usage
import React, { useRef } from "react";
import { GoogleRecaptcha, GoogleRecaptchaRef } from "google-recaptcha-v3";

const YourComponent = () => {
  const recaptchaRef = useRef<GoogleRecaptchaRef>(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 (
    <div>
      <GoogleRecaptcha
        ref={recaptchaRef}
        sitekey={siteKey}
        onChange={handleChange}
        onExpired={() => console.log("reCAPTCHA expired")}
        onErrored={(error) => console.error("reCAPTCHA error:", error)}
      />
      <button onClick={handleSubmit}>Submit</button>
    </div>
  );
};

export default YourComponent;
reCAPTCHA v2 - Advanced Configuration
import React, { useRef } from "react";
import { GoogleRecaptcha, GoogleRecaptchaRef } from "google-recaptcha-v3";

const YourComponent = () => {
  const recaptchaRef = useRef<GoogleRecaptchaRef>(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 (
    <div>
      <GoogleRecaptcha
        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" }}
      />
      <div>
        <button onClick={handleSubmit}>Submit</button>
        <button onClick={handleReset}>Reset</button>
      </div>
    </div>
  );
};

export default YourComponent;
reCAPTCHA v3 - Component Usage
import React, { useRef } from "react";
import { GoogleRecaptcha, GoogleRecaptchaRef } from "google-recaptcha-v3";

const YourComponent = () => {
  const recaptchaRef = useRef<GoogleRecaptchaRef>(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 (
    <div>
      <GoogleRecaptcha
        ref={recaptchaRef}
        sitekey={siteKey}
        version="v3"
        action="submit"
        onLoad={() => console.log("reCAPTCHA v3 loaded")}
        onErrored={(error) => console.error("reCAPTCHA error:", error)}
      />
      <button onClick={handleSubmit}>Submit with v3</button>
    </div>
  );
};

export default YourComponent;
Invisible reCAPTCHA
import React, { useRef } from "react";
import { GoogleRecaptcha, GoogleRecaptchaRef } from "google-recaptcha-v3";

const YourComponent = () => {
  const recaptchaRef = useRef<GoogleRecaptchaRef>(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 (
    <div>
      <GoogleRecaptcha
        ref={recaptchaRef}
        sitekey={siteKey}
        size="invisible"
        badge="bottomright"
        onLoad={() => console.log("Invisible reCAPTCHA loaded")}
        onErrored={(error) => console.error("Error:", error)}
      />
      <button onClick={handleSubmit}>Submit (Invisible reCAPTCHA)</button>
    </div>
  );
};

export default YourComponent;
Advanced Hook Usage
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 (
    <div>
      <button onClick={handleSubmit} disabled={isLoading}>
        {isLoading ? "Loading..." : "Submit"}
      </button>
      <button onClick={refreshToken} disabled={isLoading}>
        Refresh Token
      </button>
      {error && <p style={{ color: "red" }}>Error: {error}</p>}
      {token && <p style={{ color: "green" }}>Token ready!</p>}
    </div>
  );
};

export default YourComponent;

API Reference

Hook API
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
Component API
<GoogleRecaptcha /> 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<GoogleRecaptchaRef>():

  • execute(): Promise<string | null> - 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:

import { useGoogleRecaptcha, ReCaptchaResponse, ReCaptchaOptions } from "google-recaptcha-v3";

Features

Hook Features (v3 only)
  • 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)
Component Features (v2 & v3)
  • 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 safety

Backend Integration

Verify reCAPTCHA token from React with NestJS Back-End:

Create RecaptchaMiddleware by CMD:

nest generate middleware recaptcha
Add Sample code to RecaptchaMiddleware:
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' });
    }
  }
}
Author

Copyright 2024 mia nguyen x thind9xdev

Licensed under the MIT License

Keywords