ngx-matomo-client
Matomo Analytics client for Angular
Matomo is the Google Analytics alternative that protects your data and your customers' privacy.
Matomo is exempt from consent to tracking in some countries (recommended by the CNIL in France).
https://matomo.org/
Note: this library was previously distributed as @ngx-matomo/tracker
and @ngx-matomo/router
packages. Since version 5, it is now distributed as a single package ngx-matomo-client
.
Follow instructions below for how to
easily migrate.
![NPM version](https://img.shields.io/npm/v/@ngx-matomo/tracker/latest.svg?logo=npm&logoColor=fff&label=Legacy+NPM+package&color=limegreen)
Compatibility table:
Angular | ngx-matomo-client | @ngx-matomo/tracker @ngx-matomo/router | Matomo |
---|
9 to 12 | | 1.x (docs) | Matomo 3 or 4 |
13 | | 2.x (docs) | Matomo 3 or 4 |
14 | | 3.x (docs) | Matomo 3 or 4 |
15 | | 4.x (docs) | Matomo 3 or 4 |
16 | 5.x | 4.1+ (docs) (deprecated) | Matomo 3 or 4 |
![code style: prettier](https://img.shields.io/badge/code_style-prettier-limegreen.svg?logo=prettier)
Installation
Run ng add ngx-matomo-client
This will prompt you for some information such as your Matomo's server address and site ID. You can find your site ID in
Matomo admin panel.
This command will set up basic configuration into your root AppModule
(use ng add ngx-matomo-client --module [module]
to specify a different root module). You can then take a look
at configuration reference for fine-grained set-up.
If you're not using Angular CLI, follow these instructions instead
Run npm install --save ngx-matomo-client
or yarn add ngx-matomo-client
then
manually import Matomo into your Angular application:
Classic apps | Standalone apps |
---|
import { NgxMatomoModule } from 'ngx-matomo-client';
@NgModule({
imports: [
NgxMatomoModule.forRoot({
siteId: 1,
trackerUrl: 'http://my-matomo-instance',
}),
],
})
export class AppModule {}
|
import { provideMatomo } from 'ngx-matomo-client';
@NgModule({
providers: [
provideMatomo({
siteId: 1,
trackerUrl: 'http://my-matomo-instance',
}),
],
})
export class AppModule {}
|
Take a look at configuration reference for all available configuration properties.
Usage
Tracking page views
Enable automatic page view tracking by adding following configuration:
Classic apps | Standalone apps |
---|
import {
NgxMatomoModule,
NgxMatomoRouterModule
} from 'ngx-matomo-client';
@NgModule({
imports: [
NgxMatomoModule.forRoot({
}),
NgxMatomoRouterModule,
],
})
export class AppModule {}
|
import {
provideMatomo,
withRouter
} from 'ngx-matomo-client';
@NgModule({
providers: [
provideMatomo(
{},
withRouter()
),
],
})
export class AppModule {}
|
This will track every page view (using Angular Router) with basic info such as page title and page url.
If you wish to manually track page views instead, just inject MatomoTracker
and call trackPageView()
or other
desired methods (setCustomUrl
, setReferrerUrl
...):
import { MatomoTracker } from 'ngx-matomo-client';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.scss'],
})
export class ExampleComponent implements OnInit {
private readonly tracker = inject(MatomoTracker);
ngOnInit() {
this.tracker.trackPageView();
this.tracker.trackPageView('My page title');
}
}
Adding info or customizing automatic page view tracking
Using route data
- First, declare route data under
matomo
key:
const routes: Routes = [
{
path: '',
component: HomeComponent,
data: {
matomo: {
title: 'My Home Page Title',
} as MatomoRouteData,
},
},
{
path: 'hello',
component: HelloComponent,
data: {
matomo: {
title: 'My Home Page Title',
ecommerce: {
productSKU: '12345',
productName: 'French baguette',
},
} as MatomoRouteData,
},
},
];
- Then configure
ngx-matomo-client
as following:
Classic apps | Standalone apps |
---|
import {
NgxMatomoModule,
NgxMatomoRouterModule,
MatomoRouteDataInterceptor,
} from 'ngx-matomo-client';
@NgModule({
imports: [
NgxMatomoModule.forRoot({
}),
NgxMatomoRouterModule.forRoot({
interceptors: [MatomoRouteDataInterceptor],
}),
],
})
export class AppModule {}
|
import {
provideMatomo,
withRouter,
withRouteData
} from 'ngx-matomo-client';
@NgModule({
imports: [RouterModule.forRoot(routes)],
providers: [
provideMatomo(
{},
withRouter(),
withRouteData()
),
],
})
export class AppModule {}
|
Using custom interceptor
If you need custom logic to extract data, define a custom interceptor implementation:
import { MatomoRouterInterceptor, MatomoRouteInterceptorBase } from 'ngx-matomo-client';
@Injectable()
export class MySimpleInterceptor implements MatomoRouterInterceptor {
private readonly tracker = inject(MatomoTracker);
beforePageTrack(event: NavigationEnd): void {
this.tracker.setDocumentTitle('My title');
this.tracker.setEcommerceView();
}
}
@Injectable()
export class MyAsyncInterceptor extends MatomoRouteInterceptorBase<string> {
private readonly tracker = inject(MatomoTracker);
protected extractRouteData(route: ActivatedRouteSnapshot): string {
return route.paramMap.get('productId');
}
protected async processRouteData(productId: string): Promise<void> {
const product = await this.loadProductData(productId);
this.tracker.setEcommerceView(productId, product.name);
}
}
And provide it in your application:
Classic apps | Standalone apps |
---|
import {
NgxMatomoModule,
NgxMatomoRouterModule,
MatomoRouteDataInterceptor,
} from 'ngx-matomo-client';
@NgModule({
imports: [
NgxMatomoModule.forRoot({
}),
NgxMatomoRouterModule.forRoot({
interceptors: [
MySimpleInterceptor,
MyAsyncInterceptor
],
}),
],
})
export class AppModule {}
|
import {
withRouterInterceptors,
MatomoRouterInterceptor
} from 'ngx-matomo-client';
@NgModule({
providers: [
provideMatomo(
{},
withRouter(),
withRouterInterceptors([
MySimpleInterceptor,
MyAsyncInterceptor
])
),
],
})
export class AppModule {}
|
Tracking events
You can track click events directly from your templates:
<button
type="button"
matomoClickCategory="myCategory"
matomoClickAction="myAction"
matomoClickName="myName"
[matomoClickValue]="42"
>
Example for tracking button clicks
</button>
You can also track any other kind of events:
<input
type="text"
matomoTracker="change"
matomoCategory="myCategory"
matomoAction="myAction"
matomoName="myName"
[matomoValue]="myValue"
/>
<input
type="text"
[matomoTracker]="['focus', 'blur']"
matomoCategory="myCategory"
matomoAction="myAction"
matomoName="myName"
/>
<input
type="text"
matomoTracker
#tracker="matomo"
matomoCategory="myCategory"
matomoAction="myAction"
matomoName="myName"
[matomoValue]="myValue"
(change)="tracker.trackEvent()"
/>
<input
type="text"
matomoTracker
#tracker="matomo"
matomoCategory="myCategory"
matomoAction="myAction"
(focus)="tracker.trackEvent('focus')"
(blur)="tracker.trackEvent('blur')"
/>
Note for standalone components users: all ngx-matomo-client
components and directives are standalone
and can be imported where you need them. You may also want to import all of them at once using MATOMO_DIRECTIVES
.
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
Do not track feature is supported, just set acceptDoNotTrack
configuration option.
Please note that do-not-track setting is also configured server-side! You should likely set this setting here to match
your 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()
/ getRememberedCookieConsent()
See also example below on how to create a consent form. Example below is about creating an opt-out 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
Low-level API
All Matomo tracking features are available through MatomoTracker
service. Please refer
to Matomo documentation for details.
import { Component, inject } from '@angular/core';
import { MatomoTracker } from 'ngx-matomo-client';
@Component({
})
export class ExampleComponent {
private readonly tracker = inject(MatomoTracker);
myMethod() {
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);
}
}
Please note that some features (such as setEcommerceView
) must be called before
trackPageView
! You may want to take a look
at how to use interceptors.
Migration from @ngx-matomo/tracker
and @ngx-matomo/router
(version <= 4)
Starting from version 5, this library is distributed as a single package named ngx-matomo-client
instead
of @ngx-matomo/tracker
and @ngx-matomo/router
.
Run ng add ngx-matomo-client
to migrate your code automatically.
To manually migrate your code:
- In your
package.json
, replace @ngx-matomo/tracker
dependency with ngx-matomo-client
- In your
package.json
, remove @ngx-matomo/router
dependency - Replace all imports from
@ngx-matomo/tracker
or @ngx-matomo/router
with imports from ngx-matomo-client
instead.
Also, feel free to use the new NgModule
-free way of providing ngx-matomo-client
using provideMatomo()
function instead of
importing NgxMatomoModule
and NgxMatomoRouterModule
.
Configuration reference
Find all options and features here
FAQ
How to set page title?
If automatic page view tracking is enabled, then you probably have nothing to do: the page title will be detected and
sent to Matomo.
As of Angular 14, and as long as you don't set router delay
option to -1
, customizing page title by setting title
property of Angular route config is natively supported. See Angular tutorial
here: Setting the page title.
If you're not using automatic page view tracking, then call tracker.setDocumentTitle(title)
or tracker.trackPageView(title)
.
Should I include the tracking code provided by Matomo?
No, by default ngx-matomo-client
includes Matomo's tracking script for you, so you don't need to copy/paste the
tracking code into your application.
If you are not using the default configuration and set the initialization mode to MatomoInitializationMode.MANUAL
,
then
you must include the tracking code
yourself as explained on official guide.
How to 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
property to true
in your main configuration.
For example:
@NgModule({
imports: [
NgxMatomoModule.forRoot({
disabled: !environment.production,
}),
],
})
export class AppModule {}
How to exclude some routes from tracking
If you are using automatic route tracking and want to ignore some routes, use
the exclude
option of router configuration:
Classic apps | Standalone apps |
---|
@NgModule({
imports: [
NgxMatomoModule.forRoot({
}),
NgxMatomoRouterModule.forRoot({
exclude: [/some-pattern$/],
}),
],
})
export class AppModule {}
|
@NgModule({
providers: [
provideMatomo(
{},
withRouter({
exclude: [/some-pattern$/],
})
),
],
})
export class AppModule {}
|
How can I customize the inserted script tag?
By default, Matomo's script is injected using a basic script tag looking
like <script src="..." defer async type="text/javascript">
.
To customize this script tag, define a custom factory function:
import { createDefaultMatomoScriptElement } from 'ngx-matomo-client';
function myScriptFactory(scriptUrl: string, document: Document): HTMLScriptElement {
const script = createDefaultMatomoScriptElement(scriptUrl, document);
script.setAttribute('data-cookieconsent', 'statistics');
return script;
}
And provide it to your application:
Classic apps | Standalone apps |
---|
import {
MATOMO_SCRIPT_FACTORY
} from 'ngx-matomo-client';
@NgModule({
imports: [
NgxMatomoModule.forRoot({
}),
],
providers: [
{
provide: MATOMO_SCRIPT_FACTORY,
useValue: myScriptFactory
}
],
})
export class AppModule {}
|
import {
withScriptFactory
} from 'ngx-matomo-client';
@NgModule({
providers: [
provideMatomo(
{ ... },
withScriptFactory(myScriptFactory),
)
],
})
export class AppModule { }
|
Can I use ngx-matomo-client
with Server-side rendering (SSR) / Angular Universal?
ngx-matomo-client
cannot be used server-side and automatically disables itself on non-browser platforms.
Can I use ngx-matomo-client
with Tag Manager?
If your tracker configuration is embedded in JS client (e.g. from a Tag Manager variable), you don't have to set
yourself the trackerUrl
and siteId
.
During install with ng add
, leave serverUrl
and siteId
blank and provide a value for scriptUrl
.
Your configuration may look like that:
@NgModule({
imports: [
NgxMatomoModule({
scriptUrl: 'YOUR_MATOMO_SCRIPT_URL',
}),
],
})
export class AppModule {}
How to define configuration asynchronously? (HTTP fetch...)
In some case, you may want to load your trackers configuration asynchronously. To do so, set the configuration mode
to AUTO_DEFERRED
and manually call MatomoInitializerService.initializeTracker(config)
when you are ready:
@NgModule({
imports: [
NgxMatomoModule.forRoot({
mode: MatomoInitializationMode.AUTO_DEFERRED,
}),
],
providers: [
{
provide: APP_INITIALIZER,
useFactory: () => {
const http = inject(HttpClient);
const matomoInitializer = inject(MatomoInitializerService);
return () =>
http.get('/my-config').pipe(tap(config => matomoInitializer.initializeTracker(config)));
},
multi: true,
},
],
})
export class AppModule {}
All tracking instructions before initializeTracker
will be queued and sent only when this method is called.
Don't forget to call it!
If you need to asynchronously load more configuration properties, then
consider the solution described in this issue instead (which has
some drawbacks, such as delaying the application startup).
Side note: only the trackers configuration can be deferred, not all configuration properties.
This is required because some properties require to be set before any other action is tracked: for
example, requireConsent
must be set before any other tracking call and trackAppInitialLoad
should be set before
any navigation occurs.
Roadmap
See roadmap here
Contributing
See guide here
Launch demo app
- Clone this repository
- Update
matomoSiteId
and matomoTrackerUrl
in projects/demo/src/environments/environment.ts
- 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