Enzonix CAPTCHA Installation Guide
A reCAPTCHA v2-compatible proof-of-work CAPTCHA system that provides bot protection without relying on data collection.
API Endpoint: https://verify.enzonix.com
Overview
Enzonix CAPTCHA protects your forms with proof-of-work validation. Users must solve a computational challenge before submitting the form. Unlike traditional CAPTCHAs:
- No data collection from users
- Works without images or accessibility delays
- Privacy-focused approach
- Drop-in replacement for Google reCAPTCHA v2
How It Works
- User visits your page
- Widget displays "I'm not a robot" challenge
- User clicks the challenge
- Client performs proof-of-work computation
- Client receives verification token
- Token is submitted with form
- Server verifies token with API
Getting Started
Create your Enzonix Captcha Service Account:
- Site Key - Public key embedded in frontend
- Secret Key - Private key for backend verification
- Domains - List or wildcards for supported domains to keep your keys being used anywhere
Frontend Implementation
Direct HTML Script
The simplest approach - load the widget script and initialize it.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>My Form</title>
</head>
<body>
<form id="myForm" onsubmit="handleSubmit(event)">
<input type="text" name="username" placeholder="Username">
<input type="email" name="email" placeholder="Email">
<!-- CAPTCHA Widget -->
<div id="ez-captcha"></div>
<button type="submit">Submit</button>
</form>
<!-- Load Enzonix Widget -->
<script src="https://verify.enzonix.com/widget.js"></script>
<script>
let captchaWidget;
// Initialize CAPTCHA
window.addEventListener('load', function() {
captchaWidget = new EnzonixCaptcha(
document.getElementById('ez-captcha'),
{ sitekey: 'YOUR_SITE_KEY' },
function(token) {
console.log('CAPTCHA verified, token:', token);
}
);
});
// Handle form submission
async function handleSubmit(event) {
event.preventDefault();
// Check if CAPTCHA was verified
const token = captchaWidget.getResponse();
if (!token) {
alert('Please verify CAPTCHA first');
return;
}
// Submit form with token
const formData = new FormData(document.getElementById('myForm'));
formData.append('captcha_response', token);
const response = await fetch('/api/submit-form', {
method: 'POST',
body: formData
});
const result = await response.json();
if (result.success) {
alert('Form submitted successfully!');
}
}
</script>
</body>
</html>
JavaScript / TS Module
PHP Backend Module
Customizing the Widget Appearance
The Enzonix CAPTCHA widget uses CSS variables for theming, allowing you to customize its appearance to match your site's design.
Available Options
Theme
The widget supports two built-in themes:
dark(default) - Dark background with light textlight- Light background with dark text
Set the theme via JavaScript options or HTML data attribute:
// Via options
new EnzonixCaptcha(element, {
sitekey: 'YOUR_SITE_KEY',
theme: 'light'
});
<!-- Via data attribute -->
<div id="captcha" data-theme="light"></div>
CSS Variables for Advanced Customization
For more control, you can override the CSS variables used by the widget. The widget applies the class enzonix-captcha to its container.
Available CSS Variables
--ez-bg: Background (gradient or solid color)--ez-border: Border color--ez-text: Main text color--ez-subtext: Secondary text color (e.g., "Enzonix" link)--ez-subtext-hover: Hover color for links--ez-box-bg: Checkbox background color--ez-box-border: Checkbox border color--ez-accent: Accent color (used for loading spinner)--ez-success: Success color (checkmark)--ez-success-bg: Success background (checked box)--ez-error: Error color--ez-error-border: Error border color--ez-shadow: Default box shadow--ez-shadow-hover: Hover box shadow
How to Override Variables
Override globally for all widgets on your page:
<style>
.enzonix-captcha {
--ez-bg: linear-gradient(135deg, #667eea, #764ba2);
--ez-accent: #ff6b6b;
--ez-text: #ffffff;
--ez-border: #555555;
/* Add more as needed */
}
</style>
Or for a specific widget instance:
<div id="my-captcha" style="--ez-accent: #4ecdc4; --ez-bg: #2c3e50;"></div>
Example: Custom Dark Theme
<style>
.enzonix-captcha {
--ez-bg: linear-gradient(135deg, #2c1810, #1a1a2e);
--ez-border: #3d2b1f;
--ez-text: #f4e4bc;
--ez-subtext: #a0865c;
--ez-subtext-hover: #d4af37;
--ez-box-bg: #4a3c28;
--ez-box-border: #6b5b3a;
--ez-accent: #d4af37;
--ez-success: #90EE90;
--ez-success-bg: #2e4d2e;
--ez-error: #ff6b6b;
--ez-shadow: 0 2px 4px rgba(0,0,0,0.3);
--ez-shadow-hover: 0 4px 8px rgba(0,0,0,0.4);
}
</style>
This allows full customization while maintaining the widget's functionality.
Backend Verification
After the frontend obtains a token, your backend must verify it with the API endpoint.
Step 1: Receive the Token
The CAPTCHA token is returned by the widget's callback or via getResponse(). Submit it with your form data.
Step 2: Verify with API
Send the token and your secret key to verify it.
Troubleshooting
Widget Shows "Invalid sitekey"
Cause: The sitekey is not registered or not active.
Solution:
- Verify the sitekey is correct
- Check that the site is marked as "active" in your dashboard
- Wait a few minutes for DNS propagation
"Failed to load" Error
Cause: Network connectivity issue or domain not whitelisted.
Solution:
// Check your domain is whitelisted
// Add console logging to debug
async function fetch() {
try {
const r = await fetch(`https://verify.enzonix.com/api/challenge?sitekey=${this.sitekey}`);
console.log('Challenge status:', r.status);
const d = await r.json();
console.log('Challenge data:', d);
if (!d.challenge) {
this.showError('Invalid sitekey');
}
this.data = d;
} catch (error) {
console.error('Fetch error:', error);
this.showError('Failed to load');
}
}
Backend Verification Returns "Invalid Input Response"
Cause: The token is malformed or has expired.
Solution:
- Ensure the token is submitted immediately after verification
- Check the token is not being modified in transit
- Token is valid for 5 minutes only
"challenge-timeout" Error
Cause: More than 5 minutes passed between challenge request and verification.
Solution:
- Reduce time between user clicking the widget and form submission
- Renew the challenge if the timeout is reached
// Refresh challenge if needed
async function refreshChallenge() {
await this.fetch(); // Re-request a new challenge
}
CORS Issues in Browser Console
Cause: The API is being called from a domain not whitelisted.
Solution:
// The widget automatically handles CORS headers
// Just ensure your domain is registered and whitelisted
// Check browser console for specific domain rejection
Verification Fails with "Invalid Proof of Work"
Cause: The client's computation didn't meet the difficulty requirement.
Solution:
- Ensure the browser supports
crypto.subtle.digest() - Check that JavaScript execution isn't being blocked
- Verify the timestamp is synchronized (within 5 minutes of server)
Multiple Widgets on Same Page
<!-- Multiple widgets work independently -->
<div id="captcha-1"></div>
<div id="captcha-2"></div>
<script src="https://verify.enzonix.com/widget.js"></script>
<script>
const widget1 = new EnzonixCaptcha(
document.getElementById('captcha-1'),
{ sitekey: 'SITEKEY_1' }
);
const widget2 = new EnzonixCaptcha(
document.getElementById('captcha-2'),
{ sitekey: 'SITEKEY_2' }
);
</script>