Skip to content

SocialGouv/matomo-next

Repository files navigation

Matomo Next

Matomo analytics for Next.js applications

Github Master CI Build Status License: Apache-2.0 GitHub release (latest SemVer) Npm version codecov


A lightweight, TypeScript-ready Matomo analytics integration for Next.js applications with support for both Pages Router and App Router.

Features

  • Pages Router & App Router Support - Works with both Next.js routing systems
  • Automatic Page Tracking - Tracks route changes and page views automatically
  • Search Tracking - Built-in search query tracking
  • GDPR Compliant - Cookie-less tracking option
  • Custom Events - Type-safe event tracking API
  • A/B Testing - Built-in support for Matomo's A/B Testing plugin with React hooks
  • Server-Side Proxy - Bypass ad-blockers by routing tracking through your own domain
  • Heatmap & Session Recording - Optional user behavior visualization
  • TypeScript Support - Full type safety and auto-completion

Installation

npm install @socialgouv/matomo-next

Quick Start

Pages Router

Add the trackPagesRouter() call in your _app.js:

import { useEffect } from "react";
import { trackPagesRouter } from "@socialgouv/matomo-next";

const MATOMO_URL = process.env.NEXT_PUBLIC_MATOMO_URL;
const MATOMO_SITE_ID = process.env.NEXT_PUBLIC_MATOMO_SITE_ID;

function MyApp({ Component, pageProps }) {
  useEffect(() => {
    trackPagesRouter({ url: MATOMO_URL, siteId: MATOMO_SITE_ID });
  }, []);

  return <Component {...pageProps} />;
}

export default MyApp;

App Router

Create a client component for tracking with trackAppRouter():

"use client";

import { trackAppRouter } from "@socialgouv/matomo-next";
import { usePathname, useSearchParams } from "next/navigation";
import { useEffect } from "react";

const MATOMO_URL = process.env.NEXT_PUBLIC_MATOMO_URL;
const MATOMO_SITE_ID = process.env.NEXT_PUBLIC_MATOMO_SITE_ID;

export function MatomoAnalytics() {
  const pathname = usePathname();
  const searchParams = useSearchParams();

  useEffect(() => {
    trackAppRouter({
      url: MATOMO_URL,
      siteId: MATOMO_SITE_ID,
      pathname,
      searchParams,
    });
  }, [pathname, searchParams]);

  return null;
}

Add it to your root layout wrapped in a Suspense boundary:

import { Suspense } from "react";
import { MatomoAnalytics } from "./matomo";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Suspense fallback={null}>
          <MatomoAnalytics />
        </Suspense>
      </body>
    </html>
  );
}

Documentation

Common Use Cases

Track Custom Events

Use the sendEvent() helper for type-safe event tracking:

import { sendEvent } from "@socialgouv/matomo-next";

// Track a button click
sendEvent({ category: "contact", action: "click phone" });

// Track with additional context
sendEvent({
  category: "video",
  action: "play",
  name: "intro-video",
  value: 120,
});

A/B Testing

Run experiments using Matomo's A/B Testing plugin. Pass your test definitions to the tracker and use the useABTestVariant() hook in your components:

// Pass abTests to the tracker
trackAppRouter({
  url: MATOMO_URL,
  siteId: MATOMO_SITE_ID,
  pathname,
  searchParams,
  abTests: [
    {
      name: "homepage-hero",
      percentage: 100,
      variations: [{ name: "original" }, { name: "new-hero" }],
    },
  ],
});
// In your component
import { useABTestVariant } from "@socialgouv/matomo-next";

export function HeroSection() {
  const variant = useABTestVariant("homepage-hero");

  if (variant === "new-hero") {
    return <NewHeroSection />;
  }
  return <OriginalHeroSection />;
}

See the A/B Testing documentation for scheduling, custom triggers, and advanced usage.

Server-Side Proxy

Bypass ad-blockers by routing Matomo requests through your own domain using withMatomoProxy():

By default, the public proxy endpoint is generated under your own API namespace: /api/{random}.

// next.config.mjs
import { withMatomoProxy } from "@socialgouv/matomo-next";

export default withMatomoProxy({
  matomoUrl: "https://analytics.example.com",
})(nextConfig);

matomoUrl is required here because it’s the server-side target the proxy forwards to (stored in MATOMO_PROXY_TARGET, not exposed to the browser).

// In your tracker component
import { trackAppRouter } from "@socialgouv/matomo-next";

// When the proxy is configured, calls are automatically routed through your own domain.
// This also hides the usual `matomo.js` / `matomo.php` filenames behind opaque build-time
// random names (some blockers match on those filenames).
trackAppRouter({ siteId: "1", pathname, searchParams });

See the Server-Side Proxy documentation for custom paths, chaining with other plugins, and security considerations.

Configuration Options

Option Type Description Default Docs
url string Matomo instance URL - Required unless using the server-side proxy
siteId string Matomo site ID - Required
useProxy boolean Prefer proxy (path + opaque filenames) when available true Server-side proxy
pathname string Current pathname (App Router only) - Required for App Router
searchParams URLSearchParams URL search params (App Router only) - Required for App Router
jsTrackerFile string Custom JS tracker filename "matomo.js" (or proxy-provided opaque name) Advanced
phpTrackerFile string Custom PHP tracker filename "matomo.php" (or proxy-provided opaque name) Advanced
excludeUrlsPatterns RegExp[] URLs to exclude from tracking [] Advanced
disableCookies boolean Cookie-less tracking false Advanced
cleanUrl boolean Remove query params from URLs false Advanced
searchKeyword string Search query parameter name "q" Advanced
searchRoutes string[] Custom search route paths ["/recherche", "/search"] Advanced
enableHeartBeatTimer boolean Track time on page false Advanced
heartBeatTimerInterval number HeartBeat timer interval (seconds) 15 (Matomo default) Advanced
enableHeatmapSessionRecording boolean Enable session recording false Heatmap
heatmapConfig HeatmapConfig Heatmap configuration object {} Heatmap
debug boolean Enable debug logs false Advanced
nonce string CSP nonce value - Security
trustedPolicyName string Trusted Types policy name "matomo-next" Security
onInitialization () => void Callback on init - Advanced
onRouteChangeStart (path) => void Callback on route change start - Advanced
onRouteChangeComplete (path) => void Callback on route change complete - Advanced
onScriptLoadingError () => void Callback on script loading error - Advanced
abTests ABTestDefinition[] A/B test experiments to register - A/B Testing

See complete configuration options for full details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Links

Packages

 
 
 

Contributors