Angular
EU CAPTCHA provides dedicated packages for each major Angular version. Install the one that matches your Angular release.
| Angular version | Package | Version | npm |
|---|---|---|---|
| Angular 19 | @myrasec/eu-captcha-angular19 |
1.0.1 | npm |
| Angular 20 | @myrasec/eu-captcha-angular20 |
1.0.1 | npm |
| Angular 21 | @myrasec/eu-captcha-angular21 |
1.0.1 | npm |
Server-side verification is identical regardless of frontend framework — see Server-Side Verification.
Installation
Install the package that matches your Angular version:
# Angular 19
npm i @myrasec/eu-captcha-angular19
# Angular 20
npm i @myrasec/eu-captcha-angular20
# Angular 21
npm i @myrasec/eu-captcha-angular21
The examples below use @myrasec/eu-captcha-angular19 — replace the package name with the one you installed.
Basic usage
Standalone component
Import EuCaptchaComponent directly into your component's imports array:
import { Component } from '@angular/core';
import { EuCaptchaComponent, isEuCaptchaDone } from '@myrasec/eu-captcha-angular19';
@Component({
standalone: true,
imports: [EuCaptchaComponent],
template: `
<form (submit)="handleSubmit($event)">
<!-- your fields -->
<eu-captcha sitekey="EUCAPTCHA_SITE_KEY" />
<button type="submit">Submit</button>
</form>
`,
})
export class ContactFormComponent {
handleSubmit(event: Event): void {
event.preventDefault();
if (!isEuCaptchaDone()) {
// challenge not yet complete
return;
}
// proceed with form submission
}
}
NgModule-based app
Import EuCaptchaModule once in your AppModule (or any feature module):
import { NgModule } from '@angular/core';
import { EuCaptchaModule } from '@myrasec/eu-captcha-angular19';
@NgModule({
imports: [EuCaptchaModule],
})
export class AppModule {}
Then use the component in any template within that module:
<eu-captcha sitekey="EUCAPTCHA_SITE_KEY" />
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
sitekey |
string |
— | Your public sitekey (required) |
theme |
string |
"light" |
Visual theme: "light" or "dark" |
width |
number |
330 |
Widget width in pixels |
height |
number |
100 |
Widget height in pixels |
widgetId |
string |
— | Custom widget ID. If omitted, an ID is auto-generated. Needed when calling euCaptcha.execute(). |
autostart |
boolean |
true |
Start the challenge automatically on init. Set to false to defer until euCaptcha.execute(widgetId) is called. |
Outputs
| Output | Payload | Description |
|---|---|---|
completed |
string |
Emitted with the encoded token when the challenge completes. |
expired |
— | Emitted when the token expires (60 minutes after completion). |
error |
— | Emitted when the challenge fails due to a network or server error. |
Checking completion before submit
The challenge runs asynchronously. Call isEuCaptchaDone() in your submit handler to confirm it has finished before sending the form to your server:
import { isEuCaptchaDone } from '@myrasec/eu-captcha-angular19';
handleSubmit(event: Event): void {
event.preventDefault();
if (!isEuCaptchaDone()) {
// challenge not yet complete — show a message or wait
return;
}
// proceed with form submission
}
Event bindings
Use (completed), (expired), and (error) to react to widget events without listening for window messages manually:
<eu-captcha
sitekey="EUCAPTCHA_SITE_KEY"
(completed)="onToken($event)"
(expired)="onExpired()"
(error)="onError()"
/>
onToken(token: string): void {
// challenge complete — token is already written to the hidden input;
// update state or enable your submit button here
this.verified = true;
}
onExpired(): void {
// token has expired — prompt the user to re-verify
this.verified = false;
}
onError(): void {
// network or server error during verification
this.errorMsg = 'CAPTCHA failed. Please try again.';
}
Deferred execution
Set [autostart]="false" and provide a widgetId to suppress the automatic challenge, then trigger it programmatically:
<eu-captcha
sitekey="EUCAPTCHA_SITE_KEY"
widgetId="login-captcha"
[autostart]="false"
(completed)="submitForm($event)"
/>
<button (click)="execute()">Verify and submit</button>
execute(): void {
(window as any).euCaptcha.execute('login-captcha');
}
This is useful for forms where you want the challenge to start only when the user clicks the submit button, or when the widget is not immediately visible on page load.
Listening for completion
If you prefer to use the euCaptchaDone window message instead of the (completed) output — for example, to enable a submit button from outside the component — listen for it in ngOnInit/ngOnDestroy:
import { Component, OnInit, OnDestroy } from '@angular/core';
@Component({ /* ... */ })
export class MyComponent implements OnInit, OnDestroy {
private listener = (msg: MessageEvent) => {
if (msg.data.type === 'euCaptchaDone') {
this.submitEnabled = true;
}
};
ngOnInit(): void {
window.addEventListener('message', this.listener, false);
}
ngOnDestroy(): void {
window.removeEventListener('message', this.listener, false);
}
}
Retrieving the token
Once complete, the widget injects a hidden input into the surrounding <form>:
<input type="hidden" name="eu-captcha-response" value="<token>" />
If you are submitting via fetch or HttpClient, read the token from the DOM or use the (completed) output:
const token = document.querySelector('input[name="eu-captcha-response"]')?.value ?? '';
Pass it to your server endpoint and verify it with the verification API.