Working example with NextJS
Do you have an example for a site that supports SSR? I am using NextJS and I am not able to limit importing the vendor/GoogleAnalytics.js class to only client side rendering. How do I replace the GoogleAnalyticsStub below to get this working?
metrics.config.js
import { ga } from 'client-config'
import GoogleAnalytics from '../lib/GoogleAnalytics'
const MetricsConfig = {
vendors: [{
name: 'Google Analytics',
api: new GoogleAnalytics({
trackingId: ga.tracking_id
})
}],
pageViewEvent: 'pageLoad',
pageDefaults: () => {
return {
environment: ga.environment,
siteName: ga.siteName,
timestamp: Date.now(),
path: '/'
}
},
debug: ga.debug
}
export default MetricsConfig
Layout.js
import React from 'react'
import pageLoadTracking from '../lib/pageLoadTracking'
const Layout = ({ children }) => (
<Main>
{children}
</Main>
)
export default pageLoadTracking(Layout)
package.json
"dependencies": {
"above-the-fold-only-server-render": "^1.0.3",
"analytics.js": "^2.9.1",
"config": "^1.25.1",
"express": "^4.15.2",
"js-yaml": "^3.8.3",
"mkdirp": "^0.5.1",
"next": "^2.3.1",
"next-routes": "^1.0.26",
"prop-types": "^15.5.8",
"react": "^15.5.4",
"react-apollo": "^1.2.0",
"react-dom": "^15.5.4",
"react-ga": "^2.2.0",
"react-gpt": "^0.2.4",
"react-metrics": "^2.3.1",
"react-no-ssr": "^1.1.0",
"styled-components": "^1.4.5"
},
"devDependencies": {
"babel-eslint": "^7.2.3",
"babel-plugin-module-resolver": "^2.7.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"babel-register": "^6.24.1",
"chai": "^3.5.0",
"enzyme": "^2.8.2",
"ignore-styles": "^5.0.1",
"jsdom": "^9.12.0",
"lighthouse": "^1.6.3",
"mocha": "^3.2.0",
"nightwatch": "^0.9.14",
"phantomjs-prebuilt": "^2.1.14",
"react-test-renderer": "^15.5.4",
"selenium-server": "^3.3.1",
"sinon": "^2.1.0",
"standard": "^10.0.1"
},
GoogleAnalytics.js
let analytics
if (process.browser) {
analytics = require('analytics.js') // eslint-disable-line global-require
}
/**
* Performs the tracking calls to Google Analytics.
* Utilizing Segment IO Analytics Integration.
*
* @module GoogleAnalytics
* @class
* @internal
*/
class GoogleAnalytics {
constructor (options = {}) {
this.name = 'Google Analytics'
this._loaded = false
this.options = options
}
/**
*
* @method pageView
* @param {String} eventName
* @param {Object} params
* @returns {Promise}
* @internal
*/
pageView (...args) {
return this.track(...args)
}
user (userId) {
return new Promise((resolve) => {
this.userId = userId
resolve({
userId
})
})
}
/**
*
* @method track
* @param {String} eventName
* @param {Object} params
* @returns {Promise}
* @internal
*/
track (eventName, params) {
return new Promise((resolve, reject) => {
this._load().then(() => {
this._track(eventName, params)
resolve({
eventName,
params
})
}).catch((error) => {
console.error('GA: Failed to initialize', error)
reject(error)
})
})
}
/**
*
* @method _track
* @param {String} eventName
* @param {Object} params
* @protected
*/
_track (eventName, params) {
if (eventName === 'pageView') {
analytics.page(params.category, params)
return
}
analytics.track(eventName, params)
}
/**
*
* @method _load
* @protected
*/
_load () {
return this._promise || (this._promise = new Promise((resolve) => {
if (this._loaded) {
resolve()
} else {
analytics.once('ready', () => {
this._loaded = true
resolve()
})
analytics.initialize({
'Google Analytics': this.options
})
}
}))
}
}
export default GoogleAnalytics
@jdwinall-tm Importing the library on the server side shouldn't cause an issue, as long as you make sure it's not firing any events on the server side.
I think this might solve your issue: https://github.com/nfl/react-metrics#override-default-page-view-tracking specifically this chunk of code:
componentDidMount() {
const {value1, value2} = this.props;
this.context.metrics.pageView({value1, value2});
}
Placing the logic in componentDidMount will force react to run it on the client side instead of the server side. Let me know if you need any more info!
@jamsea Is there a way to implement this on a component that is not a "route handling" component?
My issues seems to be with GoogleAnalytics.js. The first line of this file includes analytics.js, which imports analytics.js on the server and the client.
@jamsea I updated the issue description to include my GoogleAnalytics.js file. Adding the following lines addressed my client errors on the server issue.
let analytics
if (process.browser) {
analytics = require('analytics.js') // eslint-disable-line global-require
}
My only remaining issue is related to sending the active page when navigating between links with NextJS. When I view the real time content activity while browsing my dev site, my entry page reports correctly. However, when I click a link in the site, the page title updates but the active page stays the same (whatever the entry point to the application was).