What is Invisible reCAPTCHA?
Invisible reCAPTCHA validates users transparently without requiring them to click a checkbox. It only shows a challenge when suspicious activity is detected, providing a seamless user experience.
Basic Configuration
To use invisible reCAPTCHA, set the size prop to "invisible":
import ReCAPTCHA from "react-google-recaptcha" ;
< ReCAPTCHA
size = "invisible"
sitekey = "Your client site key"
onChange = { onChange }
/>
With invisible reCAPTCHA, you must manually call the execute() method to trigger verification. The captcha won’t run automatically.
Using execute() Method
The execute() method programmatically invokes the reCAPTCHA challenge. You typically call this on form submission.
import React from "react" ;
import ReCAPTCHA from "react-google-recaptcha" ;
import ReactDOM from "react-dom" ;
const recaptchaRef = React . createRef ();
function onChange ( token ) {
console . log ( "Captcha token:" , token );
// Send token to your backend for verification
}
ReactDOM . render (
< form onSubmit = { () => { recaptchaRef . current . execute (); } } >
< input type = "text" name = "email" placeholder = "Email" />
< input type = "password" name = "password" placeholder = "Password" />
< ReCAPTCHA
ref = { recaptchaRef }
size = "invisible"
sitekey = "Your client site key"
onChange = { onChange }
/>
< button type = "submit" > Submit </ button >
</ form > ,
document . body
);
How It Works
User submits the form
execute() is called, triggering reCAPTCHA verification
If verification passes, onChange callback is invoked with the token
Your application can then proceed with form submission
Using executeAsync() with Promises
For a more modern, promise-based approach, use executeAsync(). This method returns a promise that resolves to the token.
import React from "react" ;
import ReCAPTCHA from "react-google-recaptcha" ;
import ReactDOM from "react-dom" ;
const ReCAPTCHAForm = ( props ) => {
const recaptchaRef = React . useRef ();
const onSubmitWithReCAPTCHA = async () => {
const token = await recaptchaRef . current . executeAsync ();
// apply to form data
console . log ( "Token:" , token );
}
return (
< form onSubmit = { onSubmitWithReCAPTCHA } >
< input type = "text" placeholder = "Username" />
< ReCAPTCHA
ref = { recaptchaRef }
size = "invisible"
sitekey = "Your client site key"
/>
< button type = "submit" > Submit </ button >
</ form >
)
}
ReactDOM . render (
< ReCAPTCHAForm /> ,
document . body
);
With executeAsync(), you don’t need to provide an onChange callback since the token is returned via the promise.
Complete Example with Error Handling
import React from "react" ;
import ReCAPTCHA from "react-google-recaptcha" ;
function LoginForm () {
const recaptchaRef = React . useRef ();
const [ loading , setLoading ] = React . useState ( false );
const [ error , setError ] = React . useState ( null );
const handleSubmit = async ( e ) => {
e . preventDefault ();
setLoading ( true );
setError ( null );
try {
// Get the reCAPTCHA token
const token = await recaptchaRef . current . executeAsync ();
// Submit to your API
const response = await fetch ( '/api/login' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
email: e . target . email . value ,
password: e . target . password . value ,
recaptchaToken: token
})
});
if ( response . ok ) {
// Handle successful login
console . log ( "Login successful" );
} else {
setError ( "Login failed" );
}
} catch ( err ) {
setError ( "An error occurred: " + err . message );
} finally {
setLoading ( false );
// Reset reCAPTCHA for next submission
recaptchaRef . current . reset ();
}
};
return (
< form onSubmit = { handleSubmit } >
< input type = "email" name = "email" required />
< input type = "password" name = "password" required />
< ReCAPTCHA
ref = { recaptchaRef }
size = "invisible"
sitekey = "Your client site key"
/>
{ error && < div className = "error" > { error } </ div > }
< button type = "submit" disabled = { loading } >
{ loading ? "Submitting..." : "Login" }
</ button >
</ form >
);
}
Badge Positioning
The invisible reCAPTCHA displays a small badge on your page. You can control its position with the badge prop:
< ReCAPTCHA
size = "invisible"
sitekey = "Your client site key"
badge = "bottomright"
/>
Available Positions
bottomright
bottomleft
inline
< ReCAPTCHA
size = "invisible"
sitekey = "Your client site key"
badge = "bottomright"
/>
Default position - fixed to the bottom right corner of the page. < ReCAPTCHA
size = "invisible"
sitekey = "Your client site key"
badge = "bottomleft"
/>
Fixed to the bottom left corner of the page. < ReCAPTCHA
size = "invisible"
sitekey = "Your client site key"
badge = "inline"
/>
Positioned inline where the component is placed in your layout.
The badge prop only works with invisible reCAPTCHA (size="invisible"). It has no effect on normal or compact sizes.
Hiding the Badge
You can hide the reCAPTCHA badge, but there are important legal requirements. See the Hiding the Badge guide for details.
Comparison: execute() vs executeAsync()
execute() with onChange callback
Use when:
You prefer callback-based patterns
You need to handle the token in a separate function
You’re using class components
function onChange ( token ) {
// Handle token here
}
< ReCAPTCHA
ref = { recaptchaRef }
size = "invisible"
sitekey = "key"
onChange = { onChange }
/>
// Later, in your submit handler:
recaptchaRef . current . execute ();
executeAsync() with promises
Use when:
You prefer async/await syntax
You want to handle the token inline
You’re using functional components
const handleSubmit = async () => {
const token = await recaptchaRef . current . executeAsync ();
// Use token immediately
}
< ReCAPTCHA
ref = { recaptchaRef }
size = "invisible"
sitekey = "key"
/>
Best Practices
Reset after submission : Always call reset() after processing the form to allow users to resubmit if needed.
One-time use tokens : Each reCAPTCHA token can only be verified once on your backend. Generate a new token for each submission.
Token expiration : Tokens expire after a few minutes. If a user takes too long to submit, you may need to generate a new token.