Custom hook to connect Google Analytics in React

Create a custom hook to connect Google Analytics in React using react-router-dom and react-ga packages
react
Written on August 06, 2020 ·
4 min read

TL;DR

We'll create a custom React hook that setups Google Analytics to a CRA app. The React app uses the react-router-dom and react-ga modules.

A quick explanation of what we want to achieve.

Google Analytics is a web analytics service offered by Google that tracks and reports website traffic. They offer a great dashboard and the service is free.

Our goal is to connect the Google Analytics to our React app using some utility functions and a custom React hook that handles the initialization of the ga object.

Installation

We start with the creation of a new React app using create-react-app and npx:

bash

npx create-react-app demo-app
cd demo-app

Then, we install the two dependencies. The react-router-dom library which is the de-facto routing solution in React. and react-ga the official Google Analytics React package:

bash

yarn add react-router-dom react-ga

Or if you're using npm:

bash

npm install --save react-router-dom react-ga

Create the analytics.js file

Our first step is to create the file analytics.js where we're going to create the Google Analytics init function and define two helpers to fire custom events and the pageview one.

We utilize the react-ga's method initialize to set up the Google Analytics with our unique tracking id. You can pass more options to the initialize function but we'll only enable debug logging for the local development mode.

Then we create the two extra helper functions, sendEvent() and sendPageview(), that simply fire a custom event and the pageview one respectively.

js

import ReactGA from "react-ga"
const TRACKING_ID = "UA-XXXXXXXXX-X"
function init() {
// Enable debug mode on the local development environment
const isDev = !process.env.NODE_ENV || process.env.NODE_ENV === "development"
ReactGA.initialize(TRACKING_ID, { debug: isDev })
}
function sendEvent(payload) {
ReactGA.event(payload)
}
function sendPageview(path) {
ReactGA.set({ page: path })
ReactGA.pageview(path)
}
export default {
init,
sendEvent,
sendPageview,
}

Define the App component

Now we have to create the App component that renders the pages of our app. To keep it simple, I define 3 dummy routes, /, /features, and /signup.

I use BrowserRouter over the pure Router because it ignores the history prop and handles the history object automatically for you.

The Switch component selects the first route that fits the location and renders it. So it renders only one route!

jsx

import React from "react"
import { BrowserRouter, Switch, Route } from "react-router-dom"
import Home from "./pages/Home"
import Features from "./pages/Features"
import SignUp from "./pages/SignUp"
function App() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route exact path="/features">
<Features />
</Route>
<Route exact path="/signup">
<SignUp />
</Route>
</Switch>
</BrowserRouter>
)
}
export default App

Build the custom useGoogleAnalytics hook

Since we don't handle history manually (BrowserRouter does this for us), our only option to access the current location object is by using the useLocation hook by react-router-dom.

So, we define two useEffect hooks. The first useEffect simulates the known componentDidMount function and initializes the ga object. The second one listens on every location change and sends the valuable pageview event.

Pretty straightforward, huh?!

jsx

import React from "react"
import { useLocation } from "react-router-dom"
import analytics from "./analytics"
export default function useGoogleAnalytics() {
const location = useLocation()
React.useEffect(() => {
analytics.init()
}, [])
React.useEffect(() => {
const currentPath = location.pathname + location.search
analytics.sendPageview(currentPath)
}, [location])
}

Let's call our hook

We go to our App component and we call our custom hook function.

jsx

function App() {
useGoogleAnalytics()
return (
<BrowserRouter>
<Switch>...</Switch>
</BrowserRouter>
)
}

There is a problem though. Our hook depends on the current location object which is not available yet on the App components

A quick solution is to create a separate component called Routes that renders the Switch component and its children and calls the custom hook from there.

Doing that we can be sure that the BrowserRouter component exists and has defined the location object before rendering Routes.

jsx

function Routes() {
useGoogleAnalytics()
return (
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route exact path="/features">
<Features />
</Route>
<Route exact path="/signup">
<SignUp />
</Route>
</Switch>
)
}
function App() {
return (
<BrowserRouter>
<Routes />
</BrowserRouter>
)
}

That's all folks! You have successfully added Google Analytics in your React app!

Now, you can fire custom events from any component you like by just importing and calling the sendEvent function from the analytics.js file.

If you liked this post, you can follow me on Twitter where I share daily tips about coding, design and bootstrapping micro-startups.

Join my weekly newsletter

It’s one email a week with everything interesting I’ve built or found, plus new articles and apps.