UNPKG

26 kBMarkdownView Raw
1# Angular component for Google reCAPTCHA
2
3## ng-recaptcha [![npm version](https://badge.fury.io/js/ng-recaptcha.svg)](https://www.npmjs.com/package/ng-recaptcha)
4
5[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/dethariel/ng-recaptcha/master/LICENSE)
6[![Build Status](https://app.travis-ci.com/DethAriel/ng-recaptcha.svg?branch=master)](https://app.travis-ci.com/DethAriel/ng-recaptcha)
7[![Coverage Status](https://coveralls.io/repos/github/DethAriel/ng-recaptcha/badge.svg?branch=master)](https://coveralls.io/github/DethAriel/ng-recaptcha?branch=master)
8[![NPM downloads](https://img.shields.io/npm/dm/ng-recaptcha)](https://www.npmjs.com/package/ng-recaptcha)
9
10A simple, configurable, easy-to-start component for handling reCAPTCHA v2 and v3.
11
12## Table of contents
13
141. [Installation](#installation)
151. [Basic Usage](#example-basic)
16 - [reCAPTCHA v3 Usage](#example-basic-v3)
17 - [Playground](#playground)
181. [Working with `@angular/forms`](#forms-ready)
191. [API](#api)
20 - [Input Options](#api-options)
21 - [Events](#api-events)
22 - [Methods](#api-methods)
231. [Angular version compatibility](#angular-versions)
241. [Examples](#examples)
25 - [Configuring the component globally](#example-global-config)
26 - [Specifying a different language](#example-language)
27 - [Handling errors](#example-error-handling)
28 - [Loading the reCAPTCHA API by yourself](#example-preload-api)
29 - [Usage with `required` in forms](#example-forms)
30 - [Working with invisible reCAPTCHA](#example-invisible)
31 - [Resizing](#example-resizing)
32 - [SystemJS configuration](#example-systemjs)
33 - [Loading from a different location](#example-different-url)
34 - [Specifying nonce for Content-Security-Policy](#example-csp-nonce)
35 - [Listening for all actions with reCAPTCHA v3](#example-v3-all-actions)
36 - [Loading reCAPTCHA keys asynchronously](#async-config-load)
37 - [Hiding reCAPTCHA badge](#hide-recaptcha-badge)
38
39## <a name="installation"></a>Installation
40
41The easiest way is to install through [yarn](https://yarnpkg.com/package/ng-recaptcha) or [npm](https://www.npmjs.com/package/ng-recaptcha):
42
43```sh
44yarn add ng-recaptcha
45npm i ng-recaptcha --save
46```
47
48## <a name="example-basic"></a>Basic Usage [(see in action)](https://dethariel.github.io/ng-recaptcha/)
49
50The below applies to reCAPTCHA v2, for basic usage with reCAPTCHA v3 scroll down to [here](#example-basic-v3).
51
52To start with, you need to import the `RecaptchaModule` (more on that [later](#modules)):
53
54```typescript
55// app.module.ts
56import { RecaptchaModule } from "ng-recaptcha";
57// if you need forms support:
58// import { RecaptchaModule, RecaptchaFormsModule } from 'ng-recaptcha';
59import { BrowserModule } from "@angular/platform-browser";
60import { MyApp } from "./app.component.ts";
61
62@NgModule({
63 bootstrap: [MyApp],
64 declarations: [MyApp],
65 imports: [
66 BrowserModule,
67 RecaptchaModule,
68 // RecaptchaFormsModule, // if you need forms support
69 ],
70})
71export class MyAppModule {}
72```
73
74Once you have done that, the rest is simple:
75
76```typescript
77// app.component.ts
78import { Component } from "@angular/core";
79
80@Component({
81 selector: "my-app",
82 template: `<re-captcha (resolved)="resolved($event)" siteKey="YOUR_SITE_KEY"></re-captcha>`,
83})
84export class MyApp {
85 resolved(captchaResponse: string) {
86 console.log(`Resolved captcha with response: ${captchaResponse}`);
87 }
88}
89```
90
91```typescript
92// main.ts
93import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
94import { MyAppModule } from "./app.module.ts";
95
96platformBrowserDynamic().bootstrapModule(MyAppModule);
97```
98
99### <a name="example-basic-v3"></a>reCAPTCHA v3 Usage [(see in action)](https://dethariel.github.io/ng-recaptcha/v3)
100
101[reCAPTCHA v3](https://developers.google.com/recaptcha/docs/v3) introduces a different way of bot protection. To work with v3 APIs, `ng-recaptcha` provides a service (as opposed to a component). To start with, you need to import the `RecaptchaV3Module` and provide your reCAPTCHA v3 site key using `RECAPTCHA_V3_SITE_KEY` injection token:
102
103```ts
104import { BrowserModule } from "@angular/platform-browser";
105import { RECAPTCHA_V3_SITE_KEY, RecaptchaV3Module } from "ng-recaptcha";
106
107import { MyApp } from "./app.component.ts";
108
109@NgModule({
110 bootstrap: [MyApp],
111 declarations: [MyApp],
112 imports: [BrowserModule, RecaptchaV3Module],
113 providers: [{ provide: RECAPTCHA_V3_SITE_KEY, useValue: "<YOUR_SITE_KEY>" }],
114})
115export class MyAppModule {}
116```
117
118In order to execute a reCAPTCHA v3 action, import the `ReCaptchaV3Service` into your desired component:
119
120```ts
121import { ReCaptchaV3Service } from 'ng-recaptcha';
122
123@Component({
124 selector: 'recaptcha-demo',
125 template: `
126 <button (click)="executeImportantAction()">Important action</button>
127 `,
128})
129export class RecaptchaV3DemoComponent {
130 constructor(
131 private recaptchaV3Service: ReCaptchaV3Service,
132 ) {
133 }
134
135 public executeImportantAction(): void {
136 this.recaptchaV3Service.execute('importantAction')
137 .subscribe((token) => this.handleToken(token));
138 }
139```
140
141As always with subscriptions, please don't forget to **unsubscribe**.
142
143❗️ **Important note**: If your site uses both v2 and v3, then you should _always_ provide `RECAPTCHA_V3_SITE_KEY` (even in modules that only rely on v2 functionality). This will prevent bugs in your code by allowing `ng-recaptcha` to follow reCAPTCHA development guidelines properly ([this one](https://developers.google.com/recaptcha/docs/faq#can-i-run-recaptcha-v2-and-v3-on-the-same-page) in particular).
144
145A more advanced v3 usage scenario includes listening to all actions and their respectively emitted tokens. This is covered [later on this page](#example-v3-all-actions).
146
147### <a name="playground"></a>Playground
148
149You can also play with [this Stackblitz demo](https://stackblitz.com/edit/ng-recaptcha-example) to get a feel of how this component can be used.
150
151## <a name="forms-ready"></a>Working with `@angular/forms`
152
153There are two modules available for you:
154
155```typescript
156import { RecaptchaModule, RecaptchaFormsModule } from "ng-recaptcha";
157```
158
159If you want your `<re-captcha>` element to work correctly with `[(ngModel)]` directive,
160you need to import the `RecaptchaFormsModule` into your application module (pretty much
161like with Angular own `'@angular/forms'` module).
162
163## <a name="api"></a>API
164
165### <a name="api-options"></a>Input Options
166
167The component supports this options:
168
169- `siteKey`
170- `theme`
171- `type`
172- `size`
173- `tabIndex`
174- `badge`
175
176They are all pretty well described either in the [reCAPTCHA docs](https://developers.google.com/recaptcha/docs/display), or in the [invisible reCAPTCHA docs](https://developers.google.com/recaptcha/docs/invisible),
177so I won't duplicate it here.
178
179One additional option that component accepts is `errorMode`. You can learn more about it in the [Handling errors](#example-error-handling) section below.
180
181Besides specifying these options on the component itself, you can provide a global `<re-captcha>` configuration - see [Configuring the component globally](#example-global-config) section below.
182
183### <a name="api-events"></a>Events
184
185- `resolved(response: string)`. Occurs when the captcha resolution value changed.
186 When user resolves captcha, use `response` parameter to send to the server for verification.
187 This parameter is equivalent to calling [`grecaptcha.getResponse`](https://developers.google.com/recaptcha/docs/display#js_api).
188
189 If the captcha has expired prior to submitting its value to the server, the component
190 will reset the captcha, and trigger the `resolved` event with `response === null`.
191
192- `errored(errorDetails: RecaptchaErrorParameters)`. Occurs when reCAPTCHA encounters an error (usually a connectivity problem) **if and only if** `errorMode` input has been set to `"handled"`.
193 `errorDetails` is a simple propagation of any arguments that the original `error-callback` has provided, and is documented here for the purposes of completeness and future-proofing. This array will most often (if not always) be empty. A good strategy would be to rely on just the fact that this event got triggered, and show a message to your app's user telling them to retry.
194
195### <a name="api-methods"></a>Methods
196
197- `reset()`. Performs a manual captcha reset. This method might be useful if your form
198 validation failed, and you need the user to re-enter the captcha.
199- `execute()`. Executes the invisible recaptcha. Does nothing if component's size is not set to "invisible". See [Invisible reCAPTCHA developers guide](https://developers.google.com/recaptcha/docs/invisible#js_api) for more information.
200
201## <a name="angular-versions"></a>Angular version compatibility
202
203| `ng-recaptcha` version | Supported Angular versions |
204| -------------------------------------------------------------------------------- | ---------------------------------------------------- |
205| `13.x.x` | `17.x.x` |
206| `12.x.x` | `16.x.x` |
207| `11.x.x` | `15.x.x` |
208| `10.x.x` | `14.x.x` |
209| `9.x.x` | `13.x.x` |
210| `8.x.x` | `12.x.x` |
211| `7.x.x` | `11.x.x` |
212| ⬆️ Starting with `ng-recaptcha@7`, only one version of Angular will be supported |
213| `6.x.x` | `6.x.x \|\| 7.x.x \|\| 8.x.x \|\| 9.x.x \|\| 10.x.x` |
214| `5.x.x` | `6.x.x \|\| 7.x.x \|\| 8.x.x` |
215| `4.x.x` | `6.x.x \|\| 7.x.x` |
216| `3.x.x` | `4.x.x \|\| 5.x.x` |
217| `2.x.x` | `2.x.x \|\| 4.x.x` |
218| `1.x.x` | `2.x.x` |
219
220## <a name="examples"></a>Examples
221
222### <a name="example-global-config"></a>Configuring the component globally [(see in action)](https://dethariel.github.io/ng-recaptcha/global-config)
223
224Some properties are global - including `siteKey`, `size`, and others. You can provide them at the module-level using the `RECAPTCHA_SETTINGS` provider:
225
226```typescript
227import { RECAPTCHA_SETTINGS, RecaptchaSettings } from "ng-recaptcha";
228
229@NgModule({
230 providers: [
231 {
232 provide: RECAPTCHA_SETTINGS,
233 useValue: { siteKey: "<YOUR_KEY>" } as RecaptchaSettings,
234 },
235 ],
236})
237export class MyModule {}
238```
239
240Global properties can be overridden on a case-by-case basis - the values on the `<re-captcha>` component itself take precedence over global settings.
241
242### <a name="example-language"></a>Specifying a different language [(see in action)](https://dethariel.github.io/ng-recaptcha/basic?lang-fr)
243
244`<re-captcha>` supports various languages. By default recaptcha will guess the user's language itself
245(which is beyond the scope of this lib).
246But you can override this behavior and provide a specific language to use by setting the `"hl"` search param in the `onBeforeLoad` hook.
247Note, that the language setting is **global**, and cannot be set on a per-captcha basis.
248
249A good way to synchronize reCAPTCHA language with the rest of your application is relying on `LOCALE_ID` value like so:
250
251```typescript
252import { LOCALE_ID } from "@angular/core";
253import { RECAPTCHA_LOADER_OPTIONS } from "ng-recaptcha";
254
255@NgModule({
256 providers: [
257 {
258 provide: RECAPTCHA_LOADER_OPTIONS,
259 useFactory: (locale: string) => ({
260 onBeforeLoad(url) {
261 url.searchParams.set("hl", locale);
262
263 return { url };
264 },
265 }),
266 deps: [LOCALE_ID],
267 },
268 ],
269})
270export class MyModule {}
271```
272
273Alternatively, a specific language can be provided like so:
274
275```typescript
276import { RECAPTCHA_LOADER_OPTIONS } from "ng-recaptcha";
277
278@NgModule({
279 providers: [
280 {
281 provide: RECAPTCHA_LOADER_OPTIONS,
282 useValue: {
283 onBeforeLoad(url) {
284 url.searchParams.set("hl", "fr"); // use French language
285
286 return { url };
287 },
288 },
289 },
290 ],
291})
292export class MyModule {}
293```
294
295You can find the list of supported languages in [reCAPTCHA docs](https://developers.google.com/recaptcha/docs/language).
296
297### <a name="example-error-handling"></a>Handling errors
298
299Sometimes reCAPTCHA encounters an error, which is usually a network connectivity problem. It cannot continue until connectivity is restored. By default, reCAPTCHA lets the user know that an error has happened (it's a built-in functionality of reCAPTCHA itself, and this lib is not in control of it). The downside of such behavior is that you, as a developer, don't get notified about this in any way. Opting into such notifications is easy, but comes at a cost of assuming responsibility for informing the user that they should retry. Here's how you would do this:
300
301```typescript
302import { Component } from "@angular/core";
303
304@Component({
305 selector: "my-app",
306 template: `<re-captcha (resolved)="resolved($event)" (errored)="errored($event)" errorMode="handled"></re-captcha>`,
307})
308export class MyApp {
309 resolved(captchaResponse: string) {
310 console.log(`Resolved captcha with response: ${captchaResponse}`);
311 }
312
313 errored() {
314 console.warn(`reCAPTCHA error encountered`);
315 }
316}
317```
318
319You can see this in action by navigating to either [basic example demo](https://dethariel.github.io/ng-recaptcha/basic) or [invisible demo](https://dethariel.github.io/ng-recaptcha/invisible) and trying to interact with reCAPTCHA after setting the network to "Offline".
320
321The `errorMode` input has two possible values -- `"handled"` and `"default"`, with latter being the default as the name suggests. Not specifying `errorMode`, or setting it to anything other than `"handled"` will not invoke your `(errored)` callback, and will instead result in default reCAPTCHA functionality.
322
323The `(errored)` callback will propagate all of the parameters that it receives from `grecaptcha['error-callback']` (which might be none) as an array.
324
325### <a name="example-preload-api"></a>Loading the reCAPTCHA API by yourself [(see in action)](https://dethariel.github.io/ng-recaptcha/v8/preload-api)
326
327By default, the component assumes that the reCAPTCHA API loading will be handled
328by the `RecaptchaLoaderService`. However, you can override that by providing your
329instance of this service to the Angular DI.
330
331The below code snippet is an example of how such a provider can be implemented.
332
333**TL;DR**: there should be an `Observable` that eventually resolves to a
334`grecaptcha`-compatible object (e.g. `grecaptcha` itself).
335
336```html
337<script src="https://www.google.com/recaptcha/api.js?render=explicit&amp;onload=onloadCallback"></script>
338
339<script>
340 // bootstrap the application once the reCAPTCHA api has loaded
341 function onloadCallback() {
342 System.import("app").catch(function (err) {
343 console.error(err);
344 });
345 }
346</script>
347```
348
349```typescript
350import { RecaptchaLoaderService } from "ng-recaptcha";
351
352@Injectable()
353export class PreloadedRecaptchaAPIService {
354 public ready: Observable<ReCaptchaV2.ReCaptcha>;
355
356 constructor() {
357 let readySubject = new BehaviorSubject<ReCaptchaV2.ReCaptcha>(grecaptcha);
358 this.ready = readySubject.asObservable();
359 }
360}
361
362@NgModule({
363 providers: [
364 {
365 provide: RecaptchaLoaderService,
366 useValue: new PreloadedRecaptchaAPIService(),
367 },
368 ],
369})
370export class MyModule {}
371```
372
373### <a name="example-forms"></a>Usage with `required` in forms [(see in action)](https://dethariel.github.io/ng-recaptcha/forms)
374
375It's very easy to put `<re-captcha>` in an Angular form and have it `require`d - just
376add the `required` attribute to the `<re-captcha>` element. Do not forget to import `RecaptchaFormsModule` from `'ng-recaptcha'`!
377
378```typescript
379@Component({
380 selector: "my-form",
381 template: ` <form>
382 <re-captcha [(ngModel)]="formModel.captcha" name="captcha" required siteKey="YOUR_SITE_KEY"></re-captcha>
383 </form>`,
384})
385export class MyForm {
386 formModel = new MyFormModel();
387}
388```
389
390A similar approach can be taken for reactive forms:
391
392```typescript
393@Component({
394 selector: "my-reactive-form",
395 template: `
396 <form [formGroup]="reactiveForm">
397 <re-captcha formControlName="recaptchaReactive"></re-captcha>
398 <button [disabled]="reactiveForm.invalid">Submit</button>
399 </form>
400 `,
401})
402export class MyReactiveForm {
403 reactiveForm: FormGroup;
404
405 ngOnInit() {
406 this.reactiveForm = new FormGroup({
407 recaptchaReactive: new FormControl(null, Validators.required),
408 });
409 }
410}
411```
412
413### <a name="example-invisible"></a>Working with invisible reCAPTCHA [(see in action)](https://dethariel.github.io/ng-recaptcha/invisible)
414
415Working with [invisible reCAPTCHA](https://developers.google.com/recaptcha/docs/invisible) is almost the same as with regular one.
416First, you need to provide the right size:
417
418```html
419<re-captcha size="invisible" ...></re-captcha>
420```
421
422You will also need to invoke the [`"execute()"`](https://developers.google.com/recaptcha/docs/invisible#programmatic_execute) method manually. This can be done by either obtaining a reference to `RecaptchaComponent` via `@ViewChild()`, or by using inline template reference:
423
424```html
425<re-captcha #captchaRef="reCaptcha" ...></re-captcha>
426...
427<button (click)="captchaRef.execute()">Submit</button>
428```
429
430Normally you would only submit a form when recaptcha response has been received. This can be achieved by reacting to `(resolved)` event and invoking submit logic when the captcha response is truthy (this will not try to submit the form when recaptcha response has expired). A sample implementation would look like this:
431
432```typescript
433@Component({
434 selector: "my-form",
435 template: ` <form>
436 <re-captcha
437 #captchaRef="reCaptcha"
438 siteKey="YOUR_SITE_KEY"
439 size="invisible"
440 (resolved)="$event && submit($event)"
441 ></re-captcha>
442 <button (click)="captchaRef.execute()">Submit</button>
443 </form>`,
444})
445export class MyForm {
446 public submit(captchaResponse: string): void {
447 this.http.post({
448 captcha: captchaResponse,
449 /* ... */
450 });
451 }
452}
453```
454
455### <a name="example-resizing"></a>Resizing
456
457Making reCAPTCHA responsive is sometimes necessary, especially when working with mobile devices. You can use css-transforms to achieve that as in [this StackOverflow answer](https://stackoverflow.com/a/29521983/2645305), which is also ell-described in [this blog post](https://geekgoddess.com/how-to-resize-the-google-nocaptcha-recaptcha/). You can also take a look at a [live example](https://stackblitz.com/edit/ng-recaptcha-example-uncvxq?file=src/app/app.component.html) of how this might be implemented. This boils down to
458
459```html
460<div style="transform:scale(0.7);transform-origin:0;">
461 <re-captcha></re-captcha>
462</div>
463```
464
465### <a name="example-systemjs"></a>SystemJS configuration
466
467To configure the package to work with SystemJS, you would configure it approximately like that (assuming you've installed `ng-recaptcha` using `npm`):
468
469```javascript
470// SystemJS config file
471(function () {
472 System.config({
473 paths: {
474 "npm:": "/node_modules/",
475 },
476 map: {
477 "ng-recaptcha": "npm:ng-recaptcha",
478 },
479 packages: {
480 "ng-recaptcha": { main: "./index.js" },
481 },
482 });
483})();
484```
485
486### <a name="example-different-url"></a>Loading from a different location
487
488Since `"google.com"` domain might be unavailable in some countries, reCAPTCHA core team has a solution for that - using `"recaptcha.net"` domain. You can configure the component to use that by using the `onBeforeLoad` hook of `RECAPTCHA_LOADER_OPTIONS`, for example:
489
490```javascript
491import { RECAPTCHA_LOADER_OPTIONS } from "ng-recaptcha";
492
493@NgModule({
494 providers: [
495 {
496 provide: RECAPTCHA_LOADER_OPTIONS,
497 useValue: {
498 onBeforeLoad(_url) {
499 return {
500 url: new URL("https://www.recaptcha.net/recaptcha/api.js"), // use recaptcha.net script source for some of our users
501 };
502 },
503 },
504 },
505 ],
506})
507export class MyModule {}
508```
509
510### <a name="example-csp-nonce"></a>Specifying nonce for Content-Security-Policy
511
512Per [reCAPTCHA FAQ on CSP](https://developers.google.com/recaptcha/docs/faq#im-using-content-security-policy-csp-on-my-website-how-can-i-configure-it-to-work-with-recaptcha), the recommended approach for that is to supply nonce to the script tag. This is possible by providing the nonce as part of the `onBeforeLoad` hook of `RECAPTCHA_LOADER_OPTIONS`, for example
513
514```javascript
515import { RECAPTCHA_LOADER_OPTIONS } from "ng-recaptcha";
516
517@NgModule({
518 providers: [
519 {
520 provide: RECAPTCHA_LOADER_OPTIONS,
521 useValue: {
522 onBeforeLoad(_url) {
523 return {
524 url,
525 nonce: "<YOUR_NONCE_VALUE>",
526 };
527 },
528 },
529 },
530 ],
531})
532export class MyModule {}
533```
534
535### <a name="example-v3-all-actions"></a>Listening for all actions with reCAPTCHA v3
536
537More often than not you will need to only get a reCAPTCHA token with the action the user is currently taking, and submit it to the backend at that time. However, having a single listener for all events will be desirable.
538
539There is an `Observable` exactly for that purpose: `ReCaptchaV3Service.onExecute`. It emits a value every time a token is received from reCAPTCHA. The shape of payload it operates on is defined via `OnExecuteData` interface:
540
541```ts
542interface OnExecuteData {
543 action: string;
544 token: string;
545}
546```
547
548where `action` is the name of the action that has been executed, and `token` is what reCAPTCHA v3 provided when executing that action.
549
550Here's how you would potentially set this up:
551
552```ts
553import { OnExecuteData, ReCaptchaV3Service } from "ng-recaptcha";
554
555@Component({
556 selector: "my-component",
557 templateUrl: "./v3-demo.component.html",
558})
559export class MyComponent implements OnInit, OnDestroy {
560 private subscription: Subscription;
561
562 constructor(private recaptchaV3Service: ReCaptchaV3Service) {}
563
564 public ngOnInit() {
565 this.subscription = this.recaptchaV3Service.onExecute.subscribe((data: OnExecuteData) => {
566 this.handleRecaptchaExecute(data.action, data.token);
567 });
568 }
569
570 public ngOnDestroy() {
571 if (this.subscription) {
572 this.subscription.unsubscribe();
573 }
574 }
575}
576```
577
578There are a couple things to keep in mind:
579
580- `onExecute` will trigger for **all** actions. If you only need to bulk-process some actions, and not others - you will have to apply filtering yourself.
581- `onExecute` observable will provide you with all the events emitted **after** you have subscribed to it - it doesn't keep references to the previously emitted actions. So make sure you add such a subscription as early in your code as you feel is necessary.
582- `onExecute` does not emit anything for when a `grecaptcha` error occurs. Use `onExecuteError` Observable for that.
583
584### <a name="async-config-load"></a>Loading reCAPTCHA keys asynchronously
585
586If your use-case needs to load the reCAPTCHA v2/v3 key from the backend (as opposed to specifying it in-code during build time), the Angular-idiomatic way to do that is by relying on [`APP_INITIALIZER`](https://angular.io/api/core/APP_INITIALIZER). You can find an example of how this could look like below, and you can also consult the source code for the demo site.
587
588```ts
589// config.service.ts
590import { Injectable } from "@angular/core";
591
592@Injectable({
593 providedIn: "root",
594})
595export class ConfigService {
596 public recaptchaSiteKeyV2: string | null = null;
597 public recaptchaSiteKeyV3: string | null = null;
598
599 public async loadConfig(): Promise<void> {
600 const { siteKeyV2, siteKeyV3 } = await fetchConfig(/* some API call */);
601 this.recaptchaSiteKeyV2 = siteKeyV2;
602 this.recaptchaSiteKeyV3 = siteKeyV3;
603 }
604}
605
606// app.module.ts
607import { APP_INITIALIZER, NgModule } from "@angular/core";
608import { RECAPTCHA_SETTINGS, RecaptchaSettings, RECAPTCHA_V3_SITE_KEY } from "ng-recaptcha";
609
610import { ConfigService } from "./config.service";
611
612function appLoadFactory(config: ConfigService) {
613 return () => config.loadConfig().then(() => console.log(`config resolved`, config));
614}
615
616@NgModule({
617 providers: [
618 {
619 provide: RECAPTCHA_V3_SITE_KEY,
620 useFactory: (config: ConfigService) => {
621 return config.recaptchaSiteKeyV3;
622 },
623 deps: [ConfigService],
624 },
625 {
626 provide: RECAPTCHA_SETTINGS,
627 useFactory: (config: ConfigService): RecaptchaSettings => {
628 return { siteKey: config.recaptchaSiteKeyV2 };
629 },
630 deps: [ConfigService],
631 },
632 {
633 provide: APP_INITIALIZER,
634 useFactory: appLoadFactory,
635 deps: [ConfigService],
636 multi: true,
637 },
638 ],
639})
640export class AppModule {}
641```
642
643### <a name="hide-recaptcha-badge"></a>Hiding reCAPTCHA badge
644
645To start with, this is not strictly under `ng-recaptcha` library control.
646However, there is a way of doing so (albeit subject to certain conditions).
647Please refer to the [FAQ section of reCAPTCHA documentation](https://developers.google.com/recaptcha/docs/faq#id-like-to-hide-the-recaptcha-badge.-what-is-allowed) to get an idea of what you're required to do.