Utility · Intermediate

Analytics Tracker

PostHog wrapper with auto page-view hook, user identification, a Supabase self-hosted fallback, and six pre-written SQL queries for DAU, WAU, funnel, revenue, and retention analysis.

Read the Getting Access guideif you haven't yet.

1. Get the file

Sign in at marrowstack.dev, open the Analytics Tracker block, and click Copy all files. Paste lib/analytics.ts into your project.

2. Prerequisites

  • Next.js 14 or 15, App Router
  • PostHog project at app.posthog.com (free tier available)
  • Supabase project (optional — only needed for the self-hosted event fallback)

3. Install

  1. Copy lib/analytics.ts from the block detail page into your project.
  2. Install peer dependencies:
bash
npm install posthog-js

4. Environment

VariableRequiredDefaultPurpose
NEXT_PUBLIC_POSTHOG_KEYyesPostHog project API key from Project Settings → API Keys
NEXT_PUBLIC_POSTHOG_HOSTnoPostHog instance URL. Defaults to https://app.posthog.com
NEXT_PUBLIC_SUPABASE_URLnoSupabase URL — only needed for the self-hosted event fallback
SUPABASE_SERVICE_ROLE_KEYnoService role key — only for self-hosted fallback

5. Wire it in

app/layout.tsx
import { AnalyticsProvider } from '@/lib/analytics'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <AnalyticsProvider>
          {children}
        </AnalyticsProvider>
      </body>
    </html>
  )
}
Auto page-view tracking
'use client'
import { usePageView } from '@/lib/analytics'

// Drop this in your root layout or a client wrapper
export function PageViewTracker() {
  usePageView() // tracks route changes automatically
  return null
}
Manual event tracking
'use client'
import { useAnalytics } from '@/lib/analytics'

export function UpgradeButton() {
  const { track, identify } = useAnalytics()

  return (
    <button
      onClick={() => {
        track('upgrade_clicked', { plan: 'pro', source: 'navbar' })
      }}
    >
      Upgrade to Pro
    </button>
  )
}

6. Verify it works

  1. Open PostHog → Activity — navigate a few pages and confirm page view events appear within 30 seconds.
  2. Call track('test_event', { foo: 'bar' }) and confirm it appears in PostHog Live Events.
  3. Call identify(userId, { email }) after login and confirm the user profile is created in PostHog.

7. Failure modes & fixes

Events not appearing in PostHog

Cause: Ad blockers intercept PostHog requests in the browser.

Fix: Set up a PostHog reverse proxy at /ingest in your Next.js rewrites. Instructions are in the PostHog docs under Reverse Proxy.

NEXT_PUBLIC_POSTHOG_KEY is not defined

Cause: The env var is set without the NEXT_PUBLIC_ prefix, or not set at all.

Fix: Ensure the variable is prefixed with NEXT_PUBLIC_ so Next.js exposes it to the browser bundle.

Duplicate page view events

Cause: usePageView() is mounted in multiple components or at multiple levels of the component tree.

Fix: Mount usePageView() (or PageViewTracker) exactly once, in the root layout.