hCaptcha Integration
Protect your forms with hCaptcha's privacy-focused CAPTCHA service.
Overview
hCaptcha is a privacy-focused CAPTCHA service that provides strong spam protection while respecting user privacy. Unlike other CAPTCHA services, hCaptcha is designed to be GDPR/CCPA compliant and offers better performance with lower user friction.
✨ hCaptcha Benefits
- GDPR/CCPA compliant by design
- Lower user friction than traditional CAPTCHAs
- Better accessibility features
- No data tracking or behavioral analysis
- Enterprise-grade security and reliability
Setup
1. Get hCaptcha Keys
First, create an account at hCaptcha.com and register your domain to get your site key and secret key.
You'll receive:
- Site Key: Used in your HTML/JavaScript
- Secret Key: Used for server-side verification (keep secret!)
2. Configure in Kitoform Dashboard
In your Kitoform dashboard, go to your form settings and configure hCaptcha:
{
"captchaProvider": "hcaptcha",
"hcaptchaSiteKey": "your-site-key-here",
"hcaptchaSecretKey": "your-secret-key-here",
"securityLevel": "standard"
}HTML Implementation
Basic Implementation
Add the hCaptcha widget to your HTML form:
<!DOCTYPE html>
<html>
<head>
<title>Contact Form with hCaptcha</title>
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
</head>
<body>
<form action="https://connect.kitoform.com/f/YOUR_ENDPOINT_ID" method="POST">
<div>
<label for="name">Name:</label>
<input type="text" name="name" id="name" required>
</div>
<div>
<label for="email">Email:</label>
<input type="email" name="email" id="email" required>
</div>
<div>
<label for="message">Message:</label>
<textarea name="message" id="message" required></textarea>
</div>
<!-- hCaptcha widget -->
<div class="h-captcha" data-sitekey="YOUR_SITE_KEY"></div>
<button type="submit">Send Message</button>
</form>
</body>
</html>With JavaScript Callbacks
Handle success, error, and expiration events:
<script>
// Callback when hCaptcha is solved
function onHcaptchaSuccess(token) {
console.log('hCaptcha solved, token:', token);
// Enable submit button
document.getElementById('submit-btn').disabled = false;
// Optional: Submit form automatically
// document.getElementById('contact-form').submit();
}
// Callback when hCaptcha expires
function onHcaptchaExpired() {
console.log('hCaptcha token expired');
// Disable submit button
document.getElementById('submit-btn').disabled = true;
}
// Callback when hCaptcha encounters an error
function onHcaptchaError(error) {
console.error('hCaptcha error:', error);
// Disable submit button
document.getElementById('submit-btn').disabled = true;
}
</script>
<form id="contact-form" action="https://connect.kitoform.com/f/YOUR_ENDPOINT_ID" method="POST">
<!-- Form fields here -->
<div class="h-captcha"
data-sitekey="YOUR_SITE_KEY"
data-callback="onHcaptchaSuccess"
data-expired-callback="onHcaptchaExpired"
data-error-callback="onHcaptchaError">
</div>
<button type="submit" id="submit-btn" disabled>Send Message</button>
</form>React Implementation
Installation
Install the React hCaptcha component:
npm install @hcaptcha/react-hcaptchaBasic React Component
import React, { useState, useRef } from 'react';
import HCaptcha from '@hcaptcha/react-hcaptcha';
function ContactForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
message: ''
});
const [captchaToken, setCaptchaToken] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const captchaRef = useRef(null);
const handleInputChange = (e) => {
setFormData({
...formData,
[e.target.name]: e.target.value
});
};
const handleCaptchaVerify = (token) => {
console.log('hCaptcha verified:', token);
setCaptchaToken(token);
};
const handleCaptchaExpire = () => {
console.log('hCaptcha expired');
setCaptchaToken('');
};
const handleSubmit = async (e) => {
e.preventDefault();
if (!captchaToken) {
alert('Please complete the CAPTCHA');
return;
}
setIsSubmitting(true);
try {
const formDataWithCaptcha = new FormData();
Object.keys(formData).forEach(key => {
formDataWithCaptcha.append(key, formData[key]);
});
formDataWithCaptcha.append('h-captcha-response', captchaToken);
const response = await fetch('https://connect.kitoform.com/f/YOUR_ENDPOINT_ID', {
method: 'POST',
body: formDataWithCaptcha,
});
if (response.ok) {
alert('Form submitted successfully!');
// Reset form
setFormData({ name: '', email: '', message: '' });
setCaptchaToken('');
captchaRef.current?.resetCaptcha();
} else {
alert('Form submission failed. Please try again.');
}
} catch (error) {
console.error('Submission error:', error);
alert('Form submission failed. Please try again.');
} finally {
setIsSubmitting(false);
}
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="name">Name:</label>
<input
type="text"
name="name"
id="name"
value={formData.name}
onChange={handleInputChange}
required
/>
</div>
<div>
<label htmlFor="email">Email:</label>
<input
type="email"
name="email"
id="email"
value={formData.email}
onChange={handleInputChange}
required
/>
</div>
<div>
<label htmlFor="message">Message:</label>
<textarea
name="message"
id="message"
value={formData.message}
onChange={handleInputChange}
required
/>
</div>
<HCaptcha
ref={captchaRef}
sitekey="YOUR_SITE_KEY"
onVerify={handleCaptchaVerify}
onExpire={handleCaptchaExpire}
/>
<button
type="submit"
disabled={!captchaToken || isSubmitting}
>
{isSubmitting ? 'Sending...' : 'Send Message'}
</button>
</form>
);
}
export default ContactForm;Configuration Options
Widget Customization
Customize the hCaptcha widget appearance and behavior:
<!-- Size variations -->
<div class="h-captcha"
data-sitekey="YOUR_SITE_KEY"
data-size="normal"> <!-- normal, compact, invisible -->
</div>
<!-- Theme options -->
<div class="h-captcha"
data-sitekey="YOUR_SITE_KEY"
data-theme="light"> <!-- light, dark -->
</div>
<!-- Language setting -->
<div class="h-captcha"
data-sitekey="YOUR_SITE_KEY"
data-hl="es"> <!-- Language code (es, en, fr, etc.) -->
</div>
<!-- Tab index for accessibility -->
<div class="h-captcha"
data-sitekey="YOUR_SITE_KEY"
data-tabindex="0">
</div>
<!-- Complete customization example -->
<div class="h-captcha"
data-sitekey="YOUR_SITE_KEY"
data-size="compact"
data-theme="dark"
data-hl="en"
data-tabindex="0"
data-callback="onSuccess"
data-expired-callback="onExpired"
data-error-callback="onError">
</div>React Component Props
<HCaptcha
sitekey="YOUR_SITE_KEY"
size="normal" // normal, compact, invisible
theme="light" // light, dark
tabindex={0} // Tab index for accessibility
languageOverride="en" // Language override
reCaptchaCompat={false} // reCAPTCHA compatibility mode
onVerify={handleVerify} // Called when solved
onExpire={handleExpire} // Called when expired
onError={handleError} // Called on error
onLoad={handleLoad} // Called when loaded
/>Security Levels
Configure different security levels in your Kitoform dashboard to balance security and user experience.
🟢 Standard Security
Balanced security with good user experience. Recommended for most use cases.
- • Standard hCaptcha difficulty
- • Automatic retry on failure
- • Good for contact forms and newsletters
🟡 Strict Security
Higher security with additional validation. Use for important forms.
- • Enhanced difficulty settings
- • Additional server-side validation
- • Good for registrations and lead forms
🔴 Paranoid Security
Maximum security with additional checks. Use for critical forms only.
- • Highest difficulty settings
- • Rate limiting and IP checks
- • Additional honeypot fields
- • Good for payment and sensitive forms
Troubleshooting
Common Issues
hCaptcha widget not loading
Make sure the hCaptcha script is loaded before rendering the widget:
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>Invalid site key error
Verify your site key matches your domain configuration in the hCaptcha dashboard.
Form submission failing
Ensure the hCaptcha response field is included in your form data:
formData.append('h-captcha-response', captchaToken);Testing
hCaptcha provides test keys for development:
Development keys (always pass):
Site Key: 10000000-ffff-ffff-ffff-000000000001
Secret Key: 0x0000000000000000000000000000000000000000
⚠️ These keys always pass validation - use only for testing!
Best Practices
✅ Do's
- Use test keys during development and staging
- Handle expired tokens gracefully with auto-refresh
- Provide clear feedback to users when CAPTCHA is required
- Set appropriate tab indexes for keyboard navigation
❌ Don'ts
- Don't use production keys in client-side code repositories
- Don't submit forms without validating CAPTCHA completion
- Don't rely solely on client-side CAPTCHA validation