Invisible CAPTCHA (Beta)
Invisible CAPTCHA provides seamless bot protection without interrupting the user experience. The CAPTCHA challenge runs in the background and only presents a visible challenge if additional verification is needed.
Overview
Section titled OverviewInvisible CAPTCHA works by:
- Running verification challenges in the background
- Analyzing user behavior and browser characteristics
- Only showing a visible challenge if the user appears suspicious
- Providing a smooth experience for legitimate users
Making a widget invisible
Section titled Making a widget invisibledata-size="invisible" is what makes the widget invisible. Put it on the element that submits the form:
<button class="procaptcha" data-sitekey="your_site_key" data-size="invisible" data-callback="onCaptchaSuccess"> Submit</button>Which challenge runs behind it is a property of the site key, chosen in the
Prosopo portal — see CAPTCHA Types. On a frictionless
site key most visitors complete an invisible Proof of Work and never see anything; a visitor who scores as risky is
shown a puzzle or an image challenge at the point of submission.
Implementation Methods
Section titled Implementation MethodsImplicit Rendering
Section titled Implicit RenderingAdd the procaptcha class and data attributes directly to your form elements:
<!DOCTYPE html><html><head> <script type="module" src="https://js.prosopo.io/js/procaptcha.bundle.js" async defer></script> <script nomodule src="https://js.prosopo.io/js/procaptcha.bundle.iife.js" async defer></script></head><body> <form> <input type="email" name="email" required> <button type="button" class="procaptcha" data-sitekey="your_site_key" data-size="invisible" data-callback="handleSubmit" data-failed-callback="handleFailure"> Submit Form </button> </form>
<script> function handleSubmit(token) { console.log('CAPTCHA verified:', token); // Submit your form with the token }
function handleFailure() { console.log('CAPTCHA verification failed'); // Handle failure case } </script></body></html>Explicit Rendering
Section titled Explicit RenderingFor more control over the CAPTCHA lifecycle:
<!DOCTYPE html><html><head> <script type="module" src="https://js.prosopo.io/js/procaptcha.bundle.js" async defer></script> <script nomodule src="https://js.prosopo.io/js/procaptcha.bundle.iife.js" async defer></script></head><body> <form id="demo-form"> <input type="email" name="email" required> <div id="procaptcha"></div> <button type="submit">Submit Form</button> </form>
<script type="module"> import { render, execute } from "https://js.prosopo.io/js/procaptcha.bundle.js"
let widgetId;
function handleCaptchaSuccess(token) { console.log('CAPTCHA verified:', token); // Process form submission with token }
function handleCaptchaFailure() { console.log('CAPTCHA verification failed'); // Handle failure }
document.addEventListener('DOMContentLoaded', async function() { // Render invisible CAPTCHA. render() is async, so await it before // using the id it resolves to. widgetId = await render(document.getElementById('procaptcha'), { siteKey: 'your_site_key', size: 'invisible', callback: handleCaptchaSuccess, 'failed-callback': handleCaptchaFailure });
// Handle form submission document.getElementById('demo-form').addEventListener('submit', function(e) { e.preventDefault(); // Trigger CAPTCHA verification. Pass the widget id to trigger only // this widget; with no argument every widget on the page runs. execute(widgetId); }); }); </script></body></html>Configuration Options
Section titled Configuration Options| Attribute | Value | Description |
|---|---|---|
data-size | "invisible" | Required. Enables invisible mode |
data-callback | Function name | Called when CAPTCHA is successfully verified |
data-failed-callback | Function name | Called when CAPTCHA verification fails |
data-sitekey | Your site key | Required. Your Procaptcha site key |
data-start-mode | "auto", "manual" | When the background work starts. auto (default) starts on page load. manual waits until you call window.procaptcha.start() or execute(). See Controlling when the widget starts. |
data-bind | CSS selector | A button on your page that triggers this widget, instead of your code calling execute(). The button’s default action is prevented. See Binding a button to the widget. |
data-placement | "popup" | Accepted for consistency with visible widgets, but an invisible widget has no checkbox to anchor a float challenge to, so its challenge always opens as a centred popup. |
Best Practices
Section titled Best Practices1. Choose the Right Type
Section titled 1. Choose the Right TypeSet this on the site key in the portal, not in your markup:
- Frictionless: best for most use cases — it adapts per visitor, and most of them see nothing at all
- PoW: when you want every visitor to get the same invisible challenge and never a visible one
- Puzzle or Image: when every visitor should get the same visible challenge on submission
2. Handle Failures Gracefully
Section titled 2. Handle Failures GracefullyAlways implement a failed callback to handle verification failures:
function onCaptchaFailed() { // Show user-friendly error message alert('Verification failed. Please try again.'); // Reset form or provide alternative}3. Provide Loading Indicators
Section titled 3. Provide Loading IndicatorsSince verification happens in the background, consider showing loading states:
function onCaptchaStart() { document.getElementById('submit-btn').disabled = true; document.getElementById('submit-btn').textContent = 'Verifying...';}
function onCaptchaComplete(token) { document.getElementById('submit-btn').disabled = false; document.getElementById('submit-btn').textContent = 'Submit'; // Process with token}Server-Side Verification
Section titled Server-Side VerificationAlways verify the Procaptcha response on your server:
// Node.js exampleconst response = await fetch('https://api.prosopo.io/siteverify', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ secret: 'your_secret_key', token: token, // Token from Procaptcha callback ip: userIP // Optional })});
const result = await response.json();if (result.verified) { // Procaptcha verified successfully console.log('Verification successful');} else { // Verification failed console.log('Verification failed:', result.status);}Troubleshooting
Section titled TroubleshootingCAPTCHA Not Triggering
Section titled CAPTCHA Not Triggering- Ensure
data-size="invisible"is set - Check that your site key is correct and active
- Verify your domain is registered in the portal
- Confirm you’re on Pro or Enterprise tier
Unexpected Visible Challenges
Section titled Unexpected Visible ChallengesThis is normal behavior when:
- User behavior appears suspicious
- Browser characteristics suggest automation
- Additional verification is needed for security
Integration Issues
Section titled Integration Issues- Make sure the Procaptcha script loads before your code runs
- Check browser console for error messages
- Verify callback functions are defined globally
- Test with different CAPTCHA types to isolate issues
Migration from Visible CAPTCHA
Section titled Migration from Visible CAPTCHATo convert existing visible CAPTCHA implementations:
- Add
data-size="invisible"to existing configurations - Update UI to remove CAPTCHA container (for implicit rendering)
- Adjust form styling since no visible widget will appear
- Test user flows to ensure smooth experience
- Update any size-dependent CSS or JavaScript