Browse Source

feat(analytics): add Matomo support

j8
ludovicm67 5 years ago
parent
commit
4c635a2a63

+ 2
- 0
Makefile View File

@@ -46,6 +46,8 @@ deploy-appbundle:
46 46
 		$(OUTPUT_DIR)/analytics-ga.js \
47 47
 		$(BUILD_DIR)/analytics-ga.min.js \
48 48
 		$(BUILD_DIR)/analytics-ga.min.map \
49
+		$(BUILD_DIR)/analytics-matomo.min.js \
50
+		$(BUILD_DIR)/analytics-matomo.min.map \
49 51
 		$(BUILD_DIR)/video-blur-effect.min.js \
50 52
 		$(BUILD_DIR)/video-blur-effect.min.map \
51 53
 		$(BUILD_DIR)/rnnoise-processor.min.js \

+ 7
- 2
config.js View File

@@ -371,13 +371,18 @@ var config = {
371 371
         // The Google Analytics Tracking ID:
372 372
         // googleAnalyticsTrackingId: 'your-tracking-id-UA-123456-1'
373 373
 
374
+        // Matomo configuration:
375
+        // matomoEndpoint: 'https://your-matomo-endpoint/',
376
+        // matomoSiteID: '42',
377
+
374 378
         // The Amplitude APP Key:
375 379
         // amplitudeAPPKey: '<APP_KEY>'
376 380
 
377 381
         // Array of script URLs to load as lib-jitsi-meet "analytics handlers".
378 382
         // scriptURLs: [
379
-        //      "libs/analytics-ga.min.js", // google-analytics
380
-        //      "https://example.com/my-custom-analytics.js"
383
+        //     "libs/analytics-ga.min.js",     // google-analytics
384
+        //     "libs/analytics-matomo.min.js", // Matomo
385
+        //     "https://example.com/my-custom-analytics.js"
381 386
         // ],
382 387
     },
383 388
 

+ 5
- 1
react/features/analytics/functions.js View File

@@ -65,6 +65,8 @@ export function createHandlers({ getState }: { getState: Function }) {
65 65
         blackListedEvents,
66 66
         scriptURLs,
67 67
         googleAnalyticsTrackingId,
68
+        matomoEndpoint,
69
+        matomoSiteID,
68 70
         whiteListedEvents
69 71
     } = analyticsConfig;
70 72
     const { group, user } = state['features/base/jwt'];
@@ -73,6 +75,8 @@ export function createHandlers({ getState }: { getState: Function }) {
73 75
         blackListedEvents,
74 76
         envType: (deploymentInfo && deploymentInfo.envType) || 'dev',
75 77
         googleAnalyticsTrackingId,
78
+        matomoEndpoint,
79
+        matomoSiteID,
76 80
         group,
77 81
         host,
78 82
         product: deploymentInfo && deploymentInfo.product,
@@ -95,7 +99,7 @@ export function createHandlers({ getState }: { getState: Function }) {
95 99
             .then(externalHandlers => {
96 100
                 handlers.push(...externalHandlers);
97 101
                 if (handlers.length === 0) {
98
-                    // Throwing an error in  order to dispose the analytics in the catch clause due to the lack of any
102
+                    // Throwing an error in order to dispose the analytics in the catch clause due to the lack of any
99 103
                     // analytics handlers.
100 104
                     throw new Error('No analytics handlers created!');
101 105
                 }

+ 163
- 0
react/features/analytics/handlers/MatomoHandler.js View File

@@ -0,0 +1,163 @@
1
+/* global _paq */
2
+
3
+import { getJitsiMeetGlobalNS } from '../../base/util';
4
+
5
+import AbstractHandler from './AbstractHandler';
6
+
7
+/**
8
+ * Analytics handler for Matomo.
9
+ */
10
+class MatomoHandler extends AbstractHandler {
11
+
12
+    /**
13
+     * Creates new instance of the Matomo handler.
14
+     *
15
+     * @param {Object} options -
16
+     * @param {string} options.matomoEndpoint - The Matomo endpoint.
17
+     * @param {string} options.matomoSiteID   - The site ID.
18
+     */
19
+    constructor(options) {
20
+        super(options);
21
+        this._userProperties = {};
22
+
23
+        if (!options.matomoEndpoint) {
24
+            throw new Error(
25
+                'Failed to initialize Matomo handler: no endpoint defined.'
26
+            );
27
+        }
28
+        if (!options.matomoSiteID) {
29
+            throw new Error(
30
+                'Failed to initialize Matomo handler: no site ID defined.'
31
+            );
32
+        }
33
+
34
+        this._enabled = true;
35
+        this._initMatomo(options);
36
+    }
37
+
38
+    /**
39
+     * Initializes the _paq object.
40
+     *
41
+     * @param {Object} options -
42
+     * @param {string} options.matomoEndpoint - The Matomo endpoint.
43
+     * @param {string} options.matomoSiteID   - The site ID.
44
+     * @returns {void}
45
+     */
46
+    _initMatomo(options) {
47
+        const _paq = window._paq || [];
48
+
49
+        window._paq = _paq;
50
+
51
+        _paq.push([ 'trackPageView' ]);
52
+        _paq.push([ 'enableLinkTracking' ]);
53
+
54
+        (function() {
55
+            // add trailing slash if needed
56
+            const u = options.matomoEndpoint.endsWith('/')
57
+                ? options.matomoEndpoint
58
+                : `${options.matomoEndpoint}/`;
59
+
60
+            // configure the tracker
61
+            _paq.push([ 'setTrackerUrl', `${u}matomo.php` ]);
62
+            _paq.push([ 'setSiteId', options.matomoSiteID ]);
63
+
64
+            // insert the matomo script
65
+            const d = document,
66
+                g = d.createElement('script'),
67
+                s = d.getElementsByTagName('script')[0];
68
+
69
+            g.type = 'text/javascript';
70
+            g.async = true;
71
+            g.defer = true;
72
+            g.src = `${u}matomo.js`;
73
+            s.parentNode.insertBefore(g, s);
74
+        })();
75
+    }
76
+
77
+    /**
78
+     * Extracts the integer to use for a Matomo event's value field
79
+     * from a lib-jitsi-meet analytics event.
80
+     *
81
+     * @param {Object} event - The lib-jitsi-meet analytics event.
82
+     * @returns {number} - The integer to use for the 'value' of a Matomo
83
+     * event, or NaN if the lib-jitsi-meet event doesn't contain a
84
+     * suitable value.
85
+     * @private
86
+     */
87
+    _extractValue(event) {
88
+        const value = event && event.attributes && event.attributes.value;
89
+
90
+        // Try to extract an integer from the 'value' attribute.
91
+        return Math.round(parseFloat(value));
92
+    }
93
+
94
+    /**
95
+     * Sets the permanent properties for the current session.
96
+     *
97
+     * @param {Object} userProps - The permanent properties.
98
+     * @returns {void}
99
+     */
100
+    setUserProperties(userProps = {}) {
101
+        if (!this._enabled) {
102
+            return;
103
+        }
104
+
105
+        const visitScope = [ 'user_agent', 'callstats_name', 'browser_name' ];
106
+
107
+        // add variables in the 'page' scope
108
+        Object.keys(userProps)
109
+            .filter(key => visitScope.indexOf(key) === -1)
110
+            .forEach((key, index) => {
111
+                _paq.push([
112
+                    'setCustomVariable',
113
+                    1 + index,
114
+                    key,
115
+                    userProps[key],
116
+                    'page'
117
+                ]);
118
+            });
119
+
120
+
121
+        // add variables in the 'visit' scope
122
+        Object.keys(userProps)
123
+            .filter(key => visitScope.indexOf(key) !== -1)
124
+            .forEach((key, index) => {
125
+                _paq.push([
126
+                    'setCustomVariable',
127
+                    1 + index,
128
+                    key,
129
+                    userProps[key],
130
+                    'visit'
131
+                ]);
132
+            });
133
+    }
134
+
135
+    /**
136
+     * This is the entry point of the API. The function sends an event to
137
+     * the Matomo endpoint. The format of the event is described in
138
+     * analyticsAdapter in lib-jitsi-meet.
139
+     *
140
+     * @param {Object} event - The event in the format specified by
141
+     * lib-jitsi-meet.
142
+     * @returns {void}
143
+     */
144
+    sendEvent(event) {
145
+        if (this._shouldIgnore(event)) {
146
+            return;
147
+        }
148
+
149
+        const value = this._extractValue(event);
150
+        const matomoEvent = [ 'trackEvent', 'jitsi-meet', this._extractName(event) ];
151
+
152
+        if (!isNaN(value)) {
153
+            matomoEvent.push(value);
154
+        }
155
+
156
+        _paq.push(matomoEvent);
157
+    }
158
+}
159
+
160
+const globalNS = getJitsiMeetGlobalNS();
161
+
162
+globalNS.analyticsHandlers = globalNS.analyticsHandlers || [];
163
+globalNS.analyticsHandlers.push(MatomoHandler);

+ 6
- 0
webpack.config.js View File

@@ -217,6 +217,12 @@ module.exports = [
217 217
         },
218 218
         performance: getPerformanceHints(5 * 1024)
219 219
     }),
220
+    Object.assign({}, config, {
221
+        entry: {
222
+            'analytics-matomo': './react/features/analytics/handlers/MatomoHandler.js'
223
+        },
224
+        performance: getPerformanceHints(5 * 1024)
225
+    }),
220 226
 
221 227
     // Because both video-blur-effect and rnnoise-processor modules are loaded
222 228
     // in a lazy manner using the loadScript function with a hard coded name,

Loading…
Cancel
Save