Skip to content

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.