DEV Community

Cover image for Analytics with Next.js 13
Sebastian Sdorra
Sebastian Sdorra

Posted on • Originally published at sdorra.dev on

Analytics with Next.js 13

We will explore how to integrate analytic tools such as Google Analytics, Matomo or Fathom with the Next.js 13 app directory. In this article we will use Fathom, but the same principles could be applied to Google Analytics, Matomo or similar tools.

The new app directory of Next.js 13 comes with a lot of exiting new features, but the new router (next/navigation) unfortunately does not support events.

So we have to track route changes by ourselves. My first idea was to use the history api, but the history api does not send events for route changes!

The last option we have now is to override the pushState method and send an custom event:

var pushState = history.pushState;
history.pushState = function (state) {
  var result = pushState.apply(history, arguments);
  window.dispatchEvent(new Event("routeChange", state));
  return result;
};
Enter fullscreen mode Exit fullscreen mode

The snippet above overrides the pushState, calls the original function and sends a routeChange event afterwards.

Next.js

In Next.js we could use our method with the Script tag:

import { FC, PropsWithChildren } from "react";
import Script from "next/script";
import Analytics from "./Analytics";

const RootLayout: FC<PropsWithChildren> = ({ children }) => (
  <html>
    <body>
      <main>{children}</main>
      <Analytics />
      <Script id="onRouteChange">{`
        (function (history) {
          var pushState = history.pushState;
          history.pushState = function(state){
            var result = pushState.apply(history, arguments);
            window.dispatchEvent(new Event("routeChange", state));
            return result;
          };
        })(window.history);
      `}</Script>
    </body>
  </html>
);

export default RootLayout;
Enter fullscreen mode Exit fullscreen mode

And now we are able to notify fathom about the route changes. We do this with a custom component (Analytics), which is used in our root layout (see snippet above).

"use client";

import { useEffect } from "react";
import * as Fathom from "fathom-client";

const Analytics = () => {
  useEffect(() => {
    Fathom.load("YOUR_FATHOM_TRACKING_CODE", {
      includedDomains: ["yourdomain.com"],
    });

    const onRouteChange = () => Fathom.trackPageview();

    window.addEventListener("routeChange", onRouteChange);
    return () => window.removeEventListener("routeChange", onRouteChange);
  }, []);

  return null;
};

export default Analytics;
Enter fullscreen mode Exit fullscreen mode

We have to use a custom component instead of a hook in order to annotate the component with use client.

Top comments (0)