Skip to content

Latest commit

 

History

History
665 lines (536 loc) · 19.5 KB

README.md

File metadata and controls

665 lines (536 loc) · 19.5 KB

Ngx-Matomo

Matomo (fka. Piwik) client for Angular applications. Compatible with Matomo 3 or 4 and Angular 9-12.

Angular 12 NPM latest version CircleCI Coverage Status MIT license code style: prettier semantic-release

Dependencies

NgxMatomo Angular Matomo
1.x 9.x to 12.x Matomo 3 or 4

Installation

npm install --save @ngx-matomo/tracker@^1

Optionally, if you use Angular router and want to easily track routed components, you may also install the NgxMatomo router adapter (see documentation below):

npm install --save @ngx-matomo/router@^1

Setup

NgxMatomo is able to include Matomo's script for you. You don't need to copy/paste the tracking code into your application. If you still really want to include the tracking code yourself, see the explanations below.

NgxMatomo is also able to integrate with Angular Router, so you don't need any explicit call to track page views.

Basic setup

Add NgxMatomoTrackerModule module into your application:

import { NgModule } from '@angular/core';
import { NgxMatomoTrackerModule } from '@ngx-matomo/tracker';

@NgModule({
  imports: [
    // ...
    NgxMatomoTrackerModule.forRoot({
      siteId: 'YOUR_MATOMO_SITE_ID', // your Matomo's site ID (find it in your Matomo's settings)
      trackerUrl: 'YOUR_MATOMO_SERVER_URL', // your matomo server root url
    }),
  ],
  // ...
})
export class AppModule {}

Setup Angular Router integration

First follow steps described in the previous section. Then add NgxMatomoRouterModule module into your application:

import { NgModule } from '@angular/core';
import { NgxMatomoRouterModule } from '@ngx-matomo/router';
import { NgxMatomoTrackerModule } from '@ngx-matomo/tracker';

@NgModule({
  imports: [
    // ...
    NgxMatomoTrackerModule.forRoot({
      siteId: 'YOUR_MATOMO_SITE_ID', // your Matomo's site ID (find it in your Matomo's settings)
      trackerUrl: 'YOUR_MATOMO_SERVER_URL', // your matomo server root url
    }),
    NgxMatomoRouterModule, // Add this
  ],
  // ...
})
export class AppModule {}

Setup manually with script tag

Insert Matomo tracking code into your application as explained here.

Add NgxMatomoTrackerModule module into your application, specifying the MANUAL setup mode:

import { NgModule } from '@angular/core';
import { MatomoInitializationMode, NgxMatomoTrackerModule } from '@ngx-matomo/tracker';

@NgModule({
  // ...
  imports: [
    // ...
    NgxMatomoTrackerModule.forRoot({
      mode: MatomoInitializationMode.MANUAL,
    }),
  ],
  // ...
})
export class AppModule {}

Usage

Tracking page view (with Angular Router & NgxMatomoRouterModule)

NgxMatomoRouterModule automatically tracks page views for you after each successful Angular Router navigation event, detecting current page url & title. Under the hood, it calls trackPageView, setCustomUrl and setReferrerUrl for you.

By default, page title is grabbed from DOM document title and page url is built from Router url prepended with application base href. This is fully customizable as described below. Before defining custom services, please consider MatomoRouterConfiguration options.

Customize page title

You may provide a custom service to return current page title:

import { PageTitleProvider, MATOMO_PAGE_TITLE_PROVIDER } from '@ngx-matomo/router';

@NgModule({
  // ...
  providers: [
    {
      provide: MATOMO_PAGE_TITLE_PROVIDER,
      useClass: MyPageTitleProvider,
    },
  ],
})
export class AppModule {}

@Injectable()
export class MyPageTitleProvider implements PageTitleProvider {
  getCurrentPageTitle(event: NavigationEnd): Observable<string> {
    return of('Whatever you want as current page title');
  }
}

Customize page url

You may provide a custom service to return current page url:

import { PageUrlProvider, MATOMO_PAGE_URL_PROVIDER } from '@ngx-matomo/router';

@NgModule({
  // ...
  providers: [
    {
      provide: MATOMO_PAGE_URL_PROVIDER,
      useClass: MyPageUrlProvider,
    },
  ],
})
export class AppModule {}

@Injectable()
export class MyPageUrlProvider implements PageUrlProvider {
  getCurrentPageUrl(event: NavigationEnd): Observable<string> {
    return of('Whatever you want as current page url');
  }
}

Tracking page view (without Angular Router)

Call MatomoTracker.trackPageView() from wherever you want (typically from your page components). You may have to manually call setCustomUrl or setReferrerUrl.

import { Component, OnInit } from '@angular/core';
import { MatomoTracker } from '@ngx-matomo/tracker';

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.scss'],
})
export class ExampleComponent implements OnInit {
  constructor(private readonly tracker: MatomoTracker) {}

  ngOnInit() {
    this.tracker.trackPageView();

    // With custom page title
    this.tracker.trackPageView('My page title');
  }
}

Tracking simple click events in template

<!-- Simple bindings -->
<button type="button" matomoClickCategory="myCategory" matomoClickAction="myAction">
  Example #1
</button>

<!-- Dynamic bindings/interpolation are available as well -->
<div [matomoClickCategory]="'myCategory'" matomoClickAction="{{'myAction'}}">Example #2</div>

<!-- You may also provide optional Matomo's name/value -->
<button
  type="button"
  matomoClickCategory="myCategory"
  matomoClickAction="myAction"
  matomoClickName="myName"
  [matomoClickValue]="42"
>
  Example #3
</button>

Tracking any event in template

<!-- Add 'matomoTracker' directive and set some @Input() properties -->
<input
  type="text"
  matomoTracker="change"
  matomoCategory="myCategory"
  matomoAction="myAction"
  matomoName="myName"
  [matomoValue]="myValue"
/>

<!-- You may also set multiple events to listen -->
<input
  type="text"
  [matomoTracker]="['focus', 'blur']"
  matomoCategory="myCategory"
  matomoAction="myAction"
  matomoName="myName"
/>

<!-- For advanced usage, export directive as a variable and call its 'trackEvent()' method -->
<input
  type="text"
  matomoTracker
  #tracker="matomo"
  matomoCategory="myCategory"
  matomoAction="myAction"
  matomoName="myName"
  [matomoValue]="myValue"
  (change)="tracker.trackEvent()"
/>

<!-- You may also use $event object -->
<input
  type="text"
  matomoTracker
  #tracker="matomo"
  (change)="tracker.trackEvent('myCategory', 'myAction', $event.name, $event.value)"
/>

<!-- This directive is very flexible: you may set default values as @Input() and overwrite them in method call -->
<input
  type="text"
  matomoTracker
  #tracker="matomo"
  matomoCategory="myCategory"
  matomoAction="myAction"
  (focus)="tracker.trackEvent('focus')"
  (blur)="tracker.trackEvent('blur')"
/>

Tracking events from component/service

import { Component } from '@angular/core';
import { MatomoTracker } from '@ngx-matomo/tracker';

@Component({
  /* ... */
})
export class ExampleComponent {
  constructor(private readonly tracker: MatomoTracker) {}

  myMethod() {
    // Call trackEvent method
    this.tracker.trackEvent('myCategory', 'myAction');

    // With optional name & value arguments
    this.tracker.trackEvent('myCategory', 'myAction', 'name', 0);
  }
}

Using other Matomo's tracking features: Ecommerce analytics, Marketing Campaigns...

Other Matomo tracking features are available through MatomoTracker service. Please refer to Matomo documentation for details.

import { Component } from '@angular/core';
import { MatomoTracker } from '@ngx-matomo/tracker';

@Component({
  /* ... */
})
export class ExampleComponent {
  constructor(private readonly tracker: MatomoTracker) {}

  myMethod() {
    // Example of using e-commerce features:
    this.tracker.setEcommerceView('product-SKU', 'My product name', 'Product category', 999);
    this.tracker.addEcommerceItem('product-SKU');
    this.tracker.trackEcommerceCartUpdate(999);
    this.tracker.trackEcommerceOrder('order-id', 999);

    // ... many more methods are available
  }
}

Please note that some features (such as setEcommerceView) must be called before trackPageView, so be careful when using router adapter!

Disable tracking in some environments

You may want to disable tracker in dev environments to avoid tracking some unwanted usage: local dev usage, end-to-end tests...

To do so just set the disabled switch:

import { NgModule } from '@angular/core';
import { NgxMatomoTrackerModule } from '@ngx-matomo/tracker';
import { environment } from './environment';

@NgModule({
  imports: [
    // ...
    NgxMatomoTrackerModule.forRoot({
      disabled: !environment.production,
      // include here your normal Matomo config
    }),
  ],
  // ...
})
export class AppModule {}

Managing user consent: opt-in/opt-out for tracking & cookies

Matomo supports multiple options to allow requiring user consent for tracking.

To identify whether you need to ask for any consent, you need to determine whether your lawful basis for processing personal data is "Consent" or "Legitimate interest", or whether you can avoid collecting personal data altogether.

Do not track

The do not track feature is supported, just set the acceptDoNotTrack configuration option.

Please note that do-not-track setting is configured server-side! You should likely set this setting here to match you server-side configuration. In case users opt-in for do-not-track:

  • If set to true here, users will not be tracked, independently of you server-side setting.
  • If set to false here (the default), users will be tracked depending on your server setting, but tracking requests and cookies will still be created!

See official guide

Consent opt-in

By default, no consent is required. To manage consent opt-in, first set dedicated configuration option requireConsent to either MatomoConsentMode.COOKIE or MatomoConsentMode.TRACKING:

  • In the context of tracking consent no cookies will be used and no tracking request will be sent unless consent was given. As soon as consent was given, tracking requests will be sent and cookies will be used.
  • In the context of cookie consent tracking requests will be always sent. However, cookies will be only used if consent for storing and using cookies was given by the user.

See official guide

For integration with a consent opt-in form, you may want to use following MatomoTracker methods:

  • isConsentRequired()
  • setConsentGiven() / setCookieConsentGiven()
  • rememberConsentGiven(hoursToExpire?: number) / rememberCookieConsentGiven(hoursToExpire?: number)
  • forgetConsentGiven() / forgetCookieConsentGiven()
  • hasRememberedConsent() / areCookiesEnabled()
  • getRememberedConsent()

See also example below on how to create a consent form. Example below is about creating an opt-in form, but it may be easily adapted using methods listed above.

Consent opt-out

To manage consent opt-out, use dedicated methods MatomoTracker.optUserOut() and MatomoTracker.forgetUserOptOut().

A (very) simple form is provided through <matomo-opt-out-form> component.

For more advanced integration with a custom form, you may want to define your own component and use MatomoTracker methods:

<p>To opt-out, please activate the checkbox below to receive an opt-out cookie.</p>
<p>
  <label>
    <input type="checkbox" [ngModel]="optedOut$ | async" (ngModelChange)="handleChange($event)" />
    <ng-container *ngIf="optedOut$ | async; else: optedIn">
      You are currently opted out. Click here to opt in.
    </ng-container>
    <ng-template #optedIn>You are currently opted in. Click here to opt out.</ng-template>
  </label>
</p>
@Component({
  selector: 'my-opt-out-form',
  templateUrl: '...',
})
export class MatomoOptOutFormComponent {
  optedOut$: Promise<boolean>;

  constructor(private readonly tracker: MatomoTracker) {
    this.optedOut$ = tracker.isUserOptedOut();
  }

  handleChange(optOut: boolean) {
    if (optOut) {
      this.tracker.optUserOut();
    } else {
      this.tracker.forgetUserOptOut();
    }

    this.optedOut$ = this.tracker.isUserOptedOut();
  }
}

This example is adapted from official guide about how to create a custom opt-out form

Launch demo app

  1. Clone this repository
  2. Update matomoSiteId and matomoTrackerUrl in projects/demo/src/environments/environment.ts
  3. Launch the app using npm run demo. This will build and launch the app on http://localhost:4200

Note: if you can't bind to an existing Matomo server, see https://github.com/matomo-org/docker to set-up a local Matomo instance

Configuration reference

NgxMatomoTrackerModule

Configuration may be provided either in NgxMatomoTrackerModule.forRoot(...) or by adding a provider with injection token:

@NgModule({
  imports: [NgxMatomoTrackerModule],
  providers: [
    {
      provide: MATOMO_CONFIGURATION,
      useValue: {
        // ...
      } as MatomoConfiguration,
    },
  ],
})
export class AppModule {}

Available options :

interface MatomoConfiguration {
  /**
   * If set to `true` then all tracking operations become no-op
   * Note that in this case, all getter methods will return rejected Promises
   *
   * Optional
   * Default: false
   */
  disabled?: boolean;

  /**
   * Set whether tracking code should be automatically embedded or not.
   * If set to MatomoInitializationMode.MANUAL, most other option cannot be used
   *
   * Optional
   * Default: MatomoInitializationMode.AUTO
   */
  mode?: MatomoInitializationMode;

  /**
   * Your Matomo site id (may be found in your Matomo server's settings)
   *
   * Required unless "trackers" is set
   * Not available if mode is MANUAL
   */
  siteId?: number | string;

  /**
   * Your Matomo server url
   *
   * Required unless "trackers" is set
   * Not available if mode is MANUAL
   */
  trackerUrl?: string;

  /**
   * A list of multiple Matomo servers.
   * Note that tracking code will be downloaded from the FIRST tracker in the list
   *
   * Optional (mutually exclusive with the two previous options)
   * Not available if mode is MANUAL
   */
  trackers?: { siteId: number | string; trackerUrl: string }[];

  /**
   * Download Matomo tracking code from another source
   *
   * Optional
   * Default is deduced from tracker url
   * Not available if mode is MANUAL
   */
  scriptUrl?: string;

  /**
   * If set to true, will call trackPageView on application init.
   * This should probably never be used on a routed single-page application.
   *
   * Optional
   * Default: false
   */
  trackAppInitialLoad?: boolean;

  /**
   * If set to false, disable Matomo link tracking
   *
   * Optional
   * Default: true
   */
  enableLinkTracking?: boolean;

  /**
   * Set whether to not track users who opt out of tracking using <i>Do Not Track</i> setting
   *
   * Optional
   * Default: false
   */
  acceptDoNotTrack?: boolean;

  /**
   * Configure user consent requirement
   *
   * Optional
   * Default: MatomoConsentMode.NONE
   */
  requireConsent?: MatomoConsentMode;
}

NgxMatomoRouterModule

Configuration may be provided either in NgxMatomoRouterModule.forRoot(...) or by adding a provider with injection token:

@NgModule({
  imports: [NgxMatomoRouterModule],
  providers: [
    {
      provide: MATOMO_ROUTER_CONFIGURATION,
      useValue: {
        // ...
      } as MatomoRouterConfiguration,
    },
  ],
})
export class AppModule {}

Available options :

interface MatomoRouterConfiguration {
  /**
   * Set whether the application's Base Href should be prepended to current url when tracking page views.
   * Set it to false to disable this behavior.
   *
   * Optional
   * Default: true
   */
  prependBaseHref?: boolean;

  /**
   * Set whether to detect page title when tracking views.
   * By default, page title is automatically detected from DOM document title.
   * Note that if set to `false`, Matomo is likely to still use the initial
   * document title for all tracked page views.
   *
   *
   * Optional
   * Default: true
   */
  trackPageTitle?: boolean;

  /**
   * Set a delay after navigation event before page view is tracked.
   * If your document title is updated asynchronously after Router events, you may
   * have to set a delay to correctly detect document title.
   * If set to 0, tacking is still asynchronous. Set it to -1 to execute tracking synchronously
   *
   * Optional
   * Default: 0 (no delay but still asynchronous)
   *
   * See also previous sections for more advanced page title customization
   */
  delay?: number;

  /**
   * Set some url patterns to exclude from page views tracking
   *
   * Optional
   * Default: []
   */
  exclude?: string | RegExp | string[] | RegExp[];
}

Roadmap

See ROADMAP.md