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 https://www.npmjs.com/package/enzonix-captcha PHP Backend Module https://packagist.org/packages/enzonix/captcha 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 text light - 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>