Site analytics for redwoodjs

I’m getting ready for a wider launch of the Vida app (GitHub - vidalab/vida: Flexible data viz using redwoodjs framework). I want to add site tracking analytics. Two questions:

  1. Do redwoodjs community members have or implement an analytics? I’m familiar with mixpanel and Google Analytics. Any recommendations and solutions?
  2. I plan to implement a Cell to return the analytics key from the server-side to the client-side. This way, I can set an environment variable in Netlify to turn on analytics. Any other suggestions on how to implement analytics?

Thanks.

For implementation of the analytics you can modify the index.html file in web/ side.

You can use ENV VARS on the web side, here are the docs: https://redwoodjs.com/guides/environment-variables

2 Likes

@peterp looks like index.html is rendered before any react component is loaded. I wonder how I can reference environment variables in index.html.

Hmm, great point! I actually think you’d have to do this via index.js or even at the layout or page component level – I’ve found analytics in general to have some tricky nuances when it comes to SPAs.

You might be better off using an existing NPM package.

3 Likes

@thedavid, react-ga package is useful. It makes working with Google Analytics easy. I implemented some basic tracking. And yes, I need to initialize in index.js.

React makes analytics more complicated. I have to call pageview in every single page of the app. Like this:

I think redwood router can provide some kind of hooks to make this easier.

1 Like

Oh, that’s a really good point and we’re looking at ways to improve the Router (accessibility being a priority right now). Do you have any more specifics about this, and/or would you be up for creating a new feature request Issue in GitHub about this? I think the more possible examples or ideas about how it could work (even from other existing Router implementations, if applicable) the more likely it is this would get some momentum.

I also needed to add Google Analytics to a Redwood site, and discovered autotrack. It was really straightforward to set up, and handles automatically triggering a GA pageview even when using redwood-router.

There was a link in one of the issues to a repository that does a good job of showing how to set it up.

It would definitely be good to see an “official” recommendation for how to automatically track analytics in a Redwood SPA. I wanted to use Segment or Google Tag Manager, but the information I could find was unhelpful in the context of a SPA.

2 Likes

@bennett thanks for the pointer to autotrack. I play around with it a little bit. It works on page load. But it does not do pageview tracking properly. Page navigation with router does not trigger pageview events.

@thedavid, I found this thread in the react-ga project. One way is to use history listener on react-router. Redwood router does not seem to expose a history listener. We can also wrap components around inside an analytics component.

1 Like

@dnprock I’m pretty sure page navigation tracking via redwood-router is working for me. In my analytics.js file I’ve got:

import 'autotrack';

ga('create', process.env.REDWOOD_ENV_GOOGLE_ANALYTICS_TRACKING_ID, 'auto');
ga('require', 'urlChangeTracker');
ga('require', 'cleanUrlTracker');
ga('require', 'outboundLinkTracker');
ga('send', 'pageview');

The important one is the urlChangeTracker (docs here).

1 Like

@bennett thanks for the pointer. I’ll check it again.

In my latest CRA SPA I’ve done this:

My router: (The important line is <GATracker />)

const App = () => {
    return (
        <BrowserRouter>
            <GATracker />
            <Switch>
                <Route path={names.DOCS}>
                    <Docs />
                </Route>
                <Route path=...>
                    // ...
                </Route>
                // ...
            </Switch>
        </BrowserRouter>
    );
};

And this is <GATracker /> (Sorry for the half-assed attempt at TS-ify this…)

import React, { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

declare global {
    interface Window {
        ga:
            | {
                  (...args: any[]): void;
                  l: number;
                  q: any[];
              }
            | undefined;
    }
}

const dev = process.env.NODE_ENV === 'development';

// prettier-ignore
// @ts-ignore
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};
window.ga && (window.ga.l = +new Date());
window.ga?.('create', process.env.REACT_APP_GA_TRACKING_ID, 'auto');

export const GATracker: React.FC<{}> = () => {
    const location = useLocation();

    useEffect(() => {
        if (!window.ga || dev) {
            return;
        }

        window.ga('send', 'pageview', location.pathname + location.search);
    }, [location]);

    return null;
};
4 Likes

For Matomo, I used this code on my AppLayout(used in Routes’ <Set wrap={AppLayout}>)

  const { pathname, search, hash } = useLocation()
  // https://redwoodjs.com/docs/router#uselocation
  // log the URL to Matomo when the pathname changes
  React.useEffect(() => {
    // https://developer.matomo.org/guides/spa-tracking
    //@ts-expect-error _mtm does exist if configurated well
    window._mtm?.push({'event': 'mtm.PageView'});
  }, [pathname])
1 Like