Widget Integration Guide
Last Updated: November 30, 2025
Integration Method: JavaScript Widget (Embeddable)
Add VerifyHuman verification to any website with our embeddable JavaScript widgets. No backend required - just copy, paste, and go live.
📋 Table of Contents
- Overview
- Widget Types
- Quick Start
- Configuration Options
- Callbacks & Events
- Styling & Customization
- Advanced Integration
- Troubleshooting
Overview
VerifyHuman offers embeddable widgets for all four verification products:
| Widget | Purpose | Best For |
|---|---|---|
| VerifyHuman Widget | Liveness & bot detection | Signup forms, comment sections |
| VerifyAge Widget | Age verification | Age-restricted content, e-commerce |
| VerifyIdentity Widget | KYC verification | Account verification, marketplaces |
| VerifyCompliance Widget | KYC+ with compliance | Financial apps, crypto exchanges |
Benefits:
- ✅ No backend integration required
- ✅ Camera access & image capture built-in
- ✅ Mobile-responsive design
- ✅ Customizable branding
- ✅ Real-time verification feedback
- ✅ Secure credit consumption
Widget Types
1. VerifyHuman Widget
Basic liveness detection and bot prevention widget.
<script src="https://app.verifyhuman.io/widget.js"></script>
<div id="verifyhuman-widget"></div>
<script>
VerifyHuman.init({
apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
onSuccess: function(result) {
console.log('Verified!', result);
},
onFailure: function(error) {
console.error('Failed:', error);
}
});
</script>
2. VerifyAge Widget
Age verification with two-step flow (selfie → ID if needed).
<script src="https://app.verifyhuman.io/widget-age.js"></script>
<div id="verifyage-widget"></div>
<script>
VerifyAge.init({
apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
useCase: 'alcohol',
minAge: 21,
onSuccess: function(result) {
console.log('Age verified!', result);
},
onFailure: function(error) {
console.error('Age verification failed:', error);
}
});
</script>
3. VerifyIdentity Widget
KYC widget with selfie + ID capture.
<script src="https://app.verifyhuman.io/widget-identity.js"></script>
<div id="verifyidentity-widget"></div>
<script>
VerifyIdentity.init({
apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
requireIdBack: false, // Optional ID back image
onSuccess: function(result) {
console.log('Identity verified!', result);
},
onFailure: function(error) {
console.error('Verification failed:', error);
}
});
</script>
4. VerifyCompliance Widget
KYC+ widget with integrated compliance screening.
<script src="https://app.verifyhuman.io/widget-compliance.js"></script>
<div id="verifycompliance-widget"></div>
<script>
VerifyCompliance.init({
apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
requireIdBack: false,
onSuccess: function(result) {
if (result.compliance_screening.total_hits === 0) {
console.log('Cleared!', result);
} else {
console.warn('Compliance hits detected:', result.compliance_screening);
}
},
onFailure: function(error) {
console.error('Verification failed:', error);
}
});
</script>
Quick Start
Step 1: Include Widget Script
Add the widget script to your HTML <head> or before the closing </body> tag:
<!-- For VerifyHuman -->
<script src="https://app.verifyhuman.io/widget.js"></script>
<!-- For VerifyAge -->
<script src="https://app.verifyhuman.io/widget-age.js"></script>
<!-- For VerifyIdentity -->
<script src="https://app.verifyhuman.io/widget-identity.js"></script>
<!-- For VerifyCompliance -->
<script src="https://app.verifyhuman.io/widget-compliance.js"></script>
Step 2: Add Widget Container
Place the widget container where you want verification to appear:
<div id="verifyhuman-widget"></div>
Step 3: Initialize Widget
Configure and initialize the widget:
<script>
VerifyHuman.init({
apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
buttonText: 'Verify You\'re Human',
onSuccess: function(result) {
// User verified successfully
document.getElementById('signup-button').disabled = false;
},
onFailure: function(error) {
// Verification failed
alert('Verification failed: ' + error.message);
}
});
</script>
Configuration Options
VerifyHuman Widget Options
VerifyHuman.init({
// Required
apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
// Optional
containerId: 'verifyhuman-widget', // Default: 'verifyhuman-widget'
buttonText: 'Verify You\'re Human', // Button label
buttonStyle: 'primary', // 'primary' | 'secondary' | 'minimal'
autoOpen: false, // Auto-open camera on page load
showConfidence: false, // Show confidence score to user
language: 'en', // 'en' | 'es' | 'fr' | 'de'
// Callbacks
onSuccess: function(result) { },
onFailure: function(error) { },
onClose: function() { },
onReady: function() { }
});
VerifyAge Widget Options
VerifyAge.init({
// Required
apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
useCase: 'alcohol', // 'adult' | 'alcohol' | 'tobacco' | 'cannabis' | 'gambling' | 'custom'
minAge: 21,
// Optional
containerId: 'verifyage-widget',
buttonText: 'Verify Your Age',
buttonStyle: 'primary',
stateCode: 'CA', // For US state-specific compliance
multiStep: true, // Enable multi-step flow (DOB → Selfie → ID)
allowIdSkip: false, // Allow users to skip ID verification
showAgeEstimate: false, // Show estimated age to user
language: 'en',
// Callbacks
onSuccess: function(result) { },
onFailure: function(error) { },
onStepComplete: function(step, data) { },
onClose: function() { }
});
VerifyIdentity Widget Options
VerifyIdentity.init({
// Required
apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
// Optional
containerId: 'verifyidentity-widget',
buttonText: 'Verify Your Identity',
buttonStyle: 'primary',
requireIdBack: false, // Require ID back image
collectUserData: false, // Collect name, DOB, address fields
validateData: false, // Validate user input against OCR data
showExtractedData: false, // Show extracted data to user
language: 'en',
// Callbacks
onSuccess: function(result) { },
onFailure: function(error) { },
onDataExtracted: function(data) { },
onClose: function() { }
});
VerifyCompliance Widget Options
VerifyCompliance.init({
// Required
apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
// Optional
containerId: 'verifycompliance-widget',
buttonText: 'Verify Identity & Compliance',
buttonStyle: 'primary',
requireIdBack: false,
collectGender: true, // Collect gender for better screening
autoGenerateReport: false, // Auto-generate PDF report if hits detected
reportPassword: 'secure123', // Password for encrypted PDF
language: 'en',
// Callbacks
onSuccess: function(result) { },
onFailure: function(error) { },
onComplianceHit: function(screening) { },
onReportGenerated: function(report) { },
onClose: function() { }
});
Callbacks & Events
onSuccess Callback
Called when verification succeeds.
onSuccess: function(result) {
console.log('Verification ID:', result.verification_id);
console.log('Status:', result.status);
console.log('Confidence:', result.confidence);
// For VerifyAge
if (result.verified) {
console.log('Age verified:', result.estimated_age);
}
// For VerifyIdentity/Compliance
if (result.document_data) {
console.log('Name:', result.document_data.name);
console.log('DOB:', result.document_data.date_of_birth);
}
// For VerifyCompliance
if (result.compliance_screening) {
console.log('Compliance status:', result.compliance_screening.status);
console.log('Hits:', result.compliance_screening.total_hits);
}
}
onFailure Callback
Called when verification fails.
onFailure: function(error) {
console.error('Error code:', error.code);
console.error('Error message:', error.message);
// Handle specific errors
switch(error.code) {
case 'INSUFFICIENT_CREDITS':
alert('Out of credits. Please upgrade your plan.');
break;
case 'INVALID_API_KEY':
console.error('API key is invalid or inactive');
break;
case 'CAMERA_DENIED':
alert('Please allow camera access to verify.');
break;
case 'LOW_CONFIDENCE':
alert('Verification failed. Please try again with better lighting.');
break;
default:
alert('Verification failed: ' + error.message);
}
}
onStepComplete Callback (VerifyAge only)
Called when each step of multi-step verification completes.
onStepComplete: function(step, data) {
console.log('Completed step:', step); // 'dob' | 'selfie' | 'id'
if (step === 'dob' && data.underage) {
// User is underage, verification stopped
console.log('User is underage:', data.user_age);
}
if (step === 'selfie' && data.requires_id) {
// Selfie age estimation requires ID backup
console.log('ID verification required');
}
}
onComplianceHit Callback (VerifyCompliance only)
Called when compliance screening detects hits.
onComplianceHit: function(screening) {
console.log('Compliance hits detected:', screening.total_hits);
console.log('Status:', screening.status); // 'Potential Match'
console.log('Found records:', screening.found_records);
// Flag user for manual review
flagForReview(screening);
}
Styling & Customization
Button Styles
Choose from pre-defined button styles:
// Primary (default) - Blue button
buttonStyle: 'primary'
// Secondary - Gray button
buttonStyle: 'secondary'
// Minimal - Text link style
buttonStyle: 'minimal'
// Custom - Use your own CSS
buttonStyle: 'custom'
Custom CSS
Override widget styles with custom CSS:
<style>
/* Customize button */
.verifyhuman-button {
background-color: #10b981;
color: white;
border-radius: 8px;
padding: 12px 24px;
font-size: 16px;
font-weight: 600;
}
.verifyhuman-button:hover {
background-color: #059669;
}
/* Customize modal */
.verifyhuman-modal {
border-radius: 12px;
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
}
/* Customize video preview */
.verifyhuman-video {
border-radius: 8px;
border: 2px solid #10b981;
}
</style>
Dark Mode Support
Widgets automatically detect and adapt to dark mode:
VerifyHuman.init({
apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
theme: 'auto', // 'auto' | 'light' | 'dark'
});
Advanced Integration
Signup Form Integration
Require verification before form submission:
<form id="signup-form">
<input type="email" name="email" placeholder="Email" required>
<input type="password" name="password" placeholder="Password" required>
<div id="verifyhuman-widget"></div>
<button type="submit" id="signup-button" disabled>
Sign Up
</button>
</form>
<script>
VerifyHuman.init({
apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
onSuccess: function(result) {
// Enable submit button
document.getElementById('signup-button').disabled = false;
// Store verification token
document.getElementById('signup-form').addEventListener('submit', function(e) {
e.preventDefault();
// Send verification token with form data
fetch('/api/signup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: document.querySelector('[name="email"]').value,
password: document.querySelector('[name="password"]').value,
verification_token: result.token
})
});
});
}
});
</script>
Comment Section Integration
Verify users before allowing comments:
<textarea id="comment-text" placeholder="Write your comment..." disabled></textarea>
<button id="comment-submit" disabled>Post Comment</button>
<div id="verifyhuman-widget"></div>
<script>
VerifyHuman.init({
apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
buttonText: 'Verify to Comment',
onSuccess: function(result) {
// Enable comment form
document.getElementById('comment-text').disabled = false;
document.getElementById('comment-submit').disabled = false;
// Store verification ID
sessionStorage.setItem('verified_user', result.verification_id);
}
});
</script>
Age-Gated Content
Show content only after age verification:
<div id="age-gate">
<h2>Age Verification Required</h2>
<p>You must be 21+ to access this content.</p>
<div id="verifyage-widget"></div>
</div>
<div id="restricted-content" style="display: none;">
<!-- Age-restricted content here -->
</div>
<script>
VerifyAge.init({
apiKey: 'vhk-a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
useCase: 'alcohol',
minAge: 21,
onSuccess: function(result) {
// Hide age gate
document.getElementById('age-gate').style.display = 'none';
// Show restricted content
document.getElementById('restricted-content').style.display = 'block';
// Store verification in session
sessionStorage.setItem('age_verified', 'true');
}
});
// Check if already verified
if (sessionStorage.getItem('age_verified')) {
document.getElementById('age-gate').style.display = 'none';
document.getElementById('restricted-content').style.display = 'block';
}
</script>
Troubleshooting
Widget Not Appearing
Problem: Widget container is empty.
Solutions:
- Check that script is loaded:
console.log(typeof VerifyHuman) - Verify container ID matches:
containerId: 'your-id' - Check browser console for errors
- Ensure API key is valid
Camera Not Working
Problem: Camera permission denied or not found.
Solutions:
- Check HTTPS: Widgets require HTTPS (except localhost)
- Allow camera permission in browser
- Test camera:
navigator.mediaDevices.getUserMedia({ video: true }) - Check for conflicting apps using camera
Verification Failing
Problem: All verifications return FAIL status.
Solutions:
- Check API key is active in dashboard
- Verify account email is confirmed
- Check credits remaining
- Test with good lighting and clear face
- Check browser console for error details
Styling Issues
Problem: Widget doesn't match site design.
Solutions:
- Use
buttonStyle: 'custom'for full control - Override CSS classes (see Custom CSS section)
- Use
themeoption to match light/dark mode - Contact support for custom branding (Enterprise)
Browser Support
Widgets support all modern browsers:
| Browser | Minimum Version |
|---|---|
| Chrome | 60+ |
| Firefox | 55+ |
| Safari | 11+ |
| Edge | 79+ |
| Opera | 47+ |
| Samsung Internet | 8+ |
Mobile Support:
- iOS Safari 11+
- Android Chrome 60+
- Android Firefox 55+
Requirements:
- JavaScript enabled
- Camera access (getUserMedia API)
- HTTPS (except localhost)
Security Considerations
API Key Exposure
Safe: Client-side API keys (vhk-{32chars}) can be exposed in frontend code.
Reason: Keys are scoped to specific products and have built-in rate limiting. They cannot access your account settings or other sensitive data.
Token Validation
Best Practice: Always validate verification tokens on your backend:
// Frontend: Send token to backend
onSuccess: function(result) {
fetch('/api/validate-verification', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: result.token })
});
}
// Backend: Validate with VerifyHuman
const response = await fetch('https://app.verifyhuman.io/api/validate', {
method: 'POST',
headers: {
'Authorization': 'Bearer vhsk-your_api_secret_here',
'Content-Type': 'application/json'
},
body: JSON.stringify({ token: userToken })
});
CORS & Domain Restrictions
Configure allowed domains in your dashboard:
- Go to Dashboard → API Keys
- Select your API key
- Add Allowed Domains (e.g.,
yourdomain.com) - Save changes
Support
Need help with widget integration?
- Email: support@verifyhuman.io
- Live Chat: Available in your dashboard
- Documentation: docs.verifyhuman.io
- Examples: github.com/verifyhuman/examples