EmmanuelRoux / ngx-matomo-client

Matomo analytics client for Angular applications
https://matomo.org/
MIT License
74 stars 16 forks source link

Problems with dynamic siteId configuration and routes with port numbers #45

Closed awdorrin closed 2 years ago

awdorrin commented 2 years ago

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?)

EmmanuelRoux commented 2 years ago

Hi @awdorrin

I see some issues in your providers config.

Can you please provide a repro? (stackblitz or other...)

awdorrin commented 2 years ago

I can try to set something up, but I don't have an Internet facing Matomo server, so it might take me a bit

EmmanuelRoux commented 2 years ago

At least if you can provide your full configuration and modules setup, it would be easier to investigate

awdorrin commented 2 years ago

Ok, This is quick and dirty: App URL: https://angular-ivy-n2kyst.stackblitz.io Editor URL: https://stackblitz.com/edit/angular-ivy-n2kyst?file=src/app/app.component.html

EmmanuelRoux commented 2 years ago

Thanks. Ok, I see some mistakes in your configuration. Maybe your issue is not related to this lib.

To help you, here are few tips to simplify/cleanup your config:

awdorrin commented 2 years ago

My reason for using the platform provider is to be able to make a runtime determination of which siteId I need to use for Matomo, based on which site my code is running on, before the NgxMatomo modules are loaded (Company policy for CI/CD pipelines is 'build once, load config by environment)

I had tried a provider in AppModule, but it didn't look like I could provide the configuration values in time for NgxMatomo.

(I had based my implementation upon the comments you made here: https://github.com/EmmanuelRoux/ngx-matomo/issues/31 )

As for the port number. Our angular app runs at a URL like: www.ourapp.com:8443 while another ASPX app runs at 'www.ourapp.com'. When I had this working with a statically loaded configuration, instead of seeing URLs in the Matomo application that looked like: https://www.ourapp.com:8443/home or https://www.ourapp.com:8443/reports/by-month

We were seeing: https://www.ourapp.com/home or https://www.ourapp.com/reports/by-month where the port number was not included in the URL.

I don't know if this it the NgxMatomo library not including the :8443 in the url being sent, or if something in our Matomo server is stripping off that port number.

Since I've been struggling trying to get the NgxMatomo configuration set dynamically, I haven't yet gone back to the static configuration to see if NgxMatomo is sending the :8443 in its requests, or not.

BTW, thank you for responding any trying to help me figure it out. It is very much appreciated.

awdorrin commented 2 years ago

I enabled the static configuration again, and see that there are two URLs being sent to Matomo: url: https://localhost/search urlref: https://localhost:44317/search

I would expect them to both have the port number of :44317 included in the URL.

EmmanuelRoux commented 2 years ago

Can you see those absolute urls (including host name and without port number) being sent in the HTTP request to tracker?

awdorrin commented 2 years ago

Yes, here is the 'payload' value:

action_name: Sample Page
idsite: 1084
rec: 1
r: 898525
h: 17
m: 40
s: 56
url: https://localhost/search
urlref: https://localhost:44317/search
_id: 21a648245e5ac088
_idts: 1653591583
_idvc: 5
_idn: 0
_refts: 0
_viewts: 1654030677
send_image: 1
pdf: 1
qt: 0
realp: 0
wma: 0
dir: 0
fla: 0
java: 0
gears: 0
ag: 0
cookie: 1
res: 5120x1440
gt_ms: 24
pv_id: H5Gm7V
awdorrin commented 2 years ago

I think I have an alternate approach that will work for providing the configuration information. I create a new class 'MatomoConfig',that acts as a singleton.

export class MatomoConfig {
  private static instance: MatomoConfig = new MatomoConfig();
  private static siteId: string | number;
  private static trackerUrl: string;
  private static scriptUrl: string;

  private constructor() {
    let href = document.getElementsByTagName("base")[0].href;
    MatomoConfig.trackerUrl = 'https://matomo-site.com';
    MatomoConfig.scriptUrl = 'https://matomo-site.com/matomo.js';
    MatomoConfig.siteId = '';
    if (href == "https://dev.site.com:8443/") {
      MatomoConfig.siteId = "1084";
    }
    else if (href == "https://prod.site.com:8443/") {
      MatomoConfig.siteId = "1086";
    }
    else if (href.startsWith('https://localhost')) {
      MatomoConfig.siteId = "1084";
    }
  }
  public static getSiteId(): string | number {
    if (!MatomoConfig.instance) { MatomoConfig.instance = new MatomoConfig(); }
    return MatomoConfig.siteId;
  }
  public static getTrackerUrl(): string {
    if (!MatomoConfig.instance) { MatomoConfig.instance = new MatomoConfig(); }
    return MatomoConfig.trackerUrl;
  }
  public static getScriptUrl(): string {
    if (!MatomoConfig.instance) { MatomoConfig.instance = new MatomoConfig(); }
    return MatomoConfig.scriptUrl;
  }
}

Then in AppModule I do this:

import { MatomoConfig } from "../matomoconfig";
...
  imports: [
    ...
    NgxMatomoTrackerModule
      .forRoot({
        trackerUrl: MatomoConfig.getTrackerUrl(),
        scriptUrl: MatomoConfig.getScriptUrl(),
        siteId: MatomoConfig.getSiteId()

      }),
    NgxMatomoRouterModule,
  ],
...

Not the most elegant solution, but it does work.

Now, I just need to understand the url vs urlRef entries.

EmmanuelRoux commented 2 years ago

Does it solve your problem? (If yes, I don’t understand why…).

About Matomo http params:

awdorrin commented 2 years ago

No, the discrepancy in the two URLs fields still exists. I've only resolved the initialization of the tracker settings.

In another matomo request, when I moved from the search page, to another in the app, I saw the values:

url: https://localhost/subct/list
urlref: /search

Time to grep some source code I think...

EmmanuelRoux commented 2 years ago

Ok I took a look at Matomo's JS source code, I think their client is stripping off port number from url... See source here: https://github.com/matomo-org/matomo/blob/70b004c968a1850b65c71156b465d189f4692a49/js/piwik.js#L2541

We can't fix Matomo... so what you can do for now, is to force an absolute url including protocol and port. Define a new url provider as described here in README: https://github.com/EmmanuelRoux/ngx-matomo#customize-page-url

It should look like that:

@Injectable()
export class MyPageUrlProvider implements PageUrlProvider {

  // Of course you can make it more "dynamic", by injecting APP_BASE_HREF or something else

  getCurrentPageUrl(event: NavigationEnd): Observable<string> {
    const routerUrl = event.urlAfterRedirects;
    const absoluteUrl = 'http://domain.com:port' + routerUrl;

    return of(absoluteUrl);
  }

}

Does it helps?


I will do more tests when I have some time, if this is confirmed I will probably include a fix in the lib

awdorrin commented 2 years ago

Thanks that does help. I tweaked your example to be:

@Injectable()
export class MyPageUrlProvider implements PageUrlProvider {

  getCurrentPageUrl(event: NavigationEnd): Observable<string> {
    const href = document.getElementsByTagName("base")[0].href;
    const routerUrl = event.urlAfterRedirects;
    const absoluteUrl = new URL(routerUrl, href);
    return of(absoluteUrl.toString());
  }
}
EmmanuelRoux commented 2 years ago

I closed this as solved, feel free to reopen if needed