tanstack-router-ga4

tanstack-router-ga4

Ship Google Analytics (GA4) for TanStack Router and TanStack Start without wiring up fragile route listeners or untyped analytics helpers yourself. You get automatic page_view tracking, typed event helpers, and a setup that fits naturally into real app shells.

Automatic tracking

Record route-based page_view events automatically across client-side navigation.

Typed GA4 helpers

Track sign_up, generate_lead, consent, config, and custom events with TypeScript support.

Deferred loading

Add the deferred prop to delay GA script injection until the browser is idle, improving initial page load performance.

Built for real apps

Works cleanly with TanStack Start, SSR-friendly root documents, and tested route flows.

Set up GoogleAnalytics

Mount GoogleAnalytics once near the top of your app so route changes can automatically emit page_view events.

import { HeadContent, Scripts } from "@tanstack/react-router";
import { GoogleAnalytics } from "tanstack-router-ga4";

function RootDocument({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <head>
        <HeadContent />
      </head>
      <body>
        <GoogleAnalytics measurementId="G-XXXXXXXXXX" />
        {children}
        <Scripts />
      </body>
    </html>
  );
}
Automatic page views happen on route changes. The dedicated route-based demos live under /tests/* so the browser test suite can keep validating real navigation behavior.

Deferred loading

By default, GoogleAnalytics waits until the browser is idle before injecting the GA script, using the browser's requestIdleCallback API. This moves analytics work out of the critical rendering path, improving Time to Interactive and other Core Web Vitals. On browsers that don't support requestIdleCallback (such as Safari) the script loads immediately so no data is lost. Pass deferred={false} to opt out and load GA immediately.


// Opt out — GA script is injected immediately on first render
<GoogleAnalytics measurementId="G-XXXXXXXXXX" deferred={false} />

Set Global Config

Use set() to define global GA configuration that should apply across your session, such as user_id, user_properties, or other shared parameters.

const ga = useGoogleAnalytics();

ga.set({
  user_id: user.id,
  user_properties: {
    email: user.email,
    username: user.username,
  },
});

ga.event("sign_up", { method: "email" });

Interactive demo

No user changes sent yet.

No user is currently shown in this demo.

Set Per-Stream Config

Use config() when you need per-measurement stream settings. If your app sends data to multiple streams, configure each measurementId individually instead of relying only on global set() values.

const ga = useGoogleAnalytics();

ga.config("G-MAINSTREAM", {
  debug_mode: true,
  send_page_view: false,
});

ga.config("G-MARKETING", {
  campaign_source: "newsletter",
  send_page_view: false,
});

Interactive demo

Debug mode is currently off.

Current value: false

Track sign_up events

Call event() with the recommended GA4 sign_up event name and any typed params.

const ga = useGoogleAnalytics();

ga.event("sign_up", {
  method: "email",
});

Interactive demo

No sign up event sent yet.

Track generate_lead events

Use the same event() helper for conversion-style events such as generate_lead.

const ga = useGoogleAnalytics();

ga.event("generate_lead", {
  currency: "USD",
  value: 1,
});

Interactive demo

No lead event sent yet.

Read values with get

The get() command reads callback-based values such as client_id.

const ga = useGoogleAnalytics();

ga.get("G-XXXXXXXXXX", "client_id", (value) => {
  console.log("client_id", value);
});

Interactive demo

No request sent yet.