diff --git a/src/lib/analytics.js b/src/lib/analytics.js index c498c26f3..d4892d75f 100644 --- a/src/lib/analytics.js +++ b/src/lib/analytics.js @@ -1,23 +1,62 @@ -import GoogleAnalytics from 'react-ga'; +// This was originally a thin wrapper around `react-ga`, which only supports UA. +// We now use GTM, so we could use `react-gtm-module`, but it doesn't support GTM environments (GTM_ENV_AUTH). +// So we use the GTM snippets directly. -import log from './log'; +const GTM_ID = (process.env.GTM_ID || window.GTM_ID); +const GTM_ENV_AUTH = (process.env.GTM_ENV_AUTH || window.GTM_ENV_AUTH || ''); -const GA_ID = (process.env.GA_ID || window.GA_ID); -if (GA_ID) { - GoogleAnalytics.initialize(GA_ID, { - debug: (process.env.NODE_ENV !== 'production'), - titleCase: true, - sampleRate: (process.env.NODE_ENV === 'production') ? 100 : 0, - forceSSL: true - }); -} else { - log.info('Disabling GA because GA_ID is not set.'); - window.ga = () => { - // The `react-ga` module calls this function to implement all Google Analytics calls. Providing an empty - // function effectively disables `react-ga`. This is similar to the `testModeAPI` feature of `react-ga` except - // that `testModeAPI` logs the arguments of every call into an array. That's nice for testing purposes but - // would look like a memory leak in a live program. - }; +/** + * Build the HTML snippets to load GTM. + * Call this ONLY if GTM_ID is a valid Tag Manager ID. GTM_ENV_AUTH should be valid or an empty string. + * The content of the snippets is taken from the GTM web interface. We should check there periodically for changes. + * @returns {object} an object the GTM snippets. + * @property {string} script The snippet to load GTM when JavaScript is enabled. Add this to the element. + * @property {string} noscript The snippet to load GTM when JavaScript is disabled. Add this to the element. + */ +const makeGtmSnippets = () => ({ + script: + ` + + `, + noscript: + ` + + ` +}); + +if (GTM_ID) { + // load GTM + const snippets = makeGtmSnippets(); + + const noscript = document.createElement('noscript'); + noscript.innerHTML = snippets.noscript; + + const script = document.createElement('script'); + script.innerHTML = snippets.script; + + document.head.insertBefore(script, document.head.firstChild); + document.body.insertBefore(noscript, document.body.firstChild); } -export default GoogleAnalytics; +/** + * Report analytics to GA4 using an interface similar to the 'react-ga' module we were using for UA. + */ +const GA4 = { + event: ({category, action, label}) => { + window.dataLayer = window.dataLayer || []; + // There is no perfect mapping from UA to GA4 + // See https://support.google.com/analytics/answer/11091025 + window.dataLayer.push({ + event: category, + action, + label + }); + } +}; + +export default GA4; diff --git a/src/playground/index.jsx b/src/playground/index.jsx index dcf6fa181..6ff33f7e8 100644 --- a/src/playground/index.jsx +++ b/src/playground/index.jsx @@ -7,16 +7,12 @@ import 'intl'; // For Safari 9 import React from 'react'; import ReactDOM from 'react-dom'; -import analytics from '../lib/analytics'; import AppStateHOC from '../lib/app-state-hoc.jsx'; import BrowserModalComponent from '../components/browser-modal/browser-modal.jsx'; import supportedBrowser from '../lib/supported-browser'; import styles from './index.css'; -// Register "base" page view -analytics.pageview('/'); - const appTarget = document.createElement('div'); appTarget.className = styles.app; document.body.appendChild(appTarget);