Skip to content

Commit

Permalink
feat: add support for multiple instances & custom script source to GA
Browse files Browse the repository at this point in the history
Signed-off-by: DavidWells <[email protected]>
  • Loading branch information
DavidWells committed May 12, 2020
1 parent 6af330b commit c9b2510
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 57 deletions.
143 changes: 87 additions & 56 deletions packages/analytics-plugin-google-analytics/src/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const defaultConfig = {
// TODO contentGroupings: { key: 'contentGroup1' }
}

let loadedInstances = {}

/**
* Google analytics plugin
* @link https://getanalytics.io/plugins/google-analytics/
Expand All @@ -31,6 +33,8 @@ const defaultConfig = {
* @param {object} [pluginConfig.customDimensions] - Map [Custom dimensions](https://bit.ly/3c5de88) to send extra information to Google Analytics. [See details below](#using-ga-custom-dimensions)
* @param {object} [pluginConfig.resetCustomDimensionsOnPage] - Reset custom dimensions by key on analytics.page() calls. Useful for single page apps.
* @param {boolean} [pluginConfig.setCustomDimensionsToPage] - Mapped dimensions will be set to the page & sent as properties of all subsequent events on that page. If false, analytics will only pass custom dimensions as part of individual events
* @param {string} [pluginConfig.instanceName] - Custom tracker name for google analytics. Use this if you need multiple googleAnalytics scripts loaded
* @param {string} [pluginConfig.customScriptSrc] - Custom URL for google analytics script, if proxying calls
* @return {*}
* @example
*
Expand All @@ -40,14 +44,77 @@ const defaultConfig = {
*/
function googleAnalytics(pluginConfig = {}) {
let pageCalledOnce = false
// Allow for userland overides of base methods
// Allow for multiple google analytics instances
const { instanceName, instancePrefix } = getInstanceDetails(pluginConfig)
return {
NAMESPACE: 'google-analytics',
name: 'google-analytics',
config: {
...defaultConfig,
...pluginConfig
},
initialize: initialize,
// Load google analytics
initialize: (pluginApi) => {
const { config, instance } = pluginApi
if (!config.trackingId) throw new Error('No google analytics trackingId defined')

// Load google analytics script to page
if (gaNotLoaded()) {
// var to hoist
var scriptSrc = config.customScriptSrc || 'https://www.google-analytics.com/analytics.js';
/* eslint-disable */
(function(i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function() {
(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)
})(window, document, 'script', scriptSrc, 'ga')
/* eslint-enable */
}

// Initialize tracker instance on page
if (!loadedInstances[instanceName]) {
const gaConfig = {
cookieDomain: config.domain || 'auto',
siteSpeedSampleRate: config.siteSpeedSampleRate || 1,
sampleRate: config.sampleRate || 100,
allowLinker: true,
// useAmpClientId: config.useAmpClientId
}
if (instanceName) {
gaConfig.name = instanceName
}

/* eslint-disable */
(function(i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function() {
(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)
})(window, document, 'script', scriptSrc, 'ga')
/* eslint-enable */

ga('create', config.trackingId, gaConfig)

if (config.debug) {
// Disable sends to GA http://bit.ly/2Ro0vTR
ga(`${instancePrefix}set`, 'sendHitTask', null)
window.ga_debug = { trace: true }
}

if (config.anonymizeIp) {
ga(`${instancePrefix}set`, 'anonymizeIp', true)
}

/* set custom dimenions from user traits */
const user = instance.user() || {}
const traits = user.traits || {}
if (Object.keys(traits).length) {
const customDimensions = formatObjectIntoDimensions(traits, config)
ga(`${instancePrefix}set`, customDimensions)
}
loadedInstances[instanceName] = true
}
},
// Google Analytics page view
page: ({ payload, config, instance }) => {
const { properties } = payload
Expand All @@ -65,7 +132,7 @@ function googleAnalytics(pluginConfig = {}) {
}, {})
if (Object.keys(resetDimensions).length) {
// Reset custom dimenions
ga('set', resetDimensions)
ga(`${instancePrefix}set`, resetDimensions)
}
}

Expand All @@ -88,7 +155,7 @@ function googleAnalytics(pluginConfig = {}) {

const campaignData = addCampaignData(campaign)

const dimensions = setCustomDimenions(properties, config)
const dimensions = setCustomDimenions(properties, config, instancePrefix)

/* Dimensions will only be included in the event if config.setCustomDimensionsToPage is false */
const finalPayload = {
Expand All @@ -97,15 +164,15 @@ function googleAnalytics(pluginConfig = {}) {
...dimensions
}

ga('set', pageData)
ga(`${instancePrefix}set`, pageData)

// Remove location for SPA tracking after initial page view
if (pageCalledOnce) {
delete finalPayload.location
}

/* send page view to GA */
ga('send', 'pageview', finalPayload)
ga(`${instancePrefix}send`, 'pageview', finalPayload)

// Set after initial page view
pageCalledOnce = true
Expand Down Expand Up @@ -150,51 +217,14 @@ function gaNotLoaded() {
return typeof ga === 'undefined'
}

export function initialize(pluginApi) {
const { config, instance } = pluginApi
if (!config.trackingId) throw new Error('No google analytics trackingId defined')
if (gaNotLoaded()) {
/* eslint-disable */
(function(i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function() {
(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)
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga')
/* eslint-enable */
ga('create', config.trackingId, 'auto')

if (config.debug) {
// Disable sends to GA http://bit.ly/2Ro0vTR
ga('set', 'sendHitTask', null)
window.ga_debug = { trace: true }
}

if (config.anonymizeIp) {
ga('set', 'anonymizeIp', true)
}

/* set custom dimenions from user traits */
const user = instance.user() || {}
const traits = user.traits || {}
if (Object.keys(traits).length) {
const customDimensions = formatObjectIntoDimensions(traits, config)
ga('set', customDimensions)
}
function getInstanceDetails(pluginConfig) {
const { instanceName } = pluginConfig
return {
instancePrefix: (instanceName) ? `${instanceName}.` : '',
instanceName: instanceName
}
}

/**
* Send page view to google analytics
* @param {string} [urlPath = location.pathname] - path of current path
*/
export function pageView(urlPath) {
if (gaNotLoaded()) return
const path = urlPath || document.location.pathname
ga('set', 'page', path)
ga('send', 'pageview')
}

/**
* Send event tracking to Google Analytics
* @param {object} eventData - GA event payload
Expand All @@ -207,7 +237,7 @@ export function pageView(urlPath) {
*/
export function trackEvent(eventData, opts = {}, payload) {
if (gaNotLoaded()) return

const { instancePrefix } = getInstanceDetails(opts)
const data = {
// hitType https://bit.ly/2Jab9L1 one of 'pageview', 'screenview', 'event', 'transaction', 'item', 'social', 'exception', 'timing'
hitType: eventData.hitType || 'event',
Expand All @@ -229,7 +259,7 @@ export function trackEvent(eventData, opts = {}, payload) {
/* Attach campaign data */
const campaignData = addCampaignData(eventData)
/* Set Dimensions or return them for payload is config.setCustomDimensionsToPage is false */
const dimensions = setCustomDimenions(payload.properties, opts)
const dimensions = setCustomDimenions(payload.properties, opts, instancePrefix)

const finalPayload = {
...data,
Expand All @@ -240,7 +270,7 @@ export function trackEvent(eventData, opts = {}, payload) {
}

/* Send data to Google Analytics */
ga('send', 'event', finalPayload)
ga(`${instancePrefix}send`, 'event', finalPayload)
return finalPayload
}

Expand Down Expand Up @@ -303,7 +333,7 @@ function get(obj, key, def, p, undef) {
return obj === undef ? def : obj
}

function setCustomDimenions(props = {}, opts) {
function setCustomDimenions(props = {}, opts, instancePrefix) {
const customDimensions = formatObjectIntoDimensions(props, opts)
if (!Object.keys(customDimensions).length) {
return {}
Expand All @@ -313,7 +343,7 @@ function setCustomDimenions(props = {}, opts) {
return customDimensions
}
// Set custom dimensions
ga('set', customDimensions)
ga(`${instancePrefix}set`, customDimensions)
return {}
}

Expand All @@ -323,10 +353,11 @@ function setCustomDimenions(props = {}, opts) {
*/
export function identifyVisitor(id, traits = {}, conf = {}) {
if (gaNotLoaded()) return
if (id) ga('set', 'userId', id)
const { instancePrefix } = getInstanceDetails(conf)
if (id) ga(`${instancePrefix}set`, 'userId', id)
if (Object.keys(traits).length) {
const custom = formatObjectIntoDimensions(traits, conf)
ga('set', custom)
ga(`${instancePrefix}set`, custom)
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/analytics-plugin-google-analytics/src/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ if (!process.browser) {
function googleAnalytics(pluginConfig = {}) {
const client = initialize(pluginConfig)
return {
NAMESPACE: 'google-analytics',
name: 'google-analytics',
config: pluginConfig,
// page view
page: ({ payload, config }) => {
Expand Down

0 comments on commit c9b2510

Please sign in to comment.