Browser
CDN and programmatic browser integration for NeoCaptcha — events, callbacks, and init options.
Updated 2/22/2026
Browser Integration
Use this guide for plain HTML/JS pages, or any setup where you control the page directly.
CDN (auto-discovery)
Add the script tag once per page:
<script src="https://cdn.neocaptcha.com/v1/browser.js" defer></script>Add a container element with your site key:
<div id="neocaptcha" sitekey="YOUR_SITE_KEY"></div>The script finds the element automatically at page load and mounts the widget inside it. No JavaScript required.
DOM events
The CDN script dispatches these events on the container element:
| Event | e.detail | Description |
|---|---|---|
neocaptcha:load | — | Widget is ready |
neocaptcha:complete | { verifyToken: string } | User passed the challenge |
neocaptcha:error | — | Challenge failed |
neocaptcha:expire | — | Challenge expired before completion |
const captcha = document.getElementById('neocaptcha');
let captchaToken = null;
captcha.addEventListener('neocaptcha:complete', (e) => {
captchaToken = e.detail.verifyToken;
document.getElementById('submit-btn').disabled = false;
});
captcha.addEventListener('neocaptcha:error', () => {
captchaToken = null;
document.getElementById('submit-btn').disabled = true;
});
captcha.addEventListener('neocaptcha:expire', () => {
captchaToken = null;
document.getElementById('submit-btn').disabled = true;
});Programmatic init()
For SPAs, dynamic insertion, or any case where you need lifecycle callbacks directly:
npm install @neocaptcha/sdkimport { init } from '@neocaptcha/sdk';Required options
| Option | Type | Description |
|---|---|---|
container | HTMLElement | Element to mount the captcha widget inside |
siteKey | string | Your site key from the dashboard |
Optional options
| Option | Type | Description |
|---|---|---|
expiryTimeout | number | null | Challenge expiry in seconds. Pass null to disable. |
onLoad | () => void | Called when the widget is ready |
onComplete | (verifyToken: string) => void | Called on successful challenge completion |
onError | () => void | Called when there is an error |
onExpire | () => void | Called when the challenge expires |
Full example
import { init } from '@neocaptcha/sdk';
let captchaToken: string | null = null;
init({
container: document.getElementById('captcha-slot'),
siteKey: process.env.NEOCAPTCHA_SITE_KEY!,
expiryTimeout: 60,
onLoad: () => console.log('Ready'),
onComplete: (verifyToken) => {
captchaToken = verifyToken;
},
onError: () => {
captchaToken = null;
},
onExpire: () => {
captchaToken = null;
},
});Operational recommendations
- Keep the token in memory (not localStorage).
- Tie token lifecycle to a single form submit attempt.
- Rechallenge if the user retries after expiration.
- Never call business-critical APIs without server-side verification.