reCAPTCHA Setup for Website Form Protection
Google reCAPTCHA protects forms from automated bots: spam account registrations, password brute force, mass form submissions. Three versions with different UX trade-offs exist.
reCAPTCHA Versions
v2 Checkbox — classic "I'm not a robot". User checks box, sometimes passes visual test.
v2 Invisible — requires no interaction, analyzes behavior in background. Shows challenge on suspicion.
v3 — completely invisible, returns score 0.0 to 1.0. Developer decides what to do on low score.
Registration and Keys
Get keys from google.com/recaptcha/admin. Need site_key (public, for frontend) and secret_key (private, server only).
reCAPTCHA v3 Integration
Frontend:
<script src="https://www.google.com/recaptcha/api.js?render=SITE_KEY"></script>
<script>
grecaptcha.ready(function() {
document.getElementById('submit').addEventListener('click', async function(e) {
e.preventDefault();
const token = await grecaptcha.execute('SITE_KEY', {action: 'contact_form'});
document.getElementById('recaptcha-token').value = token;
document.getElementById('myForm').submit();
});
});
</script>
<input type="hidden" id="recaptcha-token" name="recaptcha_token">
Server verification (PHP):
$token = $request->input('recaptcha_token');
$secret = config('services.recaptcha.secret');
$response = Http::post('https://www.google.com/recaptcha/api/siteverify', [
'secret' => $secret,
'response' => $token,
'remoteip' => $request->ip(),
]);
$data = $response->json();
if (!$data['success'] || $data['score'] < 0.5 || $data['action'] !== 'contact_form') {
abort(422, 'reCAPTCHA verification failed');
}
Score Strategy for reCAPTCHA v3
| Score | Interpretation | Action |
|---|---|---|
| 0.9–1.0 | Obviously human | Pass |
| 0.5–0.9 | Probably human | Pass |
| 0.3–0.5 | Undefined | Additional check / email confirmation |
| 0.0–0.3 | Probably bot | Block or show v2 Checkbox |
React Integration
import ReCAPTCHA from 'react-google-recaptcha';
function ContactForm() {
const recaptchaRef = useRef(null);
const handleSubmit = async (e) => {
e.preventDefault();
const token = await recaptchaRef.current.executeAsync();
recaptchaRef.current.reset();
// Send token with form data
await submitForm({ ...formData, recaptcha_token: token });
};
return (
<form onSubmit={handleSubmit}>
{/* form fields */}
<ReCAPTCHA
ref={recaptchaRef}
sitekey={process.env.REACT_APP_RECAPTCHA_SITE_KEY}
size="invisible"
/>
<button type="submit">Submit</button>
</form>
);
}
Implementation Timeline
Basic reCAPTCHA v3 integration — 4–8 hours including server verification.







