feat(analytics): add Matomo support
This commit is contained in:
parent
2b526557e4
commit
4c635a2a63
2
Makefile
2
Makefile
|
@ -46,6 +46,8 @@ deploy-appbundle:
|
|||
$(OUTPUT_DIR)/analytics-ga.js \
|
||||
$(BUILD_DIR)/analytics-ga.min.js \
|
||||
$(BUILD_DIR)/analytics-ga.min.map \
|
||||
$(BUILD_DIR)/analytics-matomo.min.js \
|
||||
$(BUILD_DIR)/analytics-matomo.min.map \
|
||||
$(BUILD_DIR)/video-blur-effect.min.js \
|
||||
$(BUILD_DIR)/video-blur-effect.min.map \
|
||||
$(BUILD_DIR)/rnnoise-processor.min.js \
|
||||
|
|
|
@ -371,13 +371,18 @@ var config = {
|
|||
// The Google Analytics Tracking ID:
|
||||
// googleAnalyticsTrackingId: 'your-tracking-id-UA-123456-1'
|
||||
|
||||
// Matomo configuration:
|
||||
// matomoEndpoint: 'https://your-matomo-endpoint/',
|
||||
// matomoSiteID: '42',
|
||||
|
||||
// The Amplitude APP Key:
|
||||
// amplitudeAPPKey: '<APP_KEY>'
|
||||
|
||||
// Array of script URLs to load as lib-jitsi-meet "analytics handlers".
|
||||
// scriptURLs: [
|
||||
// "libs/analytics-ga.min.js", // google-analytics
|
||||
// "https://example.com/my-custom-analytics.js"
|
||||
// "libs/analytics-ga.min.js", // google-analytics
|
||||
// "libs/analytics-matomo.min.js", // Matomo
|
||||
// "https://example.com/my-custom-analytics.js"
|
||||
// ],
|
||||
},
|
||||
|
||||
|
|
|
@ -65,6 +65,8 @@ export function createHandlers({ getState }: { getState: Function }) {
|
|||
blackListedEvents,
|
||||
scriptURLs,
|
||||
googleAnalyticsTrackingId,
|
||||
matomoEndpoint,
|
||||
matomoSiteID,
|
||||
whiteListedEvents
|
||||
} = analyticsConfig;
|
||||
const { group, user } = state['features/base/jwt'];
|
||||
|
@ -73,6 +75,8 @@ export function createHandlers({ getState }: { getState: Function }) {
|
|||
blackListedEvents,
|
||||
envType: (deploymentInfo && deploymentInfo.envType) || 'dev',
|
||||
googleAnalyticsTrackingId,
|
||||
matomoEndpoint,
|
||||
matomoSiteID,
|
||||
group,
|
||||
host,
|
||||
product: deploymentInfo && deploymentInfo.product,
|
||||
|
@ -95,7 +99,7 @@ export function createHandlers({ getState }: { getState: Function }) {
|
|||
.then(externalHandlers => {
|
||||
handlers.push(...externalHandlers);
|
||||
if (handlers.length === 0) {
|
||||
// Throwing an error in order to dispose the analytics in the catch clause due to the lack of any
|
||||
// Throwing an error in order to dispose the analytics in the catch clause due to the lack of any
|
||||
// analytics handlers.
|
||||
throw new Error('No analytics handlers created!');
|
||||
}
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
/* global _paq */
|
||||
|
||||
import { getJitsiMeetGlobalNS } from '../../base/util';
|
||||
|
||||
import AbstractHandler from './AbstractHandler';
|
||||
|
||||
/**
|
||||
* Analytics handler for Matomo.
|
||||
*/
|
||||
class MatomoHandler extends AbstractHandler {
|
||||
|
||||
/**
|
||||
* Creates new instance of the Matomo handler.
|
||||
*
|
||||
* @param {Object} options -
|
||||
* @param {string} options.matomoEndpoint - The Matomo endpoint.
|
||||
* @param {string} options.matomoSiteID - The site ID.
|
||||
*/
|
||||
constructor(options) {
|
||||
super(options);
|
||||
this._userProperties = {};
|
||||
|
||||
if (!options.matomoEndpoint) {
|
||||
throw new Error(
|
||||
'Failed to initialize Matomo handler: no endpoint defined.'
|
||||
);
|
||||
}
|
||||
if (!options.matomoSiteID) {
|
||||
throw new Error(
|
||||
'Failed to initialize Matomo handler: no site ID defined.'
|
||||
);
|
||||
}
|
||||
|
||||
this._enabled = true;
|
||||
this._initMatomo(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the _paq object.
|
||||
*
|
||||
* @param {Object} options -
|
||||
* @param {string} options.matomoEndpoint - The Matomo endpoint.
|
||||
* @param {string} options.matomoSiteID - The site ID.
|
||||
* @returns {void}
|
||||
*/
|
||||
_initMatomo(options) {
|
||||
const _paq = window._paq || [];
|
||||
|
||||
window._paq = _paq;
|
||||
|
||||
_paq.push([ 'trackPageView' ]);
|
||||
_paq.push([ 'enableLinkTracking' ]);
|
||||
|
||||
(function() {
|
||||
// add trailing slash if needed
|
||||
const u = options.matomoEndpoint.endsWith('/')
|
||||
? options.matomoEndpoint
|
||||
: `${options.matomoEndpoint}/`;
|
||||
|
||||
// configure the tracker
|
||||
_paq.push([ 'setTrackerUrl', `${u}matomo.php` ]);
|
||||
_paq.push([ 'setSiteId', options.matomoSiteID ]);
|
||||
|
||||
// insert the matomo script
|
||||
const d = document,
|
||||
g = d.createElement('script'),
|
||||
s = d.getElementsByTagName('script')[0];
|
||||
|
||||
g.type = 'text/javascript';
|
||||
g.async = true;
|
||||
g.defer = true;
|
||||
g.src = `${u}matomo.js`;
|
||||
s.parentNode.insertBefore(g, s);
|
||||
})();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the integer to use for a Matomo event's value field
|
||||
* from a lib-jitsi-meet analytics event.
|
||||
*
|
||||
* @param {Object} event - The lib-jitsi-meet analytics event.
|
||||
* @returns {number} - The integer to use for the 'value' of a Matomo
|
||||
* event, or NaN if the lib-jitsi-meet event doesn't contain a
|
||||
* suitable value.
|
||||
* @private
|
||||
*/
|
||||
_extractValue(event) {
|
||||
const value = event && event.attributes && event.attributes.value;
|
||||
|
||||
// Try to extract an integer from the 'value' attribute.
|
||||
return Math.round(parseFloat(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the permanent properties for the current session.
|
||||
*
|
||||
* @param {Object} userProps - The permanent properties.
|
||||
* @returns {void}
|
||||
*/
|
||||
setUserProperties(userProps = {}) {
|
||||
if (!this._enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const visitScope = [ 'user_agent', 'callstats_name', 'browser_name' ];
|
||||
|
||||
// add variables in the 'page' scope
|
||||
Object.keys(userProps)
|
||||
.filter(key => visitScope.indexOf(key) === -1)
|
||||
.forEach((key, index) => {
|
||||
_paq.push([
|
||||
'setCustomVariable',
|
||||
1 + index,
|
||||
key,
|
||||
userProps[key],
|
||||
'page'
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
// add variables in the 'visit' scope
|
||||
Object.keys(userProps)
|
||||
.filter(key => visitScope.indexOf(key) !== -1)
|
||||
.forEach((key, index) => {
|
||||
_paq.push([
|
||||
'setCustomVariable',
|
||||
1 + index,
|
||||
key,
|
||||
userProps[key],
|
||||
'visit'
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the entry point of the API. The function sends an event to
|
||||
* the Matomo endpoint. The format of the event is described in
|
||||
* analyticsAdapter in lib-jitsi-meet.
|
||||
*
|
||||
* @param {Object} event - The event in the format specified by
|
||||
* lib-jitsi-meet.
|
||||
* @returns {void}
|
||||
*/
|
||||
sendEvent(event) {
|
||||
if (this._shouldIgnore(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const value = this._extractValue(event);
|
||||
const matomoEvent = [ 'trackEvent', 'jitsi-meet', this._extractName(event) ];
|
||||
|
||||
if (!isNaN(value)) {
|
||||
matomoEvent.push(value);
|
||||
}
|
||||
|
||||
_paq.push(matomoEvent);
|
||||
}
|
||||
}
|
||||
|
||||
const globalNS = getJitsiMeetGlobalNS();
|
||||
|
||||
globalNS.analyticsHandlers = globalNS.analyticsHandlers || [];
|
||||
globalNS.analyticsHandlers.push(MatomoHandler);
|
|
@ -217,6 +217,12 @@ module.exports = [
|
|||
},
|
||||
performance: getPerformanceHints(5 * 1024)
|
||||
}),
|
||||
Object.assign({}, config, {
|
||||
entry: {
|
||||
'analytics-matomo': './react/features/analytics/handlers/MatomoHandler.js'
|
||||
},
|
||||
performance: getPerformanceHints(5 * 1024)
|
||||
}),
|
||||
|
||||
// Because both video-blur-effect and rnnoise-processor modules are loaded
|
||||
// in a lazy manner using the loadScript function with a hard coded name,
|
||||
|
|
Loading…
Reference in New Issue