Analytics Overview

Current analytics behavior in the TanStack Start Drizzle SaaS Kit and how to extend it.

The kit ships with a small analytics abstraction in @kit/analytics.

Current repo state:

  • Client and server exports are available via @kit/analytics and @kit/analytics/server
  • The default manager currently registers only the null provider
  • The app does not mount an analytics provider yet, so analytics calls resolve to a no-op service by default
  • A separate, app-level events system lives in @kit/shared/events and is what auth flows emit into today
  • You can extend the package by registering your own providers in packages/analytics/src/index.ts and packages/analytics/src/server.ts

Quick Start

Track a Custom Event

import { analytics } from '@kit/analytics';
void analytics.trackEvent('button_clicked', {
buttonName: 'signup',
});

Identify a User

import { analytics } from '@kit/analytics';
void analytics.identify('user_123', {
email: 'user@example.com',
});

Current Implementation

The analytics package uses an AnalyticsManager that can fan out to multiple providers, but the checked-in repo currently registers only null:

packages/analytics/src/index.ts

import { createAnalyticsManager } from './analytics-manager';
import { NullAnalyticsService } from './null-analytics-service';
import type { AnalyticsManager } from './types';
export const analytics: AnalyticsManager = createAnalyticsManager({
providers: {
null: () => NullAnalyticsService,
},
});

The same pattern exists for the server export in packages/analytics/src/server.ts.

App Events

Product events flow through @kit/shared/events, an in-app pub/sub system that is independent from the analytics package. It exposes an AppEventsProvider and a useAppEvents() hook, with a typed set of base events:

packages/shared/src/events/index.tsx

export interface BaseAppEventTypes {
'user.signedIn': { userId: string };
'user.signedUp': { method: `magiclink` | `password` };
'user.updated': EmptyPayload;
'checkout.started': { planId: string; account?: string };
// Add more base event types here
}

Auth flows already emit into this system. For example, the sign-up flow emits user.signedUp after a successful registration:

packages/auth/src/hooks/use-sign-up-flow.ts

const appEvents = useAppEvents();
// after a successful sign up
appEvents.emit({
type: 'user.signedUp',
payload: {
method: 'password',
},
});

Wiring Analytics to App Events

Note: there is currently no component in apps/web that bridges app events to @kit/analytics, and there is no automatic page-view tracking. The default analytics manager registers only the null provider, so events resolve to a no-op until you wire them up.

To send these events to a real analytics provider, subscribe to them with useAppEvents() and forward them to analytics.trackEvent(...) from a client component mounted high in the tree (e.g. inside apps/web/src/components/root-providers.tsx). For page-view tracking in TanStack Start, subscribe to router navigation and call analytics.trackPageView(path) on location changes.

Extending the Package

If you want real analytics in this repo, add a provider implementation and register it in both entrypoints:

  1. Create a provider that implements AnalyticsService
  2. Register it in packages/analytics/src/index.ts
  3. Register the server-side equivalent in packages/analytics/src/server.ts if needed

See Custom Analytics Provider for the pattern.

Topics

  1. Custom Analytics Provider
  2. Google Analytics
  3. PostHog
  4. Umami