91

I am trying to add Google Analytics to a React Web Application.

I know how to do it in HTML/CSS/JS sites and I have integrated it in an AngularJS app too. But, I'm not quite sure how to go about it when it comes to react.

With HTML/CSS/JS, I had just added it to every single page.

What I had done with AngularJS was adding GTM and GA script to index.html and added UA-labels to the HTML divs (and buttons) to get clicks.

How can I do that with React?

Please help!

1

9 Answers 9

131

Update: August 2023
The old Package react-ga is now archived since it doesn't support Google Analytics version 4. There's a new package named react-ga4.
Add it by running:
npm i react-ga4

Initialization

import ReactGA from "react-ga4";

ReactGA.initialize("your GA measurement id");

To report page view:

ReactGA.send({ hitType: "pageview", page: "/my-path", title: "Custom Title" });

To report custom event:

ReactGA.event({
  category: "your category",
  action: "your action",
  label: "your label", // optional
  value: 99, // optional, must be a number
  nonInteraction: true, // optional, true/false
  transport: "xhr", // optional, beacon/xhr/image
});

Update: Feb 2019
As I saw that this question is being searched a lot, I decided to expand my explanation.
To add Google Analytics to React, I recommend using React-GA.
Add by running:
npm install react-ga --save

Initialization:
In a root component, initialize by running:

import ReactGA from 'react-ga';
ReactGA.initialize('Your Unique ID');

To report page view:

ReactGA.pageview(window.location.pathname + window.location.search);

To report custom event:

ReactGA.event({
  category: 'User',
  action: 'Sent message'
});

More instructions can be found in the github repo


The best practice for this IMO is using react-ga. Have a look at the github rep

22
  • 1
    You can get them by using event. Have a look here: github.com/react-ga/react-ga#reactgaeventargs
    – Matan Bobi
    Commented Mar 14, 2018 at 15:29
  • 2
    @ReemaParakh Sure. Just call ReactGA.pageview('your/page');
    – Matan Bobi
    Commented Dec 3, 2018 at 8:47
  • 3
    If you use react-router It seems easiest to me to put this integration in where you set up your routes: <Route path="/myroute" render={props => { ReactGA.pageview(props.location.pathname); return <MyRoute />; }} />
    – alaiacano
    Commented May 30, 2019 at 11:38
  • 1
    @MatanBobi nevermind, I figured it out: init at the top (above component class definition), and you log page views from componentDidMount
    – s2t2
    Commented Oct 12, 2020 at 20:42
  • 1
    @Prateek, you can do it, as other answers suggest.. But I believe in encapsulating this and just getting the functionality.
    – Matan Bobi
    Commented Apr 4, 2021 at 6:52
33

If you prefer not to use a package this is how it can work in a react application. Add the "gtag" in index.html

<!-- index.html -->

<script>
            window.dataLayer = window.dataLayer || [];
            function gtag() {
                dataLayer.push(arguments);
            }
            gtag("js", new Date());

            gtag("config", "<GA-PROPERTYID>");
        </script>

In the submit action of the login form, fire off the event

window.gtag("event", "login", {
            event_category: "access",
            event_label: "login"
        });
2
  • Any ideas how to gather all the information you need to pass to the gtag, which is scattered all across the app? It's easy to pass hardcoded string but when you have dynamic data (let's say for logged in users) that's complicated.
    – mkupiniak
    Commented Jan 30, 2023 at 14:52
  • @mkupiniak I would use a "closure" for that. developer.mozilla.org/en-US/docs/Web/JavaScript/Closures. It should allow you to capture state data from all over in the client and send it when firing the event.
    – Giwan
    Commented Jan 31, 2023 at 13:50
26

Without using a package this is how I would do it:

In your index.js (in the render method):

    {/* Global site tag (gtag.js) - Google Analytics */}
    <script
      async
      src="https://www.googletagmanager.com/gtag/js?id=YOUR_TRACKING_ID"
    />
    <script>{injectGA()}</script>

And outside the class:

const injectGA = () => {
  if (typeof window == 'undefined') {
    return;
  }
  window.dataLayer = window.dataLayer || [];
  function gtag() {
    window.dataLayer.push(arguments);
  }
  gtag('js', new Date());

  gtag('config', 'YOUR_TRACKING_ID');
};
8

There are 2 types of Google Analytics properties: Universal Analytics (UA-xxxxxxxxx-x) which is deprecated with the end of life on 2023.07.01 and Google Analytics 4 property (G-xxxxxxxxxx) which is the replacement.

react-ga was popular for Universal Analytics but the maintainer doesn't plan to update it (related issues: 1, 2, 3) and it had maintenance issues (1). react-ga4 and ga-4-react popped up as replacements but since these are similar wrappers you're at the mercy of the maintainers to implement and support all functionality.

The simplest way to get started is to follow Google's guide: include gtag on the page and use it as window.gtag. This method works for both old and new tags and there's even TypeScript support via @types/gtag.js. The script can be loaded async as recommended.

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- ... -->

    <script
      async
      src="https://www.googletagmanager.com/gtag/js?id=G-xxxxxxxxxx" >
    </script>
    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());
      gtag('config', 'G-xxxxxxxxxx')
    </script>

    <!-- ... -->
  </head>

  <body>
    <!-- ... -->
  </body>
</html>

Keep in mind that Google Analytics does automatic page tracking, but this will not work for every use case. For example, hash and search parameter changes are not tracked. This can lead to a lot of confusion. For example, when using HashRouter or anchor links the navigation will not be tracked. To have full control over page view tracking you can disable automatic tracking. See for a detailed explanation: The Ultimate Guide to Google Analytics (UA & GA4) on React (Or Anything Else

Manual page tracking: https://stackoverflow.com/a/63249329/2771889

You can see this working in cra-typescript-starter where I'm also setting the tag from an env var.

1
  • Most up to date answer since Universal Analytics was deprecated on July 2023.
    – Yacc
    Commented Aug 18, 2023 at 12:25
4

One other great library that you can check is redux-beacon.

It gets integrated very easily with react/redux application and has a great documentation for it. ReactGA is good too but with redux-beacon, you won't clutter your app code with google analytics code as it works via its own middleware.

1
  • 2
    This is the better solution if you're using redux in the application (which you probably should be doing). It's better to treat your analytics as an externality, rather than integral to your code. redux-beacon allows you to configure connections to multiple analytics services based on redux actions, avoiding coupling your code to your analytics provider. Commented Jul 18, 2018 at 14:22
4

Escape the analytics code with dangerouslySetInnerHTML

First you have of course to share the header code to all pages, e.g. as asked at: React js do common header

Then, this Next.js answer https://stackoverflow.com/a/24588369/895245 gives a good working code that should also work outside of Next.js. It escapes the analytics code with dangerouslySetInnerHTML:

  <script async src="https://www.googletagmanager.com/gtag/js?id=UA-47867706-3"></script>
  <script
    dangerouslySetInnerHTML={{
      __html: `window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-47867706-3', { page_path: window.location.pathname });
`,
    }}
  />

where you should replace UA-47867706-3 with your own code.

This code is exactly the code that Google gives, but with the following modification: we added the:

{ page_path: window.location.pathname }

to gtag('config' for it to be able to get the visited path, since this is a JavaScript SPA.

This generates the desired output on the browser:

<script async="" src="https://www.googletagmanager.com/gtag/js?id=UA-47867706-3"></script><script>window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-47867706-3', { page_path: window.location.pathname });
</script>

The only other divergence from the exact code given by Google is the async="" vs async, but both of those are equivalent in HTML since it is a boolean attribute, see also: What's the proper value for a checked attribute of an HTML checkbox?

Escaping with dangerouslySetInnerHTML is necessary because otherwise React interprets the code inside script a JSX and that fails with:

Syntax error: Unexpected token, expected "}"

  21 |           <script>
  22 |             window.dataLayer = window.dataLayer || [];
> 23 |             function gtag(){dataLayer.push(arguments);}
     |                                                      ^
  24 |             gtag('js', new Date());
  25 |
  26 |             gtag('config', 'UA-47867706-3');

I wish they would just automatically escape stuff inside script for us.

Finally to get page switches, you also have to track that with more code, see the Next.js answer mentioned above for an example.

Related: Adding script tag to React/JSX

Tested on react 17.0.2, next.js 10.2.2.

3
  • Do not follow such approaches dangerouslySetInnerHTML is React’s replacement for using innerHTML in the browser DOM but setting HTML from code is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS) attack.
    – NevetsKuro
    Commented Feb 5, 2022 at 3:53
  • 1
    @NevetsKuro there's no risk when injecting a string literal like this, only if you have user input variables. Commented Feb 5, 2022 at 7:24
  • Yes my bad. It is for the case for user input only. But you need to mention that in this solution, as React keeps popping this as a bug/warning. Ref: pragmaticwebsecurity.com/articles/spasecurity/…
    – NevetsKuro
    Commented Feb 7, 2022 at 6:41
0

I suggest embedding the Segment script into your index.html, use the analytics library that is accessible on the window object, and add tracking calls onto React’s event handlers:

export default class SignupButton extends Component {
  trackEvent() {
    window.analytics.track('User Signup');
  }

  render() {
    return (
      <button onClick={this.trackEvent}>
        Signup with Segment today!
      </button>
    );
  }
}

I’m the maintainer of https://github.com/segmentio/analytics-react. I recommend checking it out if you want to solve this problem by using one singular API to manage your customer data, and be able to integrate into any other analytics tool (we support over 250+ destinations) without writing any additional code. 🙂

1
0

Looking at google's site https://developers.google.com/analytics/devguides/collection/analyticsjs,

you could also add Google Analytics using this function:

const enableGA = () => {
  !function(A,n,g,u,l,a,r){A.GoogleAnalyticsObject=l,A[l]=A[l]||function(){
  (A[l].q=A[l].q||[]).push(arguments)},A[l].l=+new Date,a=n.createElement(g),
  r=n.getElementsByTagName(g)[0],a.src=u,r.parentNode.insertBefore(a,r)
  }(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-XXXXXXXX-X');
  ga('send', 'pageview');
}

This way you don't need an external library, and it's pretty quick to setup.

0
npm install react-ga

Add it to App.js

const TRACKING_ID = "G-YOUR ANALYTICS CODE";
ReactGA.initialize(TRACKING_ID);

If you're using react-router-dom you need to catch page switches, use this hook.

  function usePageViews() {
  let location = useLocation();
  useEffect(() => {
    ReactGA.pageview(location.pathname + location.search);
  }, [location]);
}

And call it inside your function

usePageViews();

Complete example :

import React, {useEffect} from 'react';
import {BrowserRouter as Router, Routes, Route, Navigate, useLocation} from 'react-router-dom';
import Homepage from "./pages/homepage";
import ReactGA from "react-ga";


const TRACKING_ID = "G-9N3HQMQXJT";
ReactGA.initialize(TRACKING_ID);

function usePageViews() {
    let location = useLocation();
    useEffect(() => {
        ReactGA.pageview(location.pathname + location.search);
    }, [location]);
}
function App() {
    usePageViews();
    return (
        <Router>
            <Routes>
                <Route path="/" element={<Navigate replace to="/homepage" />} />

                <Route path="/homepage" element={<Homepage />} />
                {/* Other Routes /*}


            </Routes>
        </Router>
    );
}

export default App;

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.