Skip to content

Instantly share code, notes, and snippets.

@matthewepler
Created June 26, 2018 21:25
Show Gist options
  • Save matthewepler/db8c12351befb37984ab1ee18dadff11 to your computer and use it in GitHub Desktop.
Save matthewepler/db8c12351befb37984ab1ee18dadff11 to your computer and use it in GitHub Desktop.
tracking pageviews with HOC in single page application - Keen + Google Analytics
import React, { Component } from 'react';
import Keen from 'keen-tracking';
import MobileDetect from 'mobile-detect';
import GoogleAnalytics from 'react-ga';
const debug = process.env.NODE_ENV === 'development';
const rootURL = debug ? 'http://localhost:3000' : 'https://helloroo.org'; // see line 51
GoogleAnalytics.initialize(`${debug ? 'UA-121464346-2' : 'UA-121464346-1'}`, {
debug,
});
function initKeen() {
const md = new MobileDetect();
if (md.is('bot')) {
return false;
}
const helpers = Keen.helpers;
const utils = Keen.utils;
const sessionCookie = utils.cookie('session-cookie');
if (!sessionCookie.get('guest_id')) {
sessionCookie.set('guest_id', helpers.getUniqueId());
}
const keenClient = new Keen({
projectId: process.env.KEEN_PROJECT_ID,
writeKey: process.env.KEEN_WRITE_KEY,
host: 'api.keen.io',
protocol: 'https',
requestType: 'jsonp',
});
// // Optionally prevent recording in dev mode
// Keen.enabled = true;
// Display events in the browser console
if (debug) {
Keen.debug = true;
keenClient.on('recordEvent', Keen.log);
keenClient.on('recordEvents', Keen.log);
}
// Add custom properties to all events
keenClient.extendEvents(() => {
return {
geo: {
info: {
/* Enriched */
},
ip_address: '${keen.ip}',
},
page: {
info: {
/* Enriched */
},
title: document.title,
url: document.location.href,
},
referrer: {
info: {
/* Enriched */
},
url: document.referrer,
},
tech: {
browser: helpers.getBrowserProfile(),
info: {
/* Enriched */
},
user_agent: '${keen.user_agent}',
device_type: md.tablet()
? 'tablet'
: md.mobile()
? 'mobile'
: 'desktop',
},
time: helpers.getDatetimeIndex(),
visitor: {
guest_id: sessionCookie.get('guest_id'),
/* Include additional visitor info here */
},
keen: {
addons: [
{
name: 'keen:ip_to_geo',
input: {
ip: 'geo.ip_address',
},
output: 'geo.info',
},
{
name: 'keen:ua_parser',
input: {
ua_string: 'tech.user_agent',
},
output: 'tech.info',
},
{
name: 'keen:url_parser',
input: {
url: 'page.url',
},
output: 'page.info',
},
{
name: 'keen:date_time_parser',
input: {
date_time: 'keen.timestamp',
},
output: 'timestamp_info',
},
],
},
};
});
/*
There are two ways to record an event. You can do it here with DOM selectors (see below),
or you can do it inside the code where you have access to stuff like state and props.
*/
// Keen.listenTo({
// 'click .action_button, .action_button *': function(e){
// console.log('currentTarget: ', e.currentTarget); // returns #document. If you need currentTarget, see my implementation below
// }
// });
/* DOM Event Capturing - preserves event.currentTarget */
// window.onload = ()=> {
// const resourceButtons = document.querySelectorAll('.action_button');
// resourceButtons.forEach( (button) => {
// button.addEventListener('click', (e) => {
// console.log(e.currentTarget); // will return the node the listener is attached to, even if you click a child
// });
// });
// };
return keenClient;
}
export const keenClient = initKeen();
/* HOC for tracking page views with React Router */
export const withTracker = (WrappedComponent: React.ComponentType, options = {}) => {
const trackPage = page => {
keenClient.recordEvent('pageviews', { ...options });
GoogleAnalytics.set({
page,
...options,
});
GoogleAnalytics.pageview(page);
};
const HOC = class extends Component {
componentDidMount() {
const page = this.props.location.pathname;
trackPage(page);
// alt approach:
// const href = window.location.href;
// const page = href.replace(rootURL, '');
// // const pageWithoutQuery = page.replace(/\?[^&?]*?=[^&?]*/, '');
// // const pageWithoutHash = pageWithoutQuery.replace('/#', '');
// trackPage(page);
}
getDerivedStateFromProps(nextProps) {
const currentPage = this.props.location.pathname;
const nextPage = nextProps.location.pathname;
if (currentPage !== nextPage) {
trackPage(nextPage);
}
}
render() {
return <WrappedComponent {...this.props} />;
}
};
return HOC;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment