diff --git a/MATOMO_CONFIGURATION.md b/MATOMO_CONFIGURATION.md
new file mode 100644
index 00000000000..bb952d8c676
--- /dev/null
+++ b/MATOMO_CONFIGURATION.md
@@ -0,0 +1,41 @@
+# Matomo Statistics Configuration
+
+## Enable/Disable Matomo
+
+### To Disable Matomo (Default)
+Edit `src/environments/environment.ts`:
+```typescript
+matomo: {
+ enabled: false,
+ hostUrl: 'https://your-matomo-server.com/',
+ siteId: '1',
+ dimensionId: 1
+}
+```
+
+### To Enable Matomo
+Edit `src/environments/environment.ts`:
+```typescript
+matomo: {
+ enabled: true,
+ hostUrl: 'https://your-matomo-server.com/',
+ siteId: '1',
+ dimensionId: 1
+}
+```
+
+## Files to Modify
+
+- **Development**: `src/environments/environment.ts`
+- **Production**: `src/environments/environment.production.ts`
+- **Global/Server-side**: `config/config.example.yml` (and `config/config.yml` in production)
+- **Runtime (if applicable)**: `config.json`
+> **Note:** The `enabled` flag for Matomo may be present in multiple configuration files. Ensure you update all relevant files (`environment.ts`, `environment.production.ts`, `config/config.example.yml`, and any runtime `config.json`) to avoid conflicts or unexpected behavior.
+
+## After Changes
+
+1. Restart the application
+2. Clear browser cache
+
+When disabled: No Matomo scripts load, statistics page shows "disabled" message.
+When enabled: Matomo tracking works normally.
diff --git a/config/config.example.yml b/config/config.example.yml
index 8b56711c7d2..c8500545df4 100644
--- a/config/config.example.yml
+++ b/config/config.example.yml
@@ -465,5 +465,6 @@ accessibility:
cookieExpirationDuration: 7
matomo:
+ enabled: false
hostUrl: http://localhost:8135/
siteId: 1
diff --git a/src/app/item-page/clarin-matomo-statistics/clarin-matomo-statistics.component.html b/src/app/item-page/clarin-matomo-statistics/clarin-matomo-statistics.component.html
index 4e1e768abf7..ab179b15869 100644
--- a/src/app/item-page/clarin-matomo-statistics/clarin-matomo-statistics.component.html
+++ b/src/app/item-page/clarin-matomo-statistics/clarin-matomo-statistics.component.html
@@ -1,50 +1,56 @@
-
-
-
{{'item.matomo-statistics.info.message' | translate}}
+
+
+ Matomo statistics are currently disabled.
-
-
-
-
-
- {{chartMessage}}
-
-
-
-
-
-
-
-
- Filewise Statistics
-
-
-
- | {{fileData.value}} |
- {{fileData.key}} |
-
-
-
+
+
+
+ {{'item.matomo-statistics.info.message' | translate}}
+
+
+
+
+
+
+ {{chartMessage}}
+
+
+
+
+
+
+
+
+ Filewise Statistics
+
+
+
+ | {{fileData.value}} |
+ {{fileData.key}} |
+
+
+
+
diff --git a/src/app/item-page/clarin-matomo-statistics/clarin-matomo-statistics.component.ts b/src/app/item-page/clarin-matomo-statistics/clarin-matomo-statistics.component.ts
index 8f73e51e766..858d26a7e7a 100644
--- a/src/app/item-page/clarin-matomo-statistics/clarin-matomo-statistics.component.ts
+++ b/src/app/item-page/clarin-matomo-statistics/clarin-matomo-statistics.component.ts
@@ -10,6 +10,7 @@ import { map } from 'rxjs/operators';
import { ActivatedRoute } from '@angular/router';
import { RemoteData } from '../../core/data/remote-data';
import { Item } from '../../core/shared/item.model';
+import { environment } from '../../../environments/environment';
@Component({
selector: 'ds-clarin-matomo-statistics',
@@ -27,6 +28,8 @@ export class ClarinMatomoStatisticsComponent implements OnInit {
itemRD$: BehaviorSubject
- = new BehaviorSubject
- (null);
+ public matomoEnabled = false;
+
// Month shortcut with full name
public months = [
['Jan', 'January'],
@@ -130,6 +133,13 @@ export class ClarinMatomoStatisticsComponent implements OnInit {
ngOnInit(): void {
+ this.matomoEnabled = environment.matomo?.enabled === true;
+
+ // If Matomo is disabled, don't fetch statistics
+ if (!this.matomoEnabled) {
+ return;
+ }
+
this.route.data.pipe(
map((data) => data.dso as RemoteData
- ))
.subscribe(data => {
diff --git a/src/config/default-app-config.ts b/src/config/default-app-config.ts
index 38cb942e457..2fff7f31fc3 100644
--- a/src/config/default-app-config.ts
+++ b/src/config/default-app-config.ts
@@ -452,6 +452,7 @@ export class DefaultAppConfig implements AppConfig {
// Matomo configuration
matomo: MatomoConfig = {
+ enabled: false,
hostUrl: 'http://localhost:8135/',
siteId: '1',
dimensionId: 1
diff --git a/src/config/matomo-config.ts b/src/config/matomo-config.ts
index 548f02aee4c..cc71a3cb6fc 100644
--- a/src/config/matomo-config.ts
+++ b/src/config/matomo-config.ts
@@ -5,6 +5,8 @@ import { Config } from './config.interface';
*/
export class MatomoConfig implements Config {
+ public enabled: boolean;
+
public hostUrl: string;
public siteId: string;
diff --git a/src/environments/environment.test.ts b/src/environments/environment.test.ts
index a0cab16ef83..ce1998535d6 100644
--- a/src/environments/environment.test.ts
+++ b/src/environments/environment.test.ts
@@ -356,6 +356,7 @@ export const environment: BuildConfig = {
signpostingEnabled: true,
matomo: {
+ enabled: false,
hostUrl: 'http://localhost:8135/',
siteId: '1',
dimensionId: 1
diff --git a/src/environments/environment.ts b/src/environments/environment.ts
index 8be4ee7dbfe..a229e75036b 100644
--- a/src/environments/environment.ts
+++ b/src/environments/environment.ts
@@ -49,6 +49,14 @@ export const environment: Partial = {
},
signpostingEnabled: false,
+
+ // Matomo configuration
+ matomo: {
+ enabled: false,
+ hostUrl: 'http://localhost:8135/',
+ siteId: '1',
+ dimensionId: 1
+ },
};
/*
diff --git a/src/main.browser.ts b/src/main.browser.ts
index d17101d07a6..49e9242b8ab 100644
--- a/src/main.browser.ts
+++ b/src/main.browser.ts
@@ -27,9 +27,9 @@ const main = () => {
enableProdMode();
}
- addMatomoStatistics();
if (hasTransferState) {
// Configuration will be taken from transfer state during initialization
+ addMatomoStatistics();
return bootstrap();
} else {
// Configuration must be fetched explicitly
@@ -38,36 +38,41 @@ const main = () => {
.then((appConfig: AppConfig) => {
// extend environment with app config for browser when not prerendered
extendEnvironmentWithAppConfig(environment, appConfig);
+ addMatomoStatistics();
return bootstrap();
});
}
};
function addMatomoStatistics() {
- (window as any)._paq = (window as any)._paq || [];
+ // Check if Matomo is configured with required properties
+ if (!environment.matomo || !environment.matomo.hostUrl || !environment.matomo.siteId) {
+ return;
+ }
- void fetch('assets/config.json')
- .then((response) => response.json())
- .then((config) => {
- const matomoConfig = config.matomo;
+ try {
+ (window as any)._paq = (window as any)._paq || [];
- // Push all configuration commands first
- (window as any)._paq.push(['setTrackerUrl', matomoConfig.hostUrl + 'matomo.php']);
- (window as any)._paq.push(['setSiteId', matomoConfig.siteId]);
- (window as any)._paq.push(['enableLinkTracking']);
+ // Push all configuration commands first
+ (window as any)._paq.push(['setTrackerUrl', environment.matomo.hostUrl + 'matomo.php']);
+ (window as any)._paq.push(['setSiteId', environment.matomo.siteId]);
+ (window as any)._paq.push(['enableLinkTracking']);
- const g = document.createElement('script');
- g.type = 'text/javascript';
- g.async = true;
- g.defer = true;
- g.src = matomoConfig.hostUrl + 'matomo.js';
- document.getElementsByTagName('head')[0].appendChild(g);
- });
+ const g = document.createElement('script');
+ g.type = 'text/javascript';
+ g.async = true;
+ g.defer = true;
+ g.src = environment.matomo.hostUrl + 'matomo.js';
+ document.getElementsByTagName('head')[0].appendChild(g);
+ } catch (error) {
+ console.error('Matomo initialization failed:', error);
+ return;
+ }
}
// support async tag or hmr
if (document.readyState === 'complete' && !hasTransferState) {
- main();
+ void main();
} else {
- document.addEventListener('DOMContentLoaded', main);
+ document.addEventListener('DOMContentLoaded', () => void main());
}
diff --git a/src/modules/app/browser-init.service.ts b/src/modules/app/browser-init.service.ts
index 905485637d6..fd7716e570a 100644
--- a/src/modules/app/browser-init.service.ts
+++ b/src/modules/app/browser-init.service.ts
@@ -107,26 +107,36 @@ export class BrowserInitService extends InitService {
this.initRouteListeners();
this.themeService.listenForThemeChanges(true);
this.trackAuthTokenExpiration();
- // ideally we'd add the custom dimension to the 'trackPageView' action only, but don't have that information
- // in pageTrack context. So we add it to page_view events, and remove it after the page view.
- // page_view events are fired via view-track.component, and exposes dc.identifier.uri via properties
- this.angulartics2Matomo.eventTrack = function (action: string, properties?: any) {
- if (action === 'page_view') {
- if (properties.dc_identifier) {
- (window as any)._paq.push(['setCustomDimension', environment.matomo.dimensionId, properties.dc_identifier]);
- }
+
+ // Only initialize Matomo if it's configured with required properties
+ if (this.appConfig.matomo && this.appConfig.matomo.hostUrl && this.appConfig.matomo.siteId) {
+ // ideally we'd add the custom dimension to the 'trackPageView' action only, but don't have that information
+ // in pageTrack context. So we add it to page_view events, and remove it after the page view.
+ // page_view events are fired via view-track.component, and exposes dc.identifier.uri via properties
+ const dimensionId = this.appConfig.matomo.dimensionId;
+
+ // Only set up custom dimensions if dimensionId is configured
+ if (dimensionId) {
+ this.angulartics2Matomo.eventTrack = function (action: string, properties?: any) {
+ if (action === 'page_view') {
+ if (properties.dc_identifier) {
+ (window as any)._paq.push(['setCustomDimension', dimensionId, properties.dc_identifier]);
+ }
+ }
+ };
+ let pageTrack = this.angulartics2Matomo.pageTrack;
+ this.angulartics2Matomo.pageTrack = function (path: string) {
+ pageTrack.call(this, path);
+ (window as any)._paq.push(['deleteCustomDimension', dimensionId]);
+ };
}
- };
- let pageTrack = this.angulartics2Matomo.pageTrack;
- this.angulartics2Matomo.pageTrack = function (path: string) {
- pageTrack.call(this, path);
- (window as any)._paq.push(['deleteCustomDimension', environment.matomo.dimensionId]);
- };
- this.angulartics2Matomo.startTracking();
+
+ this.angulartics2Matomo.startTracking();
+ }
this.initKlaro();
- await this.authenticationReady$().toPromise();
+ await firstValueFrom(this.authenticationReady$());
return true;
};
@@ -197,7 +207,7 @@ export class BrowserInitService extends InitService {
* @private
*/
private closeAuthCheckSubscription() {
- firstValueFrom(this.authenticationReady$()).then(() => {
+ void firstValueFrom(this.authenticationReady$()).then(() => {
this.sub.unsubscribe();
});
}