You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GoogleAnalyticsHandler.js 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /* global ga */
  2. import { getJitsiMeetGlobalNS } from '../../base/util';
  3. import AbstractHandler from './AbstractHandler';
  4. const logger = require('jitsi-meet-logger').getLogger(__filename);
  5. /**
  6. * Analytics handler for Google Analytics.
  7. */
  8. class GoogleAnalyticsHandler extends AbstractHandler {
  9. /**
  10. * Creates new instance of the GA analytics handler.
  11. *
  12. * @param {Object} options -
  13. * @param {string} options.googleAnalyticsTrackingId - The GA track id
  14. * required by the GA API.
  15. */
  16. constructor(options) {
  17. super();
  18. this._userProperties = {};
  19. if (!options.googleAnalyticsTrackingId) {
  20. logger.warn(
  21. 'Failed to initialize Google Analytics handler, no tracking ID'
  22. );
  23. return;
  24. }
  25. this._enabled = true;
  26. this._initGoogleAnalytics(options);
  27. }
  28. /**
  29. * Initializes the ga object.
  30. *
  31. * @param {Object} options -
  32. * @param {string} options.googleAnalyticsTrackingId - The GA track id
  33. * required by the GA API.
  34. * @returns {void}
  35. */
  36. _initGoogleAnalytics(options) {
  37. /**
  38. * TODO: Keep this local, there's no need to add it to window.
  39. */
  40. /* eslint-disable */
  41. (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  42. (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  43. })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
  44. /* eslint-enable */
  45. ga('create', options.googleAnalyticsTrackingId, 'auto');
  46. ga('send', 'pageview');
  47. }
  48. /**
  49. * Extracts the integer to use for a Google Analytics event's value field
  50. * from a lib-jitsi-meet analytics event.
  51. *
  52. * @param {Object} event - The lib-jitsi-meet analytics event.
  53. * @returns {number} - The integer to use for the 'value' of a Google
  54. * analytics event, or NaN if the lib-jitsi-meet event doesn't contain a
  55. * suitable value.
  56. * @private
  57. */
  58. _extractValue(event) {
  59. let value = event && event.attributes && event.attributes.value;
  60. // Try to extract an integer from the "value" attribute.
  61. value = Math.round(parseFloat(value));
  62. return value;
  63. }
  64. /**
  65. * Extracts the string to use for a Google Analytics event's label field
  66. * from a lib-jitsi-meet analytics event.
  67. *
  68. * @param {Object} event - The lib-jitsi-meet analytics event.
  69. * @returns {string} - The string to use for the 'label' of a Google
  70. * analytics event.
  71. * @private
  72. */
  73. _extractLabel(event) {
  74. const { attributes = {} } = event;
  75. const labelsArray
  76. = Object.keys(attributes).map(key => `${key}=${attributes[key]}`);
  77. labelsArray.push(this._userPropertiesString);
  78. return labelsArray.join('&');
  79. }
  80. /**
  81. * Sets the permanent properties for the current session.
  82. *
  83. * @param {Object} userProps - The permanent portperties.
  84. * @returns {void}
  85. */
  86. setUserProperties(userProps = {}) {
  87. if (!this._enabled) {
  88. return;
  89. }
  90. // The label field is limited to 500B. We will concatenate all
  91. // attributes of the event, except the user agent because it may be
  92. // lengthy and is probably included from elsewhere.
  93. const filter = [ 'user_agent', 'callstats_name' ];
  94. this._userPropertiesString
  95. = Object.keys(userProps)
  96. .filter(key => filter.indexOf(key) === -1)
  97. .map(key => `permanent_${key}=${userProps[key]}`)
  98. .join('&');
  99. }
  100. /**
  101. * This is the entry point of the API. The function sends an event to
  102. * google analytics. The format of the event is described in
  103. * analyticsAdapter in lib-jitsi-meet.
  104. *
  105. * @param {Object} event - The event in the format specified by
  106. * lib-jitsi-meet.
  107. * @returns {void}
  108. */
  109. sendEvent(event) {
  110. if (this._shouldIgnore(event)) {
  111. return;
  112. }
  113. const gaEvent = {
  114. 'eventCategory': 'jitsi-meet',
  115. 'eventAction': this._extractName(event),
  116. 'eventLabel': this._extractLabel(event)
  117. };
  118. const value = this._extractValue(event);
  119. if (!isNaN(value)) {
  120. gaEvent.eventValue = value;
  121. }
  122. ga('send', 'event', gaEvent);
  123. }
  124. }
  125. const globalNS = getJitsiMeetGlobalNS();
  126. globalNS.analyticsHandlers = globalNS.analyticsHandlers || [];
  127. globalNS.analyticsHandlers.push(GoogleAnalyticsHandler);