react-recaptcha-x
a React component for Google's reCAPTCHA v3 and v2 (checkbox) component.
- Small and Performant, only 10.8KB
- Available for both Javascript and Typescript projects
- Plug and play. No CSS or Script Tags required!
- It only inserts one recaptcha/api.js script tag
- Supports v3 and v2 in the same page, at the same time
- Free to use only v3 or v2 or both (no need to have both site keys, to use one version)
- Dynamically add or remove multiple instances of any version, at any time
- Does not block the page from loading or scripts from executing
- Supports custom props to the v2 component (className, id, data-x, etc.)
- Easy to use, single callback for Token/Expiration/Error handling
why I created another one of those reCAPTCHA wrappers
Using the Google reCAPTCHA v3, can be an issue if your human user,
gets a low score and is falsely identified as a bot. There is nothing the user can do to proceed, in that case.
This can be especially troublesome, if it happens during an important action, such as signing up.
Chances are, your human user will not be able to proceed and won't retry either.
Using this component, you can chose to fallback to the Google reCAPTCHA v2 checkbox, if the user scored low and was identified as a bot. This will allow the user to attempt to pass the checkbox and
perhaps, solve the more difficult image reCAPTCHA.
Most reCAPTCHA wrappers do not support both v3 and v2 at the same time properly. This component was created to solve that case, so that you would never lose a human user again.
usage
requirements
- React 16.6.0+ or 17.x
- reCAPTCHA v2 / v3 site key(s), which you can get from here
installation
$npm install react-recaptcha-x --save
simple javascript example
import {
EReCaptchaV2Size,
EReCaptchaV2Theme,
ReCaptchaProvider,
ReCaptchaV2,
ReCaptchaV3
} from 'react-recaptcha-x';
const v2Callback = (token) => {
if (typeof token === 'string') {
console.log('this is the token', token);
} else if (typeof token === 'boolean' && !token) {
console.log('token has expired, user must check the checkbox again');
} else if (token instanceof Error) {
console.log('error. please check your network connection');
}
};
const v3Callback = (token, refreshToken) => {
if (typeof token === 'string') {
console.log('this is the token', token);
if (typeof refreshToken === 'function') {
console.log('this is the refresh token function', refreshToken);
}
} else {
console.log('token retrieval in progress...');
}
};
...
<ReCaptchaProvider
siteKeyV2="your-reCAPTCHA-v2-site-key"
siteKeyV3="your-reCAPTCHA-v3-site-key"
langCode="en"
hideV3Badge={false}
>
Your Application
<ReCaptchaV2
callback={v2Callback}
theme={EReCaptchaV2Theme.Light}
size={EReCaptchaV2Size.Normal}
id="my-id"
data-test-id="my-test-id"
tabindex={0}
/>
<ReCaptchaV3 action="your-action" callback={v3Callback} />
</ReCaptchaProvider>
simple typescript example
import {
EReCaptchaV2Size,
EReCaptchaV2Theme,
ReCaptchaProvider,
ReCaptchaV2,
ReCaptchaV3,
TReCaptchaV2Callback,
TReCaptchaV3Callback
} from 'react-recaptcha-x';
const v2Callback: TReCaptchaV2Callback = (
token: string | false | Error
): void => {
if (typeof token === 'string') {
console.log('this is the token', token);
} else if (typeof token === 'boolean' && !token) {
console.log('token has expired, user must check the checkbox again');
} else if (token instanceof Error) {
console.log('error. please check your network connection');
}
};
const v3Callback: TReCaptchaV3Callback = (
token: string | void,
refreshToken: TReCaptchaV3RefreshToken | void
): void => {
if (typeof token === 'string') {
console.log('this is the token', token);
if (typeof refreshToken === 'function') {
console.log('this is the refresh token function', refreshToken);
}
} else {
console.log('token retrieval in progress...');
}
};
...
<ReCaptchaProvider
siteKeyV2="your-reCAPTCHA-v2-site-key"
siteKeyV3="your-reCAPTCHA-v3-site-key"
langCode="en"
hideV3Badge={false}
>
Your Application
<ReCaptchaV2
callback={v2Callback}
theme={EReCaptchaV2Theme.Light}
size={EReCaptchaV2Size.Normal}
id="my-id"
data-test-id="my-test-id"
tabindex={0}
/>
<ReCaptchaV3 action="your-action" callback={v3Callback} />
</ReCaptchaProvider>
ReCaptchaProvider (provider)
This is required only once, per application and should be placed as a wrapper for the whole application if possible. That way, you can insert and remove dynamically, at any place, the ReCaptchaV2 / ReCaptchaV3 components.
It is responsible for injecting the required Javascript Script Tag, CSS Style Tag when needed and passing down the site keys using react context.
ReCaptchaProvider Props
prop | type | default value | description |
---|
siteKeyV2 | string | empty | reCAPTCHA v2 site key, which you can get from here. Required, if you plan to use the v2 component |
siteKeyV3 | string | empty | reCAPTCHA v3 site key, which you can get from here. Required, if you plan to use the v3 component |
langCode | string | auto-detected | Optional. Lanuage Code of the Widget. If provided, the v2 checkbox component, will be rendered in that language. For a list of available values, see here |
hideV3Badge | boolean | false | Optional. If true, the v3 Badge will be hidden using css. Before using this, please make sure you have read the terms of hiding the badge here |
ReCaptchaV2 (checkbox, component)
It can be used to render the reCAPTCHA v2 checkbox Component. It must be a child of the ReCaptchaProvider (direct or indirect, at any level). It requires a siteKeyV2 to be defined in the ReCaptchaProvider.
The use of this component is not required but can be combined with the v3 reCAPTCHA Component (ie. as a failover in case of a false positive as a bot).
ReCaptchaV2 Props
prop | type | default value | description |
---|
callback | function(token:string or false or Error) | n/a | Required. When called with string (token), it means token retrieved. When called with false as an argument, it means the response expired and the user needs to re-verify. When called with Error, it means an error occurred and the widget cannot continue (usually network disconnection) |
theme | string | light | Optional. light or dark. The color theme of the widget |
size | string | normal | Optional. normal or compact. The size of the widget |
tabindex | number | 0 | Optional. The tabindex of the widget |
ReCaptchaV3 (invisible with score, component)
It can be used to handle the reCAPTCHA v3 invisible (score) Component. It must be a child of the ReCaptchaProvider (direct or indirect, at any level). It requires a siteKeyV3 to be defined in the ReCaptchaProvider.
The use of this component is not required but can be combined with the v2 reCAPTCHA Component (ie. first try v3 and if that fails, show v2 in case of a false positive as a bot).
ReCaptchaV3 Props
prop | type | default value | description |
---|
callback | function(token:string or void, refreshToken:fn or void) | n/a | Required. When called without arguments, it means requesting token in progress. When called with string (token) and function (refreshToken), it means token retrieved. The refreshToken function can be used at any time, to refresh the token by calling it |
action | string | n/a | Required. The name of the action to keep score and statistic about. It can only contain alphanumeric characters and slashes, and must not be user-specific |
working examples
examples prerequisites & setup
- nodejs 16.x LTS
$npm install
$npm run build
$npm link
(you might need to run with sudo, if you get permission denied)
typescript examples setup
$cd examples/typescript
$npm install
$npm link react-recaptcha-x
- create
.env
file with your reCAPTCHA key(s) using .env.example
as a template $npm start
- open browser to
http://localhost:9001
javascript examples setup
$cd examples/javascript
$npm install
$npm link react-recaptcha-x
- create
.env
file with your reCAPTCHA key(s) using .env.example
as a template $npm start
- open browser to
http://localhost:9001
other credits
This project uses and includes, a modified version, of the Type definitions for Google Recaptcha 2.0. Original version taken from here. Original Definitions by: Kristof Mattei http://kristofmattei.be Martin Costello https://martincostello.com/ Ruslan Arkhipau https://github.com/DethAriel Rafael Tavares https://github.com/rafaeltavares Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped