您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

GoogleAnalyticsHandler.ts 4.9KB

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