Need help integrating page view tracking into React SPA

Hi,
I’m new to Matomo and I’m trying to integrate page view tracking into my single-page website in React, and I haven’t managed to get it to work. I’m following the guide here Single-Page Application Tracking: Integrate - Matomo Analytics (formerly Piwik Analytics) - Developer Docs - v3
but the hash change listening function isn’t working. I have the feeling I’m making some basic error, does anyone have advice on how to do this? My code looks like this:

    <script type="text/javascript">
        var _paq = window._paq || [];
        /* tracker methods like "setCustomDimension" should be called before "trackPageView" */
        _paq.push(["setDocumentTitle", document.domain + "/" + document.title]);
        _paq.push(["setCookieDomain", "*.<MY_WEBSITE>"]);
        _paq.push(['trackPageView']);
        _paq.push(['enableLinkTracking']);
        (function() {
        var u="https://<MY_WEBSITE>";
        _paq.push(['setTrackerUrl', u+'matomo.php']);
        _paq.push(['setSiteId', '<MY SITE ID>']);
        var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
        g.type='text/javascript'; g.async=true; g.defer=true; g.src='//<MY_WEBSITE>/matomo.js'; s.parentNode.insertBefore(g,s);
        })();

        var currentUrl = location.href;
        window.addEventListener('hashchange', function() {
            _paq.push(['setReferrerUrl', currentUrl]);
            currentUrl = '/' + window.location.hash.substr(1);
            _paq.push(['setCustomUrl', currentUrl]);
            _paq.push(['setDocumentTitle', 'My New Title']);
        });
    </script>
    <!-- End Matomo Code -->

I’ve pasted this before the head closing tag in index.html. I’ve seen some posts suggesting to add the following to my React router
_paq.push([‘setCustomUrl’, ‘/’ + window.location.hash.substr(1)]);
_paq.push([‘setDocumentTitle’, ‘My New Title’]);
_paq.push([‘trackPageView’]);

but it’s not clear to me how to do this. Can anyone show me an explicit example of how to do this?

Thanks!

Hi,

Stupid question, but are you using hashes to specify the routes in react? If you aren’t changing hashes when changing pages, obviously the hashchange listener won’t work.

The easiest way is to simply integrate the code into your router and call the code inside the eventlistener everytime the user changes a route.

Yes I am, but a good question. Could you give a code example of integrating it into a React router?

I know little about React, so I can’t really help there.

But you could use an existing library or check how they did it:

Thanks for the link, will try to see how they implemented it

I managed to do this by embedding the following on each of the pages I wanted to track:

// Trigger pageview tracking on mounting of React component
componentDidMount() {
this.registerPageLoad();
// Other component mounting logic if needed
}

// Push pageview event to Matomo on component mount
registerPageLoad(){
    var _paq = window._paq || [];
    _paq.push(['setCustomUrl', '/MyURL']);
    _paq.push(['setDocumentTitle', 'My Document Title']);
    _paq.push(['trackPageView']);
}

I’m sure the integrating it into the React Router is the better way to go, but I didn’t manage it yet. If I do I will post it. Thanks again for your help Lukas.

Instead of adding the code on every component, is there any other solution? So that we can have these few lines of code at one place when a page/location change event is get triggered?

Can any one help?

There should be no need to modify every component.

The router of the SPA framework you are using most likely has some feature that allows executing custom Javascript on every pageview.

Found a solution for react
(Don’t know if you were using that one)

You can use the function in App.js instead of using it on each page:

// Push pageview event to Matomo on component mount

const registerPageLoad = () => {

var _paq = window._paq || [];

_paq.push(['setCustomUrl', history.location.pathname]);

_paq.push(['setDocumentTitle', history.location.pathname]);

_paq.push(['trackPageView']);

};

useEffect(() => {

return history.listen((location) => {

  registerPageLoad();

});

// eslint-disable-next-line react-hooks/exhaustive-deps

}, [history]);

This article helped me get to this solution, thanks!

1 Like