GithubHelp home page GithubHelp logo

emmanuelroux / ngx-matomo-client Goto Github PK

View Code? Open in Web Editor NEW
68.0 4.0 13.0 7.82 MB

Matomo analytics client for Angular applications

Home Page: https://matomo.org/

License: MIT License

JavaScript 5.01% TypeScript 92.45% HTML 2.16% SCSS 0.35% Shell 0.04%
matomo angular ngx-matomo consent matomo-script analytics analytics-tracking matomo-analytics matomo-tracking matomo-web-analytics

ngx-matomo-client's Introduction

matomo-logo ngx-matomo-client
Matomo Analytics client for Angular

Angular 18  NPM latest version  MIT license  semantic-release  Sponsorship


matomo-logo
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


Compatibility table:

Matomo Angular ngx-matomo-client @ngx-matomo/tracker
@ngx-matomo/router
3 or 4 9 to 12 1.x (docs)
3 or 4 13 2.x (docs)
3 or 4 14 3.x (docs)
3 or 4 15 5.x (docs) 4.0.x (docs)
3, 4 or 5 16 5.x (docs) 4.x (docs) (deprecated)
3, 4 or 5 17 6.x
3, 4 or 5 18 6.2.x or above

build CodeQL Coverage Status code style: 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:

import { provideMatomo } from 'ngx-matomo-client';

await bootstrapApplication(RootComponent, {
  providers: [
    provideMatomo({
      siteId: 1,
      trackerUrl: 'http://my-matomo-instance',
    }),
  ],
});

Or, if you use @NgModule:

import { MatomoModule } from 'ngx-matomo-client';

@NgModule({
  imports: [
    MatomoModule.forRoot({
      siteId: 1,
      trackerUrl: 'http://my-matomo-instance',
    }),
  ],
})
export class AppModule {}

Take a look at configuration reference for all available configuration properties.

Note: in this documentation, all code examples use imports from ngx-matomo-client because this is the most common use case. If you don't have @angular/router in you application, you must import from ngx-matomo-client/core instead.

See FAQ for more details.

Usage

Tracking page views

Enable automatic page view tracking by adding withRouter() feature to provideMatomo():

import { provideMatomo, withRouter } from 'ngx-matomo-client';

await bootstrapApplication(RootComponent, {
  providers: [
    provideMatomo(
      {
        siteId: 1,
        trackerUrl: 'http://my-matomo-instance',
      },
      withRouter(),
    ),
  ],
});
See equivalent configuration with @NgModule
import { MatomoModule, MatomoRouterModule } from 'ngx-matomo-client';

@NgModule({
  imports: [
    MatomoModule.forRoot({
      siteId: 1,
      trackerUrl: 'http://my-matomo-instance',
    }),
    MatomoRouterModule,
  ],
})
export class AppModule {}

This will track every page view using Angular Router.

If you wish to manually track page views instead, 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();
  }
}

Adding info or customizing automatic page view tracking

By default, Matomo detects page title and url. Page title is read from Angular's Title service (which itself is filled with route's 'title' key) if available, or from document title. You may override defaults as described below.

Using route data

  1. Configure ngx-matomo-client to read from route data:
import { provideMatomo, withRouter, withRouteData } from 'ngx-matomo-client';

await bootstrapApplication(RootComponent, {
  providers: [
    provideMatomo(
      {
        /* ... */
      },
      withRouter(),
      withRouteData(), // Add this feature
    ),
  ],
});

By default, Matomo properties are looked-up at matomo key of Angular route data. You may define another key by providing it as an argument to withRouteData:

// provideMatomo()
withRouteData('myCustomKey');

// Route data:
const routes: Routes = [
  {
    path: 'hello',
    component: HelloComponent,
    data: {
      myCustomKey: {
        ecommerce: {
          productSKU: '12345',
        },
      } as MatomoRouteData,
    },
  },
];
See equivalent configuration with @NgModule
import { MatomoModule, MatomoRouterModule, MatomoRouteDataInterceptor } from 'ngx-matomo-client';

@NgModule({
  imports: [
    MatomoModule.forRoot({
      /* ... */
    }),
    MatomoRouterModule.forRoot({
      interceptors: [MatomoRouteDataInterceptor], // Add this configuration
    }),
  ],
  providers: [
    // Optionally, define another key to look-up at:
    {
      provide: MATOMO_ROUTE_DATA_KEY,
      useValue: 'myCustomKey',
    },
  ],
})
export class AppModule {}
  1. Then, declare route data under matomo key:
import { MatomoRouteData } from './route-data-interceptor';

const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    title: 'My home page', // <-- Matomo will use this title by default, if available
    data: {
      matomo: {
        title: 'My home page title for Matomo', // <-- You can override the title sent to Matomo
      } as MatomoRouteData,
    },
  },
  {
    path: 'hello',
    component: HelloComponent,
    title: 'My home page', // <-- Matomo will use this title if available
    data: {
      matomo: {
        ecommerce: {
          productSKU: '12345',
          productName: 'French baguette',
        },
      } as MatomoRouteData,
    },
  },

  // Data can also be retrieve asynchronously using 'resolve':
  {
    path: ':productId',
    component: ProductComponent,
    resolve: {
      matomo: async (route: ActivatedRouteSnapshot): Promise<MatomoRouteData> => {
        // Load any asynchronous data
        const product = await inject(MyProductService).loadProductData(route.params.productId);

        return {
          ecommerce: {
            productSKU: product.sku,
          },
        };
      },
    },
  },
];

Following properties are available:

Property Type
title string
ecommerce.productSKU string
ecommerce.productName string
ecommerce.productCategory string
ecommerce.price number
ecommerce.quantity number

Using custom interceptor

If you need custom logic to extract data, define a custom interceptor implementation. An interceptor may be either a function or a class:

import {
  MatomoRouterInterceptor,
  MatomoRouterInterceptorFn,
  MatomoRouteInterceptorBase,
} from 'ngx-matomo-client';

/** A simple functional interceptor */
const myInterceptorFn: MatomoRouterInterceptorFn = (event: NavigationEnd) => {
  const tracker = inject(MatomoTracker);

  tracker.setDocumentTitle('My title');
  tracker.setEcommerceView(/* ... */);
};

/** A class interceptor must implement `MatomoRouterInterceptor` */
@Injectable()
export class MySimpleInterceptor implements MatomoRouterInterceptor {
  private readonly tracker = inject(MatomoTracker);

  beforePageTrack(event: NavigationEnd): void {
    this.tracker.setDocumentTitle('My title');
    this.tracker.setEcommerceView(/* ... */);
  }
}

/**
 * For interceptors that need access to ActivatedRouteSnapshot, you may extend
 * `MatomoRouteInterceptorBase` built-in class.
 */
@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:

import { withRouterInterceptors, MatomoRouterInterceptor } from 'ngx-matomo-client';

await bootstrapApplication(RootComponent, {
  providers: [
    provideMatomo(
      {
        /* ... */
      },
      withRouter(),

      // Add interceptors here:
      withRouterInterceptors([myInterceptorFn, MySimpleInterceptor, MyAsyncInterceptor]),
    ),
  ],
});
See equivalent configuration with @NgModule
@NgModule({
  imports: [
    MatomoModule.forRoot({
      /* ... */
    }),
    MatomoRouterModule.forRoot({
      // Add interceptors here:
      interceptors: [myInterceptorFn, MySimpleInterceptor, MyAsyncInterceptor],
    }),
  ],
})
export class AppModule {}

Tracking events

You can track click events in templates using [matomoClickAction] directive:

<button
  type="button"
  matomoClickCategory="myCategory"
  matomoClickAction="myAction"
  matomoClickName="myName"
  [matomoClickValue]="42"
>
  Example for tracking button clicks
</button>
<!-- Inputs [matomoClickName] and [matomoClickValue] are optional -->

You can also track any kind of events using [matomoTracker] directive:

<!-- Tracking "change" event on an input -->
<input
  type="text"
  matomoTracker="change"
  matomoCategory="myCategory"
  matomoAction="myAction"
  matomoName="myName"
  [matomoValue]="myValue"
/>

<!-- Tracking multiple events -->
<input
  type="text"
  [matomoTracker]="['focus', 'blur']"
  matomoCategory="myCategory"
  matomoAction="myAction"
  matomoName="myName"
/>

<!-- For advanced usage, you may 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 set default values and overwrite them in method call -->
<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 'cookie' or '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

Tracker 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() {
    // 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 most features (such as setEcommerceView) must be called before trackPageView! You may want to take a look at how to use interceptors.

Plugins

Form analytics

Form Analytics support is currently experimental. Please report any bugs, and pull requests are highly appreciated!

Configuration

Form analytics plugin is supported out-of-the-box. Add withFormAnalytics() feature to provideMatomo():

import { withFormAnalytics } from 'ngx-matomo-client/form-analytics';

await bootstrapApplication(RootComponent, {
  providers: [
    provideMatomo(
      {}, // Your base configuration
      withFormAnalytics(), // Add this feature
    ),
  ],
});
See equivalent configuration with @NgModule
import { MatomoFormAnalyticsModule } from 'ngx-matomo-client/form-analytics';

@NgModule({
  imports: [
    NgxMatomoModule.forRoot({
      /* ... */
    }),
    MatomoFormAnalyticsModule,
  ],
})
export class AppModule {}

Usage

Matomo client will automatically scan for forms in your pages after each page tracking.

If some forms are dynamically added in your components on another timing, you can use matomoTrackForm or matomoTrackForms directives to track them:

<!-- Adding matomoTrackForm directive will ensure the form is always tracked -->
<form id="myForm" matomoTrackForm></form>

If the content of your form is dynamic, and you want to correctly track inner form controls, you will have to rescan the form after changes:

<form id="myForm" matomoTrackForm>
  <!-- Add matomoTrackFormField directive to ensure the form is tracked -->
  <input *ngIf="condition" matomoTrackFormField />
</form>

If a container is dynamically toggled, you can track multiple descendant forms at once by using matomoTrackForms (note the final s) on the container:

<div *ngIf="showFormsCondition" matomoTrackForms>
  <form id="myForm1">...</form>
  <form id="myForm2">...</form>
</div>

To automatically track a form submit when an element is clicked (for example a non-submit button), add matomoTrackFormSubmit on the button:

<form id="myForm" matomoTrackForm>
  <button type="button" matomoTrackFormSubmit>Non-native submit</button>
</form>

You can also inject MatomoFormAnalytics service in your components and use low-level api directly.

See official guide at https://developer.matomo.org/guides/form-analytics.

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:

  1. In your package.json, replace @ngx-matomo/tracker dependency with ngx-matomo-client
  2. In your package.json, remove @ngx-matomo/router dependency
  3. 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 use ngx-matomo-client without @angular/router?

If you don't have @angular/router in your application, you will encounter errors when declaring imports from ngx-matomo-client.

Instead, you must use imports from ngx-matomo-client/core.

This is because ngx-matomo-client is composed of two entry points:

  • ngx-matomo-client/core which contains core features and doesn't depend on @angular/router
  • ngx-matomo-client/router which brings router features and depends on @angular/router

For backward compatibility reasons, the global entrypoint ngx-matomo-client is a shorthand that re-exports both of them (thus depending on @angular/router).

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.

  • Customizing page title by setting title property of Angular route config is natively supported. See Angular tutorial here: Setting the page title. Please note this will not work if you set Matomo router delay option to -1.
  • For more complex logic, you may also define an interceptor that will call tracker.setDocumentTitle(title). See dedicated section.

If you're not using automatic page view tracking, then you should manually 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 '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:

await bootstrapApplication(RootComponent, {
  providers: [
    provideMatomo({
      /* ... */
      disabled: !environment.production,
    }),
  ],
});
See equivalent configuration with @NgModule
@NgModule({
  imports: [
    MatomoModule.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:

await bootstrapApplication(RootComponent, {
  providers: [
    provideMatomo(
      {
        /* ... */
      },
      withRouter({
        exclude: [/some-pattern$/],
      }),
    ),
  ],
});
See equivalent configuration with @NgModule
@NgModule({
  imports: [
    MatomoModule.forRoot({
      /* ... */
    }),
    MatomoRouterModule.forRoot({
      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 script factory function:

import { createDefaultMatomoScriptElement } from 'ngx-matomo-client';

const myScriptFactory: MatomoScriptFactory = (
  scriptUrl: string,
  document: Document,
): HTMLScriptElement => {
  // Option 1: create using default built-in factory
  const script = createDefaultMatomoScriptElement(scriptUrl, document);

  // Option 2: Manually create a script element
  const script = document.createElement('script');
  script.url = scriptUrl;

  // Customize what you want
  script.setAttribute('data-cookieconsent', 'statistics');

  return script;
};

And provide it to your application:

import { withScriptFactory } from 'ngx-matomo-client';

await bootstrapApplication(RootComponent, {
  providers: [
    provideMatomo(
      {
        /* ... */
      },
      withScriptFactory(myScriptFactory),
    ),
  ],
});
See equivalent configuration with @NgModule
import { MATOMO_SCRIPT_FACTORY } from 'ngx-matomo-client';

@NgModule({
  imports: [
    MatomoModule.forRoot({
      /* ... */
    }),
  ],
  providers: [
    {
      provide: MATOMO_SCRIPT_FACTORY,
      useValue: myScriptFactory,
    },
  ],
})
export class AppModule {}

Can I use ngx-matomo-client with Server-side rendering (SSR) / Angular Universal?

Yes. ngx-matomo-client automatically disables itself on non-browser platforms.

Can I use ngx-matomo-client with Tag Manager?

Yes.

In such case, 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:

import { withScriptFactory } from 'ngx-matomo-client';

await bootstrapApplication(RootComponent, {
  providers: [
    provideMatomo({
      /* ... */
      scriptUrl: 'YOUR_MATOMO_SCRIPT_URL', // your Matomo's script url
    }),
  ],
});
See equivalent configuration with @NgModule
@NgModule({
  imports: [
    MatomoModule({
      /* ... */
      scriptUrl: 'YOUR_MATOMO_SCRIPT_URL', // your Matomo's 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 'deferred' and manually call MatomoInitializerService.initializeTracker(config) when you are ready:

await bootstrapApplication(RootComponent, {
  providers: [
    provideMatomo({
      /* ... */
      mode: 'deferred',
    }),

    // Example: use an APP_INITIALIZER
    {
      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,
    },
  ],
});
See equivalent configuration with @NgModule
@NgModule({
  imports: [
    MatomoModule.forRoot({
      /* ... */
      mode: 'deferred',
    }),
  ],
  providers: [
    // Example: use an APP_INITIALIZER
    {
      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 locally 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 whole 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, trackAppInitialLoad should be set before any navigation occurs.

How can I test my components which uses MatomoTracker or other Matomo features?

Matomo can be easily mocked and tested by declaring either provideMatomoTesting() providers or MatomoTestingModule in TestBed.

All these symbols can be imported from ngx-matomo-client/testing.

Roadmap

See roadmap here

Contributing

See guide here

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

ngx-matomo-client's People

Contributors

arrakis-lux avatar emmanuelroux avatar kanidjar avatar p-aron avatar viceice avatar viserius avatar yatho avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ngx-matomo-client's Issues

Passing async siteId and trackerUrl

When importing the tracker module:

NgxMatomoTrackerModule.forRoot({ siteId: 'initialSiteId', trackerUrl: 'initialTrackerUrl'})

How can the siteId and trackerUrl first be retrieved async from a service, before matomo actually is trying to do something with these initial values?

I tried something like this:

function loadConfigurationFactory(configurationService: ConfigurationService): () => Observable<boolean> {
    return () => configurationService.configurationLoadedObservable; // this only emits when loading is complete
}

@NgModule({
    imports: [
        NgxMatomoTrackerModule.forRoot({ siteId: 'initialSiteId', trackerUrl: 'initialTrackerId' }),
        NgxMatomoRouterModule,
    ],
    providers: [
        ...
        {
            provide: APP_INITIALIZER,
            useFactory: loadConfigurationFactory,
            deps: [ConfigurationService],
            multi: true,
        }
    ]
})
export class AppModule {}

But how will I be able to set the url and site id after that??

Allow customization of script tag

Provide a way to customize the injected script tag.

Currently, it is inserted as <script src="..." defer async type="text/javascript">.

It would be great to be able to add custom attributes to script tag, such as data-cookieconsent="statistics".

Automatic page views tracking not working without .forRoot()

Since v5.0.0, NgxMatomoRouterModule is (incorrectly) required to be imported using NgxMatomoRouterModule.forRoot().

If imported using just NgxMatomoRouterModule, then automatic page view tracking is not set-up and will not track anything.

It must be fixed because calling .forRoot() should remain optional.

Issue using tracker.setUserId()

I am trying to use the tracker setUserId method to provide usernames to Matomo and have created a MatomoRouterInterceptor that looks like this:

@Injectable()
export class MatomoInterceptor implements MatomoRouterInterceptor {
  constructor(
  private readonly tracker: MatomoTracker,
    private userService: UserService
  ) { }

  beforePageTrack(event: NavigationEnd): void {
    this.tracker.setUserId(this.userService.getCurrentUser().ntid);
  }
}

Unfortunately, it does not seem to work until the second navigation within the application.
The initial entry into the app, does not include the 'uid' field in the request payload.

Also, I am getting an error in the dev console that says, which has be curious.

matomo.js:22 The method enableLinkTracking is registered more than once in "_paq" variable. Only the last call has an effect. Please have a look at the multiple Piwik trackers documentation:
 https://developer.piwik.org/guides/tracking-javascript-guide#multiple-piwik-trackers

Thanks - Al

ngx-matomo-tracker not setting trackerUrl

Good night! I am new into this product as Matomo and his libs, I am trying to integrate it into my Angular 9 application, I have this configuration:

    "@ngx-matomo/router": "^1.3.6",
    "@ngx-matomo/tracker": "^1.3.6",
    matomoUrl: 'http://localhost:81',
    matomoSiteId: '1',
        ...
        NgxMatomoTrackerModule.forRoot({
            trackerUrl: environment.matomoUrl,
            siteId: environment.matomoSiteId
        }),
        NgxMatomoRouterModule
        ...

And I can resolve correctly the matomo.js file:
image

But when it exceutes and try to send data to my matomo server it calls to http://localhost:4200 instead of
http://localhost:81/atomo.php as show below

telegram-cloud-document-4-5958331112387252932

I don´t know if is there any problem with the version 1.3.6. or I am missing some configuration but if I add the script manually to the index.html it works propperly, I couldn't find where the error could be and I hope if anyone can help me with this.

Thanks in advance

Implement matomoClickAction

Thanks for providing the ngx-matomo package, it works great!
I'm having a small problem however with implementing actions. I've used your example:

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

However when I click the button I get a 404:
GET http://localhost:4200/matomo.js net::ERR_ABORTED 404 (Not Found)

What am I missing or doing wrong? I've imported the NgxMatomoTrackerModule in the module for my page. Is there anything else I should do?

Calls to setCustomDimension() are working on init but not on event (Angular App)

Hello,

We have been noticing that call to setCustomDimension() method in order to set or update Matomo Custom Dimension are no longer working when they are linked to user's actions.

Our case : Once the application loaded, we set 2 different dimesions to our company's Matomo :

  • user profile
  • customerName (both are business infos, stored as string)

Once the user clic on a given element of the app, we were sending a 3rd Custom Dimension : "isActive". And while it worked for a while, it seams to have stop working since last week. If sending this even on the app load like the other 2, no issues happens and the dimension is set. If waiting for any user event, it doesn't.

Have you ever heard or anything similar happening within an Angular app ?
Is there any logs or reproduction details that could help for troubleshooting this ?

Looking forward hearing from you !

ps : I'm fluent in French if that can help explaining better the issue

Tracking e-commerce category page view not permitted

Tracking an e-commerce category (having only productCategory parameter) page view is not permitted, because productSKU is always required.
Only e-commerce item (with productSKU, and other optional parameters) page view are currently allowed.

Slow concurrent page tracks are discarded

If some page tracking call takes some time for some reason (such as a long async interceptor), and a new navigation occurs, the pending tracking call is cancelled.

Question about enabling/disabling tracker

Hello!

Many thanks for a great library!

The ngx-tracker works perfectly well in my standard Angular application.

I'm using Scully.io for prerendering pages and see that I have an issue with matomo triggering before the Angular application itself has booted up and initialized the tracker properly (replaced the static html generated by scully).

Scully uses the browser to prerender and in some component I've just got an if statement saying "if scullyIsRunning, return".
I'd like to do something similar with this tracker and I've seen that it's possible to disable the tracker in app.module

Is it possible to enable it run-time? :)

I have read through the readme to see if I could enable this tracker globally in some other way where I have access to the scully service.

Any thoughts?

Cookieless setup

Hi,

thank you for the helpful module.
I was wondering if it was possible to use Matomo's cookieless tracking.
When setting it up with angular it works great in standard setup and tracks my angular app, but it sets cookies although in Matomo-settings I set it to cookieless tracking. On my website cookieless tracking works without any problems.
I already tried to set the parameter 'scriptUrl' to my matomo.js, but then the app keeps on returning errors in the javascript console and reloads by itself the whole time. When entering the URL in my browser I can see the JS-file.

Any ideas how to solve this?

Thank you for your help.

Kind regards,

Sebastian

Customizing script tag not working

Application Version: Angular 13
@ngx-matomo/router: "^2.2.1"
@ngx-matomo/tracker: "^2.3.0"

TypeError: Cannot read properties of undefined (reading 'createElement')

I wanted to add "integrity" attribute on script tag for matomo.js. I tried using the way suggested in the doc

The following is the code:
`
import { NgxMatomoTrackerModule } from '@ngx-matomo/tracker';
import { NgxMatomoRouterModule } from '@ngx-matomo/router';

const getMatomoScript = (scriptUrl: string, document: Document) => {
console.log("🚀 ~ file: app.module.ts ~ line 33 ~ getMatomoScript ~ scriptUrl", scriptUrl)
console.log("🚀 ~ file: app.module.ts ~ line 31 ~ getMatomoScript ~ document", document)

const script = document.createElement('script');
script.type = 'text/javascript';
script.async = !0;
script.src = scriptUrl;
script.id = 'matomo-script';
script.integrity = 'sha256-O2UvOjz2SgGApRDh4pNxKwPxgjt7BRYgz8861kVcBLQ=';
script.crossOrigin = 'anonymous';

return script;

}

@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
AppRoutingModule,
CommonModule,
...
NgxMatomoTrackerModule.forRoot(
{
trackerUrl: environment.matomoConfig.appUrl,
siteId: environment.matomoConfig.siteId
},
getMatomoScript
),
NgxMatomoRouterModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
`
This throwing the error below:
image

Anything I am doing wrong?

Dynamic environment variables aren't properly loaded in.

Packages used:

"@ngx-matomo/router": "^3.0.0",
"@ngx-matomo/tracker": "^3.0.0",
"@elemental-concept/env-bakery": "0.0.5",
// Angular 14

I'm trying to dynamically load in environment variables into NgxMatomoTrackerModule.forRoot() to configure Matomo. For this, I'm using @elemental-concept/env-bakery to import the values from a .dotenv file. The code below is how I setup the environment variable that is used throughout my application.

export const environment = () => ({
  appVersion: require('../../package.json').version,
  production: getEnv('PRODUCTION').boolean(),
  backendUrl: getEnv('BACKEND_URL').string(),
  matomoConfig: {
    trackers: [
      {
        trackerUrl: getEnv('MATOMO_TRACKER_URL').string(),
        siteId: getEnv('MATOMO_SITE_ID').number()
      }
    ],
    skipTrackingInitialPageView: false,
    routeTracking: {
      enable: true
    }
  },
  auth: {
    issuer: getEnv('ISSUER').string(),
    clientId: getEnv('CLIENT_ID').string()
  }
});

And in the @NgModule I feed the config into the forRoot()

imports: [
    BrowserModule,
    AppRoutingModule,
    CoreModule,
    BrowserAnimationsModule,
    BreadcrumbModule,
    FtIconModule,
    MatMomentDateModule,
    // NgxMatomoTrackerModule.forRoot({ trackerUrl: 'MY_URL', siteId: '1' }), // This works.
    NgxMatomoTrackerModule.forRoot(environment().matomoConfig), // This doesn't. 
    NgxMatomoRouterModule
 ],

If I try and run this I get an error stating matomo.js cannot be found on my localhost. That's because it tries to inject the DOM script from my trackerUrl. Breakpointing on the forRoot method in the debugger, I find this:

forRoot

As you can see, it finds my custom configuration object but it just doesn't load in the custom values. In other places where I use this environment() global variable it is correctly populated with my environment variables.

The first thing my application does is 'bake' the environment variable and THEN load everything in (as seen below). Therefore I cannot see this being an issue with asynchronous actions that have yet to resolve.

bakeEnv(() => import('./environments/environment')).then((environment: any) => {
  if (environment.production) {
    enableProdMode();
  }

  platformBrowserDynamic()
    .bootstrapModule(AppModule)
    .catch(err => console.error(err));
});

Do you have any ideas how I could fix this issue?

trackerUrl required even if scriptUrl should be sufficient

I moved to. this package from another matomo tracker package (https://www.npmjs.com/package/ngx-matomo)
Previously I was only required to specify scriptUrl but after changing to this package I am required to specify both scriptUrl and trackerUrl - like this:

{
      provide: MATOMO_CONFIGURATION,
      useValue: {
        disabled: !cue.config.analyticsConfig?.enabled,
        scriptUrl: !!cue.config.analyticsConfig?.enabled
          ? 'https://product-analytics.xxxx.com/analytics/js/container_X4aTUp5k.js'
          : undefined,
        trackerUrl: !!cue.config.analyticsConfig?.enabled
          ? 'https://product-analytics.xxxx.com/analytics/'
          : undefined,
      } as MatomoConfiguration,
 },

If I only specify scriptUrl like this in my app.module

{
      provide: MATOMO_CONFIGURATION,
      useValue: {
        disabled: !cue.config.analyticsConfig?.enabled,
        scriptUrl:
          'https://product-analytics.xxxx.com/analytics/js/container_X4aTUp5k.js',
      } as MatomoConfiguration,
},

I get this error:

zone.js:372 TypeError: Cannot read properties of undefined (reading 'endsWith')
    at appendTrailingSlash (ngx-matomo-tracker.mjs:1332:16)
    at buildTrackerUrl (ngx-matomo-tracker.mjs:1336:16)
    at MatomoInitializerService.injectMatomoScript (ngx-matomo-tracker.mjs:1368:36)
    at MatomoInitializerService.init (ngx-matomo-tracker.mjs:1362:14)
    at new NgxMatomoTrackerModule (ngx-matomo-tracker.mjs:1432:30)
    at Object.NgxMatomoTrackerModule_Factory [as factory] (ngx-matomo-tracker.mjs:1446:1)
    at R3Injector.hydrate (core.mjs:11457:1)
    at R3Injector.get (core.mjs:11276:1)
    at core.mjs:11314:1
    at Set.forEach (<anonymous>)
    at R3Injector._resolveInjectorDefTypes (core.mjs:11314:1)
    at new NgModuleRef (core.mjs:21821:1)
    at NgModuleFactory.create (core.mjs:21875:1)
    at core.mjs:26016:1
    at ZoneDelegate.invoke (zone.js:372:1)
invoke @ zone.js:372
run @ zone.js:134
(anonymous) @ zone.js:1276
invokeTask @ zone.js:406
runTask @ zone.js:178
drainMicroTaskQueue @ zone.js:582
Promise.then (async)
scheduleMicroTask @ zone.js:565
scheduleTask @ zone.js:396
scheduleTask @ zone.js:221
scheduleMicroTask @ zone.js:241
scheduleResolveOrReject @ zone.js:1266
then @ zone.js:1410
bootstrapModule @ core.mjs:26067
45725 @ main.ts:11
__webpack_require__ @ bootstrap:19
__webpack_exec__ @ postcss.mjs:30
(anonymous) @ postcss.mjs:30
webpackJsonpCallback @ jsonp chunk loading:71
(anonymous) @ main.js:1

Directives in templates aren't working whereas all the rest is.

Hello

Thanks for your hard work! Love that your package provides some capabilities for async initialization.

I've set up Matomo and it works to some extent. I have some application in Angular using PrimeNG and I get the routing events, as well as the customized bits I'm passing (SSO user) with the interceptor. So far, so good, except when I'm using the directives in component templates like described in https://github.com/EmmanuelRoux/ngx-matomo#tracking-events, e.g.,

<button
  type="button"
  matomoClickCategory="myCategory"
  matomoClickAction="myAction"
  matomoClickName="myName"
  [matomoClickValue]="42"
>
  Example for tracking button clicks
</button>

=>

Can't bind to 'matomoClickValue' since it isn't a known property of 'button'.ngtsc(-998002)
whatever.component.ts(17, 4): Error occurs in the template of component WhateverComponent.

I'm wondering if you have some hints about why this would be the case?


When using for instance something like, the other approach, event-based:

*.ts code:

// ...
@Component({
})
export class WhateverComponent {
  constructor(private readonly _matomoTracker: MatomoTracker)
// ...
  public onClick() {
    this._matomoTracker.trackEvent("Export", action);
  }
// ...
}

*.html template code:

<button (click)="onClick()">  Example for tracking button clicks</button>

It works.


Notes:

Add possibility to provide a custom tracker class

First of all thanks a lot for such a useful lib! Works like a charm! 👏

I would like to use the Matomo Tag Manager and I also need to "push" other data into the _mtm variable. Perfhaps this is out of the scope of ngx-matomo and maybe what I'm going to explain below is not feasible, but who knows 😛

Currently there is no way to perform custom logic nor pushing custom data into the _mtm variable because there are only 2 trackers to use in the library: NoopMatomoTracker and StandardMatomoTracker. The latter as its name suggests, works out of the box with a standard Motomo traking workflow and uses the _paq variable.

image

I think this could be enhanced by being able to provide a custom Matomo tracker class, via the config for example, so that such class can be instantiated instead of the Noop or Standard ones.

export function createMatomoTracker(
  config: InternalMatomoConfiguration,
  platformId: Object,
  ngZone: NgZone,
): MatomoTracker {
  if (config.disabled || !isPlatformBrowser(platformId)) {
     return new NoopMatomoTracker();
  }

  return config.customTrackerClass;
    ? new config.customTrackerClass(ngZone, config)
    : new StandardMatomoTracker(ngZone, config);
}

From then on, everything should be fairly simple for the developer since the tracker class should extend the MatomoTracker abstract class as the other 2 trackers. This way any custom logic could be placed in the push() for example or in any trackXXXX() method if needed.

Not really sure if this would fit in ngx-matomo in its current state cause what I actually need is to customize data to be sent to the Tag Manager and trigger some other logic in my own app whenever such events are sent.

What do yo think?

Angular 17 Jest ReferenceError: Cannot access 'NgxMatomoRouterModule' before initialization

After updating to Angular 17 and ngx-matomo-client 6.0.0 there are problems with the unit tests of the components/service, where Matomo Directives or MatomoTracker is being used. NgxMatomoRouterModule is not being used in the app, the matomo configuration is being done through the standalone function provideMatomo() and withRouter().
The problem occurs only after updating to the version 6.0.0 of matomo. In the version 5.0.4 there are no problems.
Do you have any ideas, how we can use solve this problem?

Disable automatic send event

Hey,

I'd like to know how can we disable some events that are automatically sent to matomo. For example, I have an input with a "click" event that will redirect to a result page. I want to record result count and query term manually by using the MatomoTracker service. It works, however I have another event "search" that is recorded by default since we have a change of page with query params (the actual term searched in the bar).

My custom event (with category 'click', action 'rechercherTermes', name 'Hello' and value 15 corresponding to result count) :
image
The associated code :
image

Another one created by default, that I don't want (it's a duplicate and doesn't have the result count)
image

The same issues occurs for some button that I have, that also navigate using Angular Router and therefore creates duplicated entries that I don't need.
Thanks for the good work :)

Enable routerTracking will throw error

Below is error message:
Unhandled Promise rejection: R3InjectorError(AppModule)[MatomoModule -> MatomoRouteTracker -> Router -> Router -> Router]: NullInjectorError: No provider for Router! ; Zone: <root> ; Task: Promise.then ; Value: NullInjectorError: R3InjectorError(AppModule)[MatomoModule -> MatomoRouteTracker -> Router -> Router -> Router]: NullInjectorError: No provider for Router! at NullInjector.get (core.js:11100) at R3Injector.get (core.js:11267) at R3Injector.get (core.js:11267) at R3Injector.get (core.js:11267) at injectInjectorOnly (core.js:4751) at Module.ɵɵinject (core.js:4755) at Object.MatomoRouteTracker_Factory [as factory] (ngx-matomo.js:1919) at R3Injector.hydrate (core.js:11437) at R3Injector.get (core.js:11256) at new MatomoModule (ngx-matomo.js:1961) NullInjectorError: R3InjectorError(AppModule)[MatomoModule -> MatomoRouteTracker -> Router -> Router -> Router]: NullInjectorError: No provider for Router! at NullInjector.get (http://localhost:4200/vendor.js:27658:27) at R3Injector.get (http://localhost:4200/vendor.js:27825:33) at R3Injector.get (http://localhost:4200/vendor.js:27825:33) at R3Injector.get (http://localhost:4200/vendor.js:27825:33) at injectInjectorOnly (http://localhost:4200/vendor.js:21309:33) at Module.ɵɵinject (http://localhost:4200/vendor.js:21313:61) at Object.MatomoRouteTracker_Factory [as factory] (http://localhost:4200/vendor.js:233002:308) at R3Injector.hydrate (http://localhost:4200/vendor.js:27995:35) at R3Injector.get (http://localhost:4200/vendor.js:27814:33) at new MatomoModule (http://localhost:4200/vendor.js:233044:27)
Use npm install is ok for me but use yarn install will throw this error

Logging on secondary siteId

Im not sure if its the right place to ask for a feature, or if its allready possible. :-)
The Matomo site script has a feature to log on a secondary siteId.
But is this possible in ngx-matomo? or is it af feature that have been thought about.

Uncaught TypeError: (0 , tslib__WEBPACK_IMPORTED_MODULE_5__.__param) is not a function

When adding ngx-matomo to my angular 14 solution I am unable to load my site because of the error below:

NgxMatomoRouterModule is the culprit, the NgxMatomoTrackerModule is loading fine

Uncaught TypeError: (0 , tslib__WEBPACK_IMPORTED_MODULE_5__.__param) is not a function
at 54392 (ngx-matomo-router.mjs:87:12)

minified by webpack:
DefaultPageUrlProvider = __decorate([
__param(0, Optional()),
__param(0, Inject(INTERNAL_ROUTER_CONFIGURATION)),
__param(1, Optional()),
__param(1, Inject(APP_BASE_HREF))
], DefaultPageUrlProvider);

Current code:
export class DefaultPageUrlProvider implements PageUrlProvider {
constructor(
@optional()
@Inject(INTERNAL_ROUTER_CONFIGURATION)
private readonly config: InternalRouterConfiguration,
@optional() @Inject(APP_BASE_HREF) private readonly baseHref: string | null,
private readonly platformLocation: PlatformLocation
) {}

Why yet another ngx-matomo?

Hey @EmmanuelRoux! I have just came across your fantastic library but I struggle to answer myself a question: why have you started yet another ngx-matomo?

Is it because the original ngx-matomo is orphaned and no longer maintained? I tried adopting it but I failed and ended up using RC version which was still far from perfect. I would like to know your story and commitment to maintaining this better ngx-matomo because it looks very promising.

export 'map' (imported as 'map') was not found in 'rxjs' (and other rxjs related import issues)

Hello there, thank you for your integration of Matomo for Angular app.

When trying to install it in my company's app, I am face with multiple errors while trying to build the application.
All the errors are related to rxjs and its dependencies.

I attached below the errors that are shown in my terminal : (the command was npm run build, on a Angular 13 app).

Any idea why those errors are showing? Is there a workaround?

Thank you so much in advance

`./node_modules/@ngx-matomo/router/fesm2020/ngx-matomo-router.mjs:192:57-60 - Error: export 'map' (imported as 'map') was not found in 'rxjs' (possible exports: ArgumentOutOfRangeError, AsyncSubject, BehaviorSubject, ConnectableObservable, EMPTY, EmptyError, GroupedObservable, NEVER, Notification, NotificationKind, ObjectUnsubscribedError, Observable, ReplaySubject, Scheduler, Subject, Subscriber, Subscription, TimeoutError, UnsubscriptionError, VirtualAction, VirtualTimeScheduler, animationFrameScheduler, asapScheduler, asyncScheduler, bindCallback, bindNodeCallback, combineLatest, concat, config, defer, empty, forkJoin, from, fromEvent, fromEventPattern, generate, identity, iif, interval, isObservable, merge, never, noop, observable, of, onErrorResumeNext, pairs, partition, pipe, queueScheduler, race, range, scheduled, throwError, timer, using, zip)

./node_modules/@ngx-matomo/router/fesm2020/ngx-matomo-router.mjs:200:8-17 - Error: export 'concatMap' (imported as 'concatMap') was not found in 'rxjs' (possible exports: ArgumentOutOfRangeError, AsyncSubject, BehaviorSubject, ConnectableObservable, EMPTY, EmptyError, GroupedObservable, NEVER, Notification, NotificationKind, ObjectUnsubscribedError, Observable, ReplaySubject, Scheduler, Subject, Subscriber, Subscription, TimeoutError, UnsubscriptionError, VirtualAction, VirtualTimeScheduler, animationFrameScheduler, asapScheduler, asyncScheduler, bindCallback, bindNodeCallback, combineLatest, concat, config, defer, empty, forkJoin, from, fromEvent, fromEventPattern, generate, identity, iif, interval, isObservable, merge, never, noop, observable, of, onErrorResumeNext, pairs, partition, pipe, queueScheduler, race, range, scheduled, throwError, timer, using, zip)

./node_modules/@ngx-matomo/router/fesm2020/ngx-matomo-router.mjs:203:52-55 - Error: export 'tap' (imported as 'tap') was not found in 'rxjs' (possible exports: ArgumentOutOfRangeError, AsyncSubject, BehaviorSubject, ConnectableObservable, EMPTY, EmptyError, GroupedObservable, NEVER, Notification, NotificationKind, ObjectUnsubscribedError, Observable, ReplaySubject, Scheduler, Subject, Subscriber, Subscription, TimeoutError, UnsubscriptionError, VirtualAction, VirtualTimeScheduler, animationFrameScheduler, asapScheduler, asyncScheduler, bindCallback, bindNodeCallback, combineLatest, concat, config, defer, empty, forkJoin, from, fromEvent, fromEventPattern, generate, identity, iif, interval, isObservable, merge, never, noop, observable, of, onErrorResumeNext, pairs, partition, pipe, queueScheduler, race, range, scheduled, throwError, timer, using, zip)

./node_modules/@ngx-matomo/router/fesm2020/ngx-matomo-router.mjs:216:32-36 - Error: export 'take' (imported as 'take') was not found in 'rxjs' (possible exports: ArgumentOutOfRangeError, AsyncSubject, BehaviorSubject, ConnectableObservable, EMPTY, EmptyError, GroupedObservable, NEVER, Notification, NotificationKind, ObjectUnsubscribedError, Observable, ReplaySubject, Scheduler, Subject, Subscriber, Subscription, TimeoutError, UnsubscriptionError, VirtualAction, VirtualTimeScheduler, animationFrameScheduler, asapScheduler, asyncScheduler, bindCallback, bindNodeCallback, combineLatest, concat, config, defer, empty, forkJoin, from, fromEvent, fromEventPattern, generate, identity, iif, interval, isObservable, merge, never, noop, observable, of, onErrorResumeNext, pairs, partition, pipe, queueScheduler, race, range, scheduled, throwError, timer, using, zip)

./node_modules/@ngx-matomo/router/fesm2020/ngx-matomo-router.mjs:216:41-55 - Error: export 'defaultIfEmpty' (imported as 'defaultIfEmpty') was not found in 'rxjs' (possible exports: ArgumentOutOfRangeError, AsyncSubject, BehaviorSubject, ConnectableObservable, EMPTY, EmptyError, GroupedObservable, NEVER, Notification, NotificationKind, ObjectUnsubscribedError, Observable, ReplaySubject, Scheduler, Subject, Subscriber, Subscription, TimeoutError, UnsubscriptionError, VirtualAction, VirtualTimeScheduler, animationFrameScheduler, asapScheduler, asyncScheduler, bindCallback, bindNodeCallback, combineLatest, concat, config, defer, empty, forkJoin, from, fromEvent, fromEventPattern, generate, identity, iif, interval, isObservable, merge, never, noop, observable, of, onErrorResumeNext, pairs, partition, pipe, queueScheduler, race, range, scheduled, throwError, timer, using, zip)

./node_modules/@ngx-matomo/router/fesm2020/ngx-matomo-router.mjs:217:19-24 - Error: export 'mapTo' (imported as 'mapTo') was not found in 'rxjs' (possible exports: ArgumentOutOfRangeError, AsyncSubject, BehaviorSubject, ConnectableObservable, EMPTY, EmptyError, GroupedObservable, NEVER, Notification, NotificationKind, ObjectUnsubscribedError, Observable, ReplaySubject, Scheduler, Subject, Subscriber, Subscription, TimeoutError, UnsubscriptionError, VirtualAction, VirtualTimeScheduler, animationFrameScheduler, asapScheduler, asyncScheduler, bindCallback, bindNodeCallback, combineLatest, concat, config, defer, empty, forkJoin, from, fromEvent, fromEventPattern, generate, identity, iif, interval, isObservable, merge, never, noop, observable, of, onErrorResumeNext, pairs, partition, pipe, queueScheduler, race, range, scheduled, throwError, timer, using, zip)

./node_modules/@ngx-matomo/router/fesm2020/ngx-matomo-router.mjs:217:37-51 - Error: export 'defaultIfEmpty' (imported as 'defaultIfEmpty') was not found in 'rxjs' (possible exports: ArgumentOutOfRangeError, AsyncSubject, BehaviorSubject, ConnectableObservable, EMPTY, EmptyError, GroupedObservable, NEVER, Notification, NotificationKind, ObjectUnsubscribedError, Observable, ReplaySubject, Scheduler, Subject, Subscriber, Subscription, TimeoutError, UnsubscriptionError, VirtualAction, VirtualTimeScheduler, animationFrameScheduler, asapScheduler, asyncScheduler, bindCallback, bindNodeCallback, combineLatest, concat, config, defer, empty, forkJoin, from, fromEvent, fromEventPattern, generate, identity, iif, interval, isObservable, merge, never, noop, observable, of, onErrorResumeNext, pairs, partition, pipe, queueScheduler, race, range, scheduled, throwError, timer, using, zip)

./node_modules/@ngx-matomo/router/fesm2020/ngx-matomo-router.mjs:227:105-108 - Error: export 'tap' (imported as 'tap') was not found in 'rxjs' (possible exports: ArgumentOutOfRangeError, AsyncSubject, BehaviorSubject, ConnectableObservable, EMPTY, EmptyError, GroupedObservable, NEVER, Notification, NotificationKind, ObjectUnsubscribedError, Observable, ReplaySubject, Scheduler, Subject, Subscriber, Subscription, TimeoutError, UnsubscriptionError, VirtualAction, VirtualTimeScheduler, animationFrameScheduler, asapScheduler, asyncScheduler, bindCallback, bindNodeCallback, combineLatest, concat, config, defer, empty, forkJoin, from, fromEvent, fromEventPattern, generate, identity, iif, interval, isObservable, merge, never, noop, observable, of, onErrorResumeNext, pairs, partition, pipe, queueScheduler, race, range, scheduled, throwError, timer, using, zip)

./node_modules/@ngx-matomo/router/fesm2020/ngx-matomo-router.mjs:230:70-73 - Error: export 'tap' (imported as 'tap') was not found in 'rxjs' (possible exports: ArgumentOutOfRangeError, AsyncSubject, BehaviorSubject, ConnectableObservable, EMPTY, EmptyError, GroupedObservable, NEVER, Notification, NotificationKind, ObjectUnsubscribedError, Observable, ReplaySubject, Scheduler, Subject, Subscriber, Subscription, TimeoutError, UnsubscriptionError, VirtualAction, VirtualTimeScheduler, animationFrameScheduler, asapScheduler, asyncScheduler, bindCallback, bindNodeCallback, combineLatest, concat, config, defer, empty, forkJoin, from, fromEvent, fromEventPattern, generate, identity, iif, interval, isObservable, merge, never, noop, observable, of, onErrorResumeNext, pairs, partition, pipe, queueScheduler, race, range, scheduled, throwError, timer, using, zip)

./node_modules/@ngx-matomo/router/fesm2020/ngx-matomo-router.mjs:233:50-53 - Error: export 'map' (imported as 'map') was not found in 'rxjs' (possible exports: ArgumentOutOfRangeError, AsyncSubject, BehaviorSubject, ConnectableObservable, EMPTY, EmptyError, GroupedObservable, NEVER, Notification, NotificationKind, ObjectUnsubscribedError, Observable, ReplaySubject, Scheduler, Subject, Subscriber, Subscription, TimeoutError, UnsubscriptionError, VirtualAction, VirtualTimeScheduler, animationFrameScheduler, asapScheduler, asyncScheduler, bindCallback, bindNodeCallback, combineLatest, concat, config, defer, empty, forkJoin, from, fromEvent, fromEventPattern, generate, identity, iif, interval, isObservable, merge, never, noop, observable, of, onErrorResumeNext, pairs, partition, pipe, queueScheduler, race, range, scheduled, throwError, timer, using, zip)`

Load initial configuration async?

Is it currently possible to load the Site ID and Tracker URL in an async manner?

I have an Angular 10 project that stores every config in a database, and would need to query the backend before I can start setting up Matomo.

I looked at the docs and was hopeful maybe via provider useFactory I could return a Promise, but doesn't look doable.

Tracking page view not complete since 5.0.1

Hello,

I'm having strange issue the 5.0.1 migration, I'm only having the first page tracked into my matomo dashboard.

Below it's my initialization code :

NgxMatomoModule.forRoot({
      mode: MatomoInitializationMode.AUTO_DEFERRED,
      requireConsent: MatomoConsentMode.COOKIE,
      disabled: isDevelopment(),
    }),
    NgxMatomoRouterModule,
     if (response.body) {
        matomoInitializer.initializeTracker({
          siteId: response.body.matomoId,
          trackerUrl: getMatomoTrackerUrl()
        })
      }

As I said I still see my first event but not more. I'm using tracker for event tracking in some component also.
Am I the only one facing this issue ?

Lazily check initialization

In order to authorize early tracking (for example using APP_INITIALIZER), delay tracker initialization check until first call actually happen

NgxMatomo is not adding correct Matomo's script

I am encountering an issue with the @ngx-matomo/tracker library (version 1.3.6) in Angular 11, where the tracking code verification fails with the error message "Tracking code verification failed. Please verify that you have installed the code correctly."

Upon inspection, I observed that the script is attempting to load from the URL https://sitename.matomo.cloud/matomo.php/matomo.js. However, attempting to access this URL results in an Internal Server Error. This discrepancy raises concerns about the accuracy of the script addition.

Notably, when inspecting the tracking code on Matomo, the provided link is formatted as //cdn.matomo.cloud/sitename.matomo.cloud/matomo.js.

I would appreciate it if you could confirm whether the script added is correct. If it is not, kindly advise on the correct method for loading the script using the URL cdn.matomo.cloud, considering the package I am currently using.

Allow more customization of auto-tracked page views

Currently NgxMatomoRouterModule only allows a few customization for automatically tracked page views (page title and url).

It would be nice to have more customization available for such pages (e-commerce details, etc.)

Angular 14 Update

Any Date when this project will get the update to Angular 14?

Thanks in advance

initial page load tracked twice

initial page load is tracked twice. It seems trackAppInitialLoad, which is default false, is not working properly.

These all don't fix the issue:
Explicitly setting trackAppInitialLoad to false
Tracking without NgxMatomoRouterModule
Tracking with NgxMatomoRouterModule
Tracking with NgxMatomoRouterModule and using a custom MATOMO_PAGE_TITLE_PROVIDER

Application freezes sometimes

Bonjour Emmanuel,

Dans le cadre d'un projet, j'ai dû intégrer Matomo afin de faire du tracking basique.
J'utilise la version 3.2.0 du ngx-matomo/router (donc la dernière version).

Depuis la mise en place du module, sur certaines actions, j'ai un freeze complet de mon application. Je dois fermer l'onglet et en ouvrir un nouveau. Ce problème est reproduit sur plusieurs navigateurs (FF, Chrome) et par plusieurs personnes sur plusieurs environnements.

C'est un problème qui arrive pendant une navigation (changement de page), à chaque fois depuis les mêmes pages, vers n'importe laquelle.

Lorsque je passe le paramètre "disabled" à true dans le MatomoConfiguration, je n'ai plus de problème (mais plus de tracking non plus). Dès que je le réactive, le problème apparait.

Avez-vous des retours quant à ce problème?

Merci d'avance

How to disable link tracking?

Is there any way to completely disable link tracking? I have tried to use the enableLinkTracking(false) method on the tracker, but that does not stop links from being tracked, it only seems to stop middle- and right-button mouseclicks on URLs from being tracked.

I am only interested in event logging of clicks and navigation actions within my application (which work perfectly fine with ngx-matomo).

How can I completely disable the logging of clicks on URLs that result in requests like this?
my.domain.com/application/matomo.php?link=https://my.target.url/

Angular 17 compatability

Hi, we're very happily using your @ngx-matomo/router and @ngx-matomo/tracker. However it doesn't work on the latest version of Angular 17. Could you please update the project so we can keep using it?

Missing mtmPreviewMode and mtmSetDebugFlag

Hello,

When using the scripts provided by Matomo (Matomo and Matomo Tag Manager) we're able to get a Preview/Debug on a console when providing following query params : https://website.com/?mtmPreviewMode=ContainerID&mtmSetDebugFlag=1.

I tested to use those query params with this package but I'm not getting any result (no console), is it somehow not implemented in your lib or maybe I'm doing something wrong ?

I'm on Angular 13, last version of ngx-matomo, we have Server Side Rendering but it shouldn't be enabled for the client (only robots) on our Dev platform.

Do you have any idea on how to display the preview/debug console using your lib ?

Thanks for your help.

matomo.php is always appended to trackerUrl

First of all I want to thank you for your great work. 👏🏻

Unfortunately, we can not use this plugin in our project at the time because of a tiny detail. In the MatomoInitializerService the TRACKER_SUFFIX matomo.php is always appended to the configured trackerUrl. However, in our setup we use a different path for the tracker endpoint which does not end in matomo.php. For me it seems unintuitive to automatically append a suffix to the configured trackerUrls.

Could this suffix be removed? Maybe not as this is a backward incompatible change and would lead to a new major version.

Or could we add an optional configuration option to avoid adding this suffix? This would solve our issue in backward compatible manner.

If you want I could possibly provide a PR for this. @EmmanuelRoux, would you accept such a PR?

(I know we could manually initialise the tracker but we prefer to use the auto mode.)

Problems with dynamic siteId configuration and routes with port numbers

Following comments in another issue, I configured a provider in our main.ts file to help determine and set my siteId based on the base href of our app.

export function getMatomoConfig() {
  let href = document.getElementsByTagName("base")[0].href;
  let config = {
    trackerUrl: 'https://ourTrackerUrl.com',
    scriptUrl: 'https://ourTrackerUrl.com/matomo.js',
    siteId: ''
  };

  if (href == "https://dev.our-site.com:8443/") {
    config.siteId = "1001";
  }
  else if (href == "https://prod.our-site.com:8443/") {
    config.siteId = "1002";
  }
  console.log("getMatomoConfig:", config);
  return config;
}

const providers = [
  { provide: "BASE_URL", useFactory: getBaseUrl, deps: [] },
  { provide: "MATOMO_CONFIG", useFactory: getMatomoConfig, deps: [] },
];

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic(providers)
  .bootstrapModule(AppModule)
  .catch((err) => console.error(err));

Then, in our app.module.ts file I did the following:

  imports: [
    ...
    NgxMatomoTrackerModule,
    NgxMatomoRouterModule,
  ],
  providers: [
    {
      provide: MATOMO_CONFIGURATION, 
      useFactory: () => getMatomoConfig, // calls provider in main.ts
      deps: ["MATOMO_CONFIG"]
    }, 

I am seeing the console message from the getMatomoConfig() call, however I only seem to be getting one tracking message sent to the Matomo server, and, that message does not contain the :8443/ of the URL.

I'm not sure if I am doing something incorrectly above, and I'm not sure if there is anything I can add to see what URLs are being sent to Matomo, within the angular app (perhaps adding a MatomoRouteDataInterceptor?)

Window is not defined (ssr prerendering) / Angular Universal

Hi,

when using SSR and prerendering I get the issue, that "window" is not definded. I'm using ngx-matomo version 2.1.0

Console error:
Prerendering 1 route(s) to C:\Development\xxx\dist\xxx\browser\be...Unhandled Promise rejection: window is not defined ; Zone: <root> ; Task: Promise.then ; Value: ReferenceError: window is not defined at initializeMatomoHolder (C:\Development\xxx\dist\xxx\server\be\main.js:3:8382901) at new MatomoInitializerService (C:\Development\xxx\dist\xxx\server\be\main.js:3:8399437) at createMatomoInitializer (C:\Development\xxx\dist\xxx\server\be\main.js:3:8399140) at Object.MatomoInitializerService_Factory [as factory] (C:\Development\xxx\dist\xxx\server\be\main.js:3:8401113) at R3Injector.hydrate (C:\Development\xxx\dist\xxx\server\be\main.js:3:6371603) at R3Injector.get (C:\Development\xxx\dist\xxx\server\be\main.js:3:6368724) at injectInjectorOnly (C:\Development\xxx\dist\xxx\server\be\main.js:3:6263915) at Object.ɵɵinject (C:\Development\xxx\dist\xxx\server\be\main.js:3:6264085) at Object.NgxMatomoTrackerModule_Factory [as factory] (C:\Development\xxx\dist\xxx\server\be\main.js:3:8401652) at R3Injector.hydrate (C:\Development\xxx\dist\xxx\server\be\main.js:3:6371603) ReferenceError: window is not defined at initializeMatomoHolder (C:\Development\xxx\dist\xxx\server\be\main.js:3:8382901) at new MatomoInitializerService (C:\Development\xxx\dist\xxx\server\be\main.js:3:8399437) at createMatomoInitializer (C:\Development\xxx\dist\xxx\server\be\main.js:3:8399140) at Object.MatomoInitializerService_Factory [as factory] (C:\Development\xxx\dist\xxx\server\be\main.js:3:8401113) at R3Injector.hydrate (C:\Development\xxx\dist\xxx\server\be\main.js:3:6371603) at R3Injector.get (C:\Development\xxx\dist\xxx\server\be\main.js:3:6368724) at injectInjectorOnly (C:\Development\xxx\dist\xxx\server\be\main.js:3:6263915) at Object.ɵɵinject (C:\Development\xxx\dist\xxx\server\be\main.js:3:6264085) at Object.NgxMatomoTrackerModule_Factory [as factory] (C:\Development\xxx\dist\xxx\server\be\main.js:3:8401652) at R3Injector.hydrate (C:\Development\xxx\dist\xxx\server\be\main.js:3:6371603) × Prerendering routes to C:\Development\xxx\dist\xxx\browser\be failed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.