HTML and JavaScript¶
Without a framework, you embed the widget with two lines of HTML: a script link in the head area of the page and an element in the form. Use this method also for each content management system that permits your own HTML.
Requirements¶
The following requirements must be met:
| Requirement | Value |
|---|---|
| Sitekey | Public sitekey from the Details view |
| Access | Write rights for the HTML template of the page |
| Server side | Endpoint that verifies the token |
Embed the script¶
Add this line to the <head> area of your page:
Note
If your website sends a Content Security Policy, then it must permit the https://cdn.eu-captcha.eu and https://api.eu-captcha.eu addresses. See Content Security Policy.
Add the widget¶
Add this element to each form to protect:
Replace the value of data-sitekey with your public sitekey.
Thus, the full form is as follows:
<form method="POST" action="/your-endpoint">
<!-- your fields -->
<div class="eu-captcha" data-sitekey="a1b2c3d4-0000-0000-0000-000000000000"></div>
<button type="submit">Submit</button>
</form>
During the transmission, the widget adds the hidden eu-captcha-response field with the token.
Attributes of the element¶
The verify.js script uses these attributes:
| Attribute | Default | Effect |
|---|---|---|
data-sitekey |
— | Public sitekey. The value is necessary. |
data-theme |
"light" |
Appearance, values "light" and "dark". |
data-width |
330 |
Width of the widget in pixels. |
data-height |
100 |
Height of the widget in pixels. |
data-widgetid |
automatic | Your own identifier of the widget. |
data-autostart |
"true" |
The "false" value delays the start of the challenge. |
data-callback |
— | Name of a global function that is called after the challenge passed. |
data-expired-callback |
— | Name of a global function that is called when the token expires. |
data-error-callback |
— | Name of a global function that is called when an error occurs. |
Embed the package with npm¶
For projects with a bundler, the same widget is available as an npm package. The package supplies TypeScript types and a version control. The widget continues to load verify.js from the CDN.
Proceed as follows to embed the package:
- ► Install the package:
- ► Make a target element in the form:
<form id="contact-form">
<!-- your fields -->
<div id="captcha"></div>
<button type="submit">Submit</button>
</form>
- ► Render the widget into the target element:
import { renderEuCaptcha, isEuCaptchaDone } from "@myrasec/eu-captcha-vanilla";
const captchaSitekey = "EUCAPTCHA_SITE_KEY";
renderEuCaptcha("#captcha", {
sitekey: captchaSitekey,
onComplete: (token: string) => console.log("token:", token),
}).catch((err) => console.error("EU CAPTCHA failed to render", err));
- ➔ The widget starts the verification in the background.
As the first argument, renderEuCaptcha accepts a CSS selector or an HTMLElement.
Options¶
These options are available:
| Option | Type | Default | Effect |
|---|---|---|---|
sitekey |
string |
— | Public sitekey. The value is necessary. |
theme |
string |
"light" |
Appearance, values "light" and "dark". |
width |
number |
330 |
Width of the widget in pixels. |
height |
number |
100 |
Height of the widget in pixels. |
widgetId |
string |
— | Your own identifier of the widget. Without a value, the package makes an identifier. For euCaptcha.execute(), the value is necessary. |
autostart |
boolean |
true |
Starts the challenge automatically. The false value delays the start until the euCaptcha.execute(widgetId) call. |
onComplete |
(token: string) => void |
— | Is called with the token as soon as the challenge passed. |
onExpired |
() => void |
— | Is called when the token expires. A token expires 60 minutes after the solution. |
onError |
() => void |
— | Is called when a network error or a server error occurs. |
Delay the start of the challenge¶
Set autostart to false and give an identifier, to start the challenge yourself:
renderEuCaptcha("#captcha", {
sitekey: captchaSitekey,
widgetId: "my-captcha",
autostart: false,
});
document.getElementById("verify-btn")!.addEventListener("click", () => {
(window as any).euCaptcha.execute("my-captcha");
});
Get the condition¶
Before the transmission, examine if the challenge passed:
import { isEuCaptchaDone } from "@myrasec/eu-captcha-vanilla";
function handleSubmit(e: SubmitEvent): void {
e.preventDefault();
if (!isEuCaptchaDone()) {
// challenge not yet complete
return;
}
// proceed with form submission
}
Warning
Without an argument, isEuCaptchaDone() is reliable only with exactly one widget without its own identifier. With more than one widget, give an identifier to each widget and get isEuCaptchaDone(widgetId).
As an alternative, wait for the euCaptchaCompleted message at the window. Examine the origin of the message, because each script and each extension in the browser can send messages:
const CAPTCHA_ORIGIN = "https://cdn.eu-captcha.eu";
function listenForCaptchaDone(msg: MessageEvent): void {
if (msg.origin !== CAPTCHA_ORIGIN) return;
const data = (msg.data ?? {}) as { type?: string };
if (data.type === "euCaptchaCompleted") {
// enable submit button, update state, etc.
}
}
window.addEventListener("message", listenForCaptchaDone, false);
Warning
The verification in the browser controls only the operation. Always also verify the token on the server.
Remove the widget¶
renderEuCaptcha returns a reference. The handle.destroy() call removes the message listener, clears the target element, and resets the condition. Thus, isEuCaptchaDone() gives false again.
const handle = await renderEuCaptcha("#captcha", { sitekey: captchaSitekey });
// later
handle.destroy();
Warning
Call destroy() for each removal. Each render with a callback function adds a message listener to the window, and only destroy() removes it again. Without this call, one listener and one detached DOM subtree stay in the memory for each render.
Verify the token¶
Verify the token on your server. See Verify a client token.
Full example¶
See HTML and Django.