JavaScript API
verify.js initialises automatically on DOMContentLoaded and processes every element with class="eu-captcha" on the page. This page documents all widget attributes, the programmatic rendering function, and the postMessage events the widget emits.
Widget attributes
Place these attributes on the <div class="eu-captcha"> element.
| Attribute | Type | Default | Description |
|---|---|---|---|
data-sitekey |
string | — | Your public sitekey. Required — the widget will not verify correctly without it. |
data-theme |
string | "light" |
Visual theme. Accepted values: "light" or "dark" (case-insensitive). Any other value is treated as "light". |
data-width |
number | 330 |
Width of the widget iframe in pixels. Must be a finite number; invalid values fall back to 330. |
data-height |
number | 100 |
Height of the widget iframe in pixels. Must be a finite number; invalid values fall back to 100. Minimum value is 48. |
data-widgetid |
string | — | Custom widget ID. If omitted, an ID is auto-generated (eucaptcha-0, eucaptcha-1, …). Useful when you need a stable, known name to pass to euCaptcha.execute(). |
data-autostart |
boolean | true |
Whether the challenge starts automatically when the page loads. Set to "false" to defer the challenge until euCaptcha.execute() is called manually. |
data-callback |
string | — | Name of a global function to call when the challenge completes. The function receives the encoded token as its first argument. |
data-expired-callback |
string | — | Name of a global function to call when the token expires (60 minutes after completion). |
data-error-callback |
string | — | Name of a global function to call when the challenge fails due to a network or server error. |
Example:
<div
class="eu-captcha"
data-sitekey="EUCAPTCHA_SITE_KEY"
data-theme="dark"
data-width="280"
data-height="60"
data-widgetid="login-captcha"
data-autostart="false"
data-callback="onCaptchaDone"
data-expired-callback="onCaptchaExpired"
data-error-callback="onCaptchaError"
></div>
What the widget renders
When verify.js processes a .eu-captcha element it replaces its contents with two elements:
1. A hidden input that will hold the token once the challenge completes:
<input type="hidden" name="eu-captcha-response" class="eu-captcha-response" value="" />
2. An iframe that runs the challenge in an isolated context:
<iframe
src="https://cdn.eu-captcha.eu/check.html#host=…&sitekey=…&protocol=…&theme=…"
title="myraverify"
width="330"
height="100"
frameborder="0"
scrolling="no"
></iframe>
The hidden input is populated automatically when the iframe posts a completion message.
Deferred execution
By default the challenge starts as soon as the widget loads. Set data-autostart="false" to suppress this, then trigger the challenge programmatically with euCaptcha.execute():
euCaptcha.execute(widgetId)
| Parameter | Type | Description |
|---|---|---|
widgetId |
string |
The widget ID — either the value you set in data-widgetid, or the auto-generated eucaptcha-0, eucaptcha-1, … |
euCaptcha.execute() posts a start message to the widget iframe. If the widget has already started (e.g. because data-autostart was not set to "false"), the call has no effect.
Example — trigger the challenge when the user clicks a button:
<div
class="eu-captcha"
data-sitekey="EUCAPTCHA_SITE_KEY"
data-widgetid="my-captcha"
data-autostart="false"
data-callback="onVerified"
></div>
<button onclick="euCaptcha.execute('my-captcha')">Verify and submit</button>
<script>
function onVerified(token) {
// token is already written to the hidden input;
// submit the form or make an API call here
document.getElementById("my-form").submit();
}
</script>
Programmatic rendering
verify.js exposes a function on window for cases where you need to generate the widget HTML dynamically (e.g. after a route change in a non-React/Vue/Angular SPA, or when injecting a form at runtime):
window.getEuCaptchaElement(sitekey, opts)
| Parameter | Type | Description |
|---|---|---|
sitekey |
string |
Your public sitekey |
opts.theme |
string |
"light" or "dark" |
opts.width |
number |
Widget width in pixels |
opts.height |
number |
Widget height in pixels |
opts.widgetId |
string |
Widget ID — must be unique on the page |
opts.autostart |
boolean |
true to start immediately, false to defer |
Returns an HTML string (hidden input + iframe) that you can assign to element.innerHTML. You are responsible for registering any callbacks and calling euCaptcha.execute() when appropriate.
const container = document.getElementById("my-captcha-container");
container.innerHTML = window.getEuCaptchaElement("EUCAPTCHA_SITE_KEY", {
theme: "light",
width: 330,
height: 100,
widgetId: "my-widget",
autostart: true,
});
postMessage events
When the challenge completes, the widget iframe posts two messages to the parent window in sequence.
euCaptchaCompleted
Carries the encoded token. verify.js listens for this internally and writes the token into the eu-captcha-response hidden input. You do not normally need to handle this event yourself — reading input[name="eu-captcha-response"] after submission is sufficient.
window.addEventListener("message", function (msg) {
if (msg.data.type === "euCaptchaCompleted") {
// msg.data.payload contains the encoded token string
// already written to the hidden input by verify.js
}
}, false);
euCaptchaDone
A lightweight completion signal with an empty payload. Use this to update UI state — enabling a submit button, hiding a spinner, or similar — without needing to handle the token yourself.
window.addEventListener("message", function (msg) {
if (msg.data.type === "euCaptchaDone") {
document.getElementById("submit-btn").disabled = false;
}
}, false);
euCaptchaExpired
Posted 60 minutes after a successful completion to indicate the token is no longer valid. Use this to reset the form or prompt the user to re-verify. verify.js invokes data-expired-callback when this event arrives.
window.addEventListener("message", function (msg) {
if (msg.data.type === "euCaptchaExpired") {
// token has expired — prompt the user to re-verify
}
}, false);
euCaptchaError
Posted when the challenge fails due to a network or server error. verify.js invokes data-error-callback when this event arrives.
window.addEventListener("message", function (msg) {
if (msg.data.type === "euCaptchaError") {
// show an error message to the user
}
}, false);
All events are posted from the iframe to parent using the page's own origin, so no cross-origin issues arise for listeners on the same page. Each event includes a widgetId field identifying which widget instance fired it.
Reading the token for fetch / XHR submissions
If your form is submitted via fetch or XMLHttpRequest rather than a native <form> POST, read the token from the DOM after confirming the challenge is done:
window.addEventListener("message", async function (msg) {
if (msg.data.type !== "euCaptchaDone") return;
const token = document.querySelector('input[name="eu-captcha-response"]')?.value ?? "";
await fetch("/submit", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ token, /* …other fields */ }),
});
}, false);
Framework packages
For React, Vue, and Angular, use the official npm packages — they handle widget mounting, unmounting, and the euCaptchaDone event internally via isEuCaptchaDone(). See React, Vue 3 / Nuxt, Angular, or Other SPA Frameworks.
Related
- HTML Integration — declarative widget setup
- React — React package
- Vue 3 / Nuxt — Vue package
- Angular — Angular package
- Other SPA Frameworks — Svelte, SolidJS, etc.
- Server-Side Verification — verifying the token on your backend