Skip to main content
The withGoogleReCaptcha is a higher-order component (HOC) that injects reCAPTCHA functionality into your React components. This is primarily useful for class components where React Hooks cannot be used.
For functional components, it’s recommended to use the useGoogleReCaptcha hook instead, which provides a cleaner API and better TypeScript support.

Installation

npm install react-google-recaptcha-v3

Basic Usage

import { Component } from 'react';
import {
  GoogleReCaptchaProvider,
  withGoogleReCaptcha,
  IWithGoogleReCaptchaProps
} from 'react-google-recaptcha-v3';

class MyComponent extends Component<IWithGoogleReCaptchaProps> {
  handleVerify = async () => {
    const { executeRecaptcha } = this.props.googleReCaptchaProps;

    if (!executeRecaptcha) {
      console.log('Execute recaptcha not yet available');
      return;
    }

    const token = await executeRecaptcha('submit');
    console.log('Token:', token);
  };

  render() {
    return <button onClick={this.handleVerify}>Verify</button>;
  }
}

const WrappedComponent = withGoogleReCaptcha(MyComponent);

function App() {
  return (
    <GoogleReCaptchaProvider reCaptchaKey="YOUR_RECAPTCHA_SITE_KEY">
      <WrappedComponent />
    </GoogleReCaptchaProvider>
  );
}

Injected Props

The HOC injects a googleReCaptchaProps prop into your component with the following properties:
googleReCaptchaProps
IGoogleReCaptchaConsumerProps
An object containing reCAPTCHA functionality.
googleReCaptchaProps.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
googleReCaptchaProps.container
string | HTMLElement | undefined
Reference to the custom container element if specified in the provider.

Examples

Class Component with Form Submission

import { Component, FormEvent } from 'react';
import { withGoogleReCaptcha, IWithGoogleReCaptchaProps } from 'react-google-recaptcha-v3';

interface State {
  email: string;
  password: string;
  loading: boolean;
}

class LoginForm extends Component<IWithGoogleReCaptchaProps, State> {
  state: State = {
    email: '',
    password: '',
    loading: false
  };

  handleSubmit = async (e: FormEvent) => {
    e.preventDefault();
    
    const { executeRecaptcha } = this.props.googleReCaptchaProps;

    if (!executeRecaptcha) {
      console.log('Execute recaptcha not yet available');
      return;
    }

    this.setState({ loading: true });

    try {
      const token = await executeRecaptcha('login');
      
      const response = await fetch('/api/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          email: this.state.email,
          password: this.state.password,
          recaptchaToken: token
        })
      });

      const data = await response.json();
      console.log('Login successful:', data);
    } catch (error) {
      console.error('Login failed:', error);
    } finally {
      this.setState({ loading: false });
    }
  };

  render() {
    const { email, password, loading } = this.state;
    const { executeRecaptcha } = this.props.googleReCaptchaProps;

    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type="email"
          value={email}
          onChange={(e) => this.setState({ email: e.target.value })}
          placeholder="Email"
        />
        <input
          type="password"
          value={password}
          onChange={(e) => this.setState({ password: e.target.value })}
          placeholder="Password"
        />
        <button type="submit" disabled={loading || !executeRecaptcha}>
          {loading ? 'Logging in...' : 'Login'}
        </button>
      </form>
    );
  }
}

export default withGoogleReCaptcha(LoginForm);

Button Click Verification

import { Component } from 'react';
import { withGoogleReCaptcha, IWithGoogleReCaptchaProps } from 'react-google-recaptcha-v3';

interface State {
  token: string;
  isVerifying: boolean;
}

class VerifyButton extends Component<IWithGoogleReCaptchaProps, State> {
  state: State = {
    token: '',
    isVerifying: false
  };

  handleClick = async () => {
    const { executeRecaptcha } = this.props.googleReCaptchaProps;

    if (!executeRecaptcha) {
      console.log('Execute recaptcha not yet available');
      return;
    }

    this.setState({ isVerifying: true });

    try {
      const token = await executeRecaptcha('verify_action');
      this.setState({ token });
      console.log('Verification successful');
    } catch (error) {
      console.error('Verification failed:', error);
    } finally {
      this.setState({ isVerifying: false });
    }
  };

  render() {
    const { token, isVerifying } = this.state;
    const { executeRecaptcha } = this.props.googleReCaptchaProps;

    return (
      <div>
        <button onClick={this.handleClick} disabled={isVerifying || !executeRecaptcha}>
          {isVerifying ? 'Verifying...' : 'Verify'}
        </button>
        {token && <p>Token: {token.substring(0, 20)}...</p>}
      </div>
    );
  }
}

export default withGoogleReCaptcha(VerifyButton);

Complete Example from Source

Here’s the actual example from the library’s source code:
// From: example/with-google-recaptcha-example.tsx:1
import React, { Component } from 'react';
import {
  IWithGoogleReCaptchaProps,
  withGoogleReCaptcha
} from 'react-google-recaptcha-v3';

class ReCaptchaComponent extends Component<{}, { token?: string }> {
  constructor(props: {}) {
    super(props);
    this.state = { token: undefined };
  }

  handleVerifyRecaptcha = async () => {
    const { executeRecaptcha } = (this.props as IWithGoogleReCaptchaProps)
      .googleReCaptchaProps;

    if (!executeRecaptcha) {
      console.log('Recaptcha has not been loaded');
      return;
    }

    const token = await executeRecaptcha('homepage');
    this.setState({ token });
  };

  render() {
    const { token } = this.state;
    return (
      <div>
        <h3>With Google Recaptcha HOC Example</h3>
        <button onClick={this.handleVerifyRecaptcha}>Verify Recaptcha</button>
        <p>Token: {token}</p>
      </div>
    );
  }
}

export const WithGoogleRecaptchaExample =
  withGoogleReCaptcha(ReCaptchaComponent);

With Additional Props

import { Component } from 'react';
import { withGoogleReCaptcha, IWithGoogleReCaptchaProps } from 'react-google-recaptcha-v3';

// Define your own props
interface OwnProps {
  title: string;
  onSuccess: (token: string) => void;
}

// Combine with HOC props
type Props = OwnProps & IWithGoogleReCaptchaProps;

class CustomComponent extends Component<Props> {
  handleVerify = async () => {
    const { executeRecaptcha } = this.props.googleReCaptchaProps;
    const { onSuccess } = this.props;

    if (!executeRecaptcha) return;

    const token = await executeRecaptcha('custom_action');
    onSuccess(token);
  };

  render() {
    const { title } = this.props;
    
    return (
      <div>
        <h2>{title}</h2>
        <button onClick={this.handleVerify}>Verify</button>
      </div>
    );
  }
}

export default withGoogleReCaptcha(CustomComponent);

// Usage:
// <CustomComponent title="My Form" onSuccess={(token) => console.log(token)} />

TypeScript Types

export interface IWithGoogleReCaptchaProps {
  googleReCaptchaProps: IGoogleReCaptchaConsumerProps;
}

export interface IGoogleReCaptchaConsumerProps {
  executeRecaptcha?: (action?: string) => Promise<string>;
  container?: string | HTMLElement;
}

export const withGoogleReCaptcha: <OwnProps>(
  Component: ComponentType<OwnProps & Partial<IWithGoogleReCaptchaProps>>
) => ComponentType<OwnProps & Partial<IWithGoogleReCaptchaProps>>;

How It Works

The withGoogleReCaptcha HOC wraps your component with a GoogleReCaptchaConsumer (from React Context) and injects the context values as the googleReCaptchaProps prop. From the source code:
// From: src/with-google-recaptcha.tsx:14
export const withGoogleReCaptcha = function <OwnProps>(
  Component: ComponentType<OwnProps & Partial<IWithGoogleReCaptchaProps>>
): ComponentType<OwnProps & Partial<IWithGoogleReCaptchaProps>> {
  const WithGoogleReCaptchaComponent = (
    props: OwnProps & Partial<IWithGoogleReCaptchaProps>
  ) => (
    <GoogleReCaptchaConsumer>
      {googleReCaptchaValues => (
        <Component {...props} googleReCaptchaProps={googleReCaptchaValues} />
      )}
    </GoogleReCaptchaConsumer>
  );

  WithGoogleReCaptchaComponent.displayName = `withGoogleReCaptcha(${
    Component.displayName || Component.name || 'Component'
  })`;

  hoistNonReactStatics(WithGoogleReCaptchaComponent, Component);

  return WithGoogleReCaptchaComponent;
};

Features

Display Name

The HOC automatically sets a helpful displayName for debugging:
class MyComponent extends Component { /* ... */ }
const Wrapped = withGoogleReCaptcha(MyComponent);
// Wrapped.displayName === 'withGoogleReCaptcha(MyComponent)'

Static Methods Hoisting

The HOC uses hoist-non-react-statics to automatically copy static methods from your component to the wrapped component:
class MyComponent extends Component {
  static myStaticMethod() {
    return 'hello';
  }
}

const Wrapped = withGoogleReCaptcha(MyComponent);
Wrapped.myStaticMethod(); // Works!

Best Practices

Prefer Hooks: If you’re using functional components, use the useGoogleReCaptcha hook instead for a cleaner API.
Check Availability: Always check if executeRecaptcha is available before calling it:
if (!executeRecaptcha) {
  console.log('Not ready yet');
  return;
}
Disable UI Elements: Disable buttons or forms while executeRecaptcha is undefined:
<button disabled={!this.props.googleReCaptchaProps.executeRecaptcha}>
  Submit
</button>
Server-Side Verification: Always verify the token on your backend. Never trust client-side validation alone.
Type Safety: Use IWithGoogleReCaptchaProps type for proper TypeScript support:
class MyComponent extends Component<IWithGoogleReCaptchaProps> {
  // TypeScript knows about googleReCaptchaProps
}

Common Patterns

Accessing Props in TypeScript

// Correct way to access the props
const { executeRecaptcha } = this.props.googleReCaptchaProps;

// Or with destructuring in method
handleVerify = async () => {
  const { googleReCaptchaProps: { executeRecaptcha } } = this.props;
  // ...
};

Combining with Other HOCs

import { connect } from 'react-redux';
import { withGoogleReCaptcha } from 'react-google-recaptcha-v3';

class MyComponent extends Component { /* ... */ }

// Compose multiple HOCs
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(withGoogleReCaptcha(MyComponent));

Migration to Hooks

If you’re refactoring from class components to functional components: Before (with HOC):
class MyComponent extends Component<IWithGoogleReCaptchaProps> {
  handleClick = async () => {
    const { executeRecaptcha } = this.props.googleReCaptchaProps;
    if (!executeRecaptcha) return;
    const token = await executeRecaptcha('action');
  };
  
  render() {
    return <button onClick={this.handleClick}>Click</button>;
  }
}

export default withGoogleReCaptcha(MyComponent);
After (with Hook):
import { useCallback } from 'react';
import { useGoogleReCaptcha } from 'react-google-recaptcha-v3';

function MyComponent() {
  const { executeRecaptcha } = useGoogleReCaptcha();
  
  const handleClick = useCallback(async () => {
    if (!executeRecaptcha) return;
    const token = await executeRecaptcha('action');
  }, [executeRecaptcha]);
  
  return <button onClick={handleClick}>Click</button>;
}

export default MyComponent;

When to Use This HOC

Use withGoogleReCaptcha when:
  • You’re working with class components
  • You can’t use React Hooks
  • You’re maintaining legacy code
  • You need to compose with other HOCs
Use useGoogleReCaptcha hook when:
  • You’re using functional components (recommended)
  • You want a cleaner, more modern API
  • You prefer hooks over HOCs

See Also

Build docs developers (and LLMs) love