New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

@startupkit/analytics

Package Overview
Dependencies
Maintainers
2
Versions
43
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@startupkit/analytics

Provider-agnostic analytics helpers for StartupKit

Source
npmnpm
Version
0.6.0
Version published
Weekly downloads
0
Maintainers
2
Weekly downloads
 
Created
Source

@startupkit/analytics

Provider-agnostic analytics helpers for StartupKit projects.

Part of StartupKit - The Zero to One Startup Framework.

Installation

pnpm add @startupkit/analytics

Or use the StartupKit CLI to get started with a complete monorepo setup:

npx startupkit init

What This Package Provides

This package provides a provider-agnostic analytics context pattern with built-in conveniences:

  • ✅ Plugin architecture - Compose multiple analytics providers
  • ✅ Auto page tracking (with Next.js App Router)
  • ✅ Memoized handlers for performance
  • ✅ Type-safe hooks (useAnalytics, useFlag)
  • ✅ No vendor lock-in - use any analytics providers

Built-in Plugins

The package includes ready-to-use plugins for popular analytics services:

  • PostHog - Product analytics and feature flags
  • GoogleAnalytics - Google Analytics 4 integration
  • OpenPanelPlugin - Privacy-focused analytics
  • AhrefsPlugin - SEO and traffic analytics

Usage

The plugin architecture makes it easy to use multiple analytics providers:

"use client"

import {
  AnalyticsProvider,
  PostHogPlugin,
  GoogleAnalyticsPlugin,
  OpenPanelPlugin
} from "@startupkit/analytics"

const plugins = [
  PostHogPlugin({
    apiKey: process.env.NEXT_PUBLIC_POSTHOG_API_KEY,
    apiHost: process.env.NEXT_PUBLIC_POSTHOG_HOST // optional
  }),
  GoogleAnalyticsPlugin({
    measurementId: process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID
  }),
  OpenPanelPlugin({
    clientId: process.env.NEXT_PUBLIC_OPENPANEL_CLIENT_ID
  })
]

export function Providers({ children, flags }) {
  return (
    <AnalyticsProvider flags={flags} plugins={plugins}>
      {children}
    </AnalyticsProvider>
  )
}

Using Analytics in Components

"use client"

import { useAnalytics } from "@startupkit/analytics"

export function MyComponent() {
  const { track, identify, page, reset, flags } = useAnalytics()

  const handleClick = () => {
    track("BUTTON_CLICKED", { 
      buttonId: "cta",
      page: "home" 
    })
  }

  const handleSignIn = (userId: string, email: string) => {
    identify(userId, {
      email,
      plan: "pro"
    })
  }

  return (
    <button onClick={handleClick}>
      Click me
    </button>
  )
}

Feature Flags

import { useFlag } from "@startupkit/analytics"

export function MyFeature() {
  const isEnabled = useFlag("new-feature")

  if (!isEnabled) {
    return null
  }

  return <div>New Feature!</div>
}

API Reference

AnalyticsProvider

Provider component that accepts flags and plugins or handlers.

interface AnalyticsProviderProps<TFlags> {
  flags: TFlags
  plugins?: AnalyticsPlugin[]
  handlers?: AnalyticsHandlers
  autoPageTracking?: boolean  // Default: true
  children: ReactNode
}

Plugin Mode (Recommended):

<AnalyticsProvider 
  flags={flags} 
  plugins={[
    PostHogPlugin({ apiKey: "..." }),
    GoogleAnalyticsPlugin({ measurementId: "..." })
  ]}
>
  {children}
</AnalyticsProvider>

Custom Handlers with Plugins (Advanced):

For full customization, provide both plugins and handlers. Your handlers receive a strongly-typed plugins object:

const plugins = [
  PostHogPlugin({ apiKey: "..." }),
  GoogleAnalyticsPlugin({ measurementId: "..." })
] as const // Important: use 'as const' for type inference

<AnalyticsProvider 
  flags={flags}
  plugins={plugins}
  handlers={{
    identify: ({ plugins, userId, traits }) => {
      // plugins.PostHog is strongly typed!
      if (userId) {
        plugins.PostHog.identify?.(userId, traits)
        
        // Add custom logic
        if (traits?.isPremium) {
          plugins.GoogleAnalytics.identify?.(userId, traits)
        }
      }
    },
    track: ({ plugins, event, properties }) => {
      // Full control over which events go where
      plugins.PostHog.track?.(event, properties)
      
      if (event.startsWith('PURCHASE_')) {
        plugins.GoogleAnalytics.track?.(event, properties)
      }
    },
    page: ({ plugins, name, properties }) => {
      plugins.PostHog.page?.(name, properties)
      plugins.GoogleAnalytics.page?.(name, properties)
    },
    reset: ({ plugins }) => {
      plugins.PostHog.reset?.()
      plugins.GoogleAnalytics.reset?.()
    }
  }}
>
  {children}
</AnalyticsProvider>

Simple Handlers Mode (No Plugins):

<AnalyticsProvider 
  flags={flags}
  handlers={{
    identify: (userId, traits) => { /* your code */ },
    track: (event, properties) => { /* your code */ },
    page: (name, properties) => { /* your code */ },
    reset: () => { /* your code */ }
  }}
>
  {children}
</AnalyticsProvider>

Auto Page Tracking:

  • Automatically tracks page views using Next.js App Router hooks
  • Filters out route groups like (dashboard)
  • Replaces long numeric segments with :id
  • Can be disabled with autoPageTracking: false

useAnalytics()

Hook to access analytics context.

const { identify, track, page, reset, flags } = useAnalytics()

// Identify a user
identify("user_123", {
  email: "user@example.com",
  plan: "pro"
})

// Track an event
track("PURCHASE_COMPLETED", {
  amount: 99.99,
  currency: "USD"
})

// Track a page view
page("/dashboard", { 
  pathname: "/dashboard/settings" 
})

// Reset analytics (on logout)
reset()

useFlag(name)

Hook to access a specific feature flag.

const isNewFeatureEnabled = useFlag("new-feature")

if (isNewFeatureEnabled) {
  // Show new feature
}

Built-in Plugins

PostHog

import { PostHogPlugin } from "@startupkit/analytics"

const plugin = PostHogPlugin({
  apiKey: "phc_...",
  apiHost: "https://app.posthog.com" // optional
})

Features:

  • Product analytics
  • Feature flags
  • Session recordings
  • A/B testing

GoogleAnalytics

import { GoogleAnalyticsPlugin } from "@startupkit/analytics"

const plugin = GoogleAnalyticsPlugin({
  measurementId: "G-XXXXXXXXXX"
})

Features:

  • Page view tracking
  • Event tracking
  • Google Analytics 4 integration

OpenPanelPlugin

import { OpenPanelPlugin } from "@startupkit/analytics"

const plugin = OpenPanelPlugin({
  clientId: "your-client-id"
})

Features:

  • Privacy-focused analytics
  • Real-time dashboards
  • Event tracking

AhrefsPlugin

import { AhrefsPlugin } from "@startupkit/analytics"

const plugin = AhrefsPlugin()

Features:

  • SEO tracking
  • Traffic source analytics

Creating Custom Plugins

You can create your own analytics plugins:

import type { AnalyticsPlugin } from "@startupkit/analytics"
import { useCallback } from "react"

export function MyAnalyticsPlugin(): AnalyticsPlugin {
  return {
    name: "MyAnalytics",
    Provider: ({ children }) => {
      // Optional: Wrap in your provider
      return <>{children}</>
    },
    useHandlers: () => {
      const identify = useCallback(
        (userId: string | null, traits?: Record<string, unknown>) => {
          // Your identify logic
          console.log("Identify:", userId, traits)
        },
        []
      )

      const track = useCallback(
        (event: string, properties?: Record<string, unknown>) => {
          // Your track logic
          console.log("Track:", event, properties)
        },
        []
      )

      const page = useCallback(
        (name?: string, properties?: Record<string, unknown>) => {
          // Your page view logic
          console.log("Page:", name, properties)
        },
        []
      )

      const reset = useCallback(() => {
        // Your reset logic
        console.log("Reset")
      }, [])

      return {
        identify,
        track,
        page,
        reset
      }
    }
  }
}

Advanced: Custom Handlers with Plugins

For maximum flexibility, you can provide both plugins and handlers to gain full control over how analytics events are dispatched. When you do this, the analytics provider:

  • Initializes all plugins (calls their Provider components)
  • Gets handlers from each plugin (calls their useHandlers() hooks)
  • Passes a strongly-typed plugins object to your custom handlers
  • Lets you decide which events go to which plugins

Use Cases

  • Conditional tracking: Only send certain events to specific providers
  • Data transformation: Modify event properties per provider
  • Performance: Skip expensive tracking for non-critical events
  • Debugging: Log events before sending to providers
  • A/B testing: Route events differently for different user segments

Example: Conditional Tracking

const plugins = [
  PostHogPlugin({ apiKey: "..." }),
  GoogleAnalyticsPlugin({ measurementId: "..." })
] as const // 'as const' enables type inference

<AnalyticsProvider 
  flags={flags}
  plugins={plugins}
  handlers={{
    track: ({ plugins, event, properties }) => {
      // All events go to PostHog
      plugins.PostHog.track?.(event, properties)
      
      // Only send purchase events to Google Analytics
      if (event.startsWith('PURCHASE_')) {
        plugins.GoogleAnalytics.track?.(event, {
          ...properties,
          value: properties.amount // Transform property name
        })
      }
    },
    identify: ({ plugins, userId, traits }) => {
      if (!userId) return
      
      plugins.PostHog.identify?.(userId, traits)
      
      // Only identify premium users in GA
      if (traits?.plan === 'premium') {
        plugins.GoogleAnalytics.identify?.(userId, traits)
      }
    },
    page: ({ plugins, name, properties }) => {
      // Track all page views in both
      plugins.PostHog.page?.(name, properties)
      plugins.GoogleAnalytics.page?.(name, properties)
    },
    reset: ({ plugins }) => {
      plugins.PostHog.reset?.()
      plugins.GoogleAnalytics.reset?.()
    }
  }}
>
  {children}
</AnalyticsProvider>

Type Safety

The plugins object is strongly typed based on the plugins you provide:

const plugins = [
  PostHogPlugin({ apiKey: "..." }),
  GoogleAnalyticsPlugin({ measurementId: "..." })
] as const // Important!

// TypeScript knows these exist:
plugins.PostHog.track(...)      // ✅
plugins.GoogleAnalytics.track(...) // ✅

// TypeScript catches typos:
plugins.PostHOG.track(...)      // ❌ Error
plugins.Mixpanel.track(...)     // ❌ Error

Important: Use as const when defining your plugins array for proper type inference.

Example: Debugging

<AnalyticsProvider 
  flags={flags}
  plugins={plugins}
  handlers={{
    track: ({ plugins, event, properties }) => {
      // Log all events in development
      if (process.env.NODE_ENV === 'development') {
        console.log('📊 Analytics:', event, properties)
      }
      
      // Send to all providers
      plugins.PostHog.track?.(event, properties)
      plugins.GoogleAnalytics.track?.(event, properties)
    }
    // identify, page, reset use default behavior (send to all plugins)
  }}
>
  {children}
</AnalyticsProvider>

Partial Handlers

You don't need to provide all handlers! Unspecified handlers will use the default behavior (sending to all plugins):

const plugins = [
  PostHogPlugin({ apiKey: "..." }),
  GoogleAnalyticsPlugin({ measurementId: "..." })
] as const

<AnalyticsProvider 
  flags={flags}
  plugins={plugins}
  handlers={{
    // Only override track - everything else uses defaults
    track: ({ plugins, event, properties }) => {
      // Custom logic for tracking only
      if (event.startsWith('PURCHASE_')) {
        plugins.PostHog.track?.(event, properties)
        plugins.GoogleAnalytics.track?.(event, properties)
      } else {
        // Only track non-purchase events to PostHog
        plugins.PostHog.track?.(event, properties)
      }
    }
    // identify, page, reset automatically send to ALL plugins
  }}
>
  {children}
</AnalyticsProvider>

This is perfect for:

  • Selective tracking: Override just track to filter which events go where
  • Custom identification: Override just identify to add extra logic
  • Debugging specific methods: Add logging to one method without affecting others

Multi-Provider Setup

Events are sent to all configured plugins simultaneously:

const plugins = [
  PostHogPlugin({ apiKey: "..." }),      // Product analytics
  GoogleAnalyticsPlugin({ measurementId: "..." }), // Marketing analytics
  OpenPanelPlugin({ clientId: "..." })   // Privacy-focused analytics
]

<AnalyticsProvider flags={flags} plugins={plugins}>
  {children}
</AnalyticsProvider>

When you call track(), the event is sent to all three providers automatically.

Auto Page Tracking Details

The package automatically tracks page views with clean route names:

Input: /dashboard/(settings)/profile/abc123def456 Output: /dashboard/profile/:id

  • Filters out route groups: (settings) → removed
  • Replaces long IDs: abc123def456 → :id
  • Preserves meaningful segments: dashboard, profile

The page handler is called with:

  • name: The clean route (e.g., /dashboard/profile/:id)
  • properties.pathname: The actual pathname

TypeScript Types

// Plugin interface
interface AnalyticsPlugin {
  name: string
  Provider?: ComponentType<{ children: ReactNode }>
  useHandlers: () => Partial<AnalyticsHandlers>
}

// Simple handlers interface (no plugins)
interface AnalyticsHandlers {
  identify: (userId: string | null, traits?: Record<string, unknown>) => void
  track: (event: string, properties?: Record<string, unknown>) => void
  page: (name?: string, properties?: Record<string, unknown>) => void
  reset: () => void
}

// Custom handlers interface (with plugins) - receives plugins object and parameters
interface CustomAnalyticsHandlers<TPlugins extends readonly AnalyticsPlugin[]> {
  identify: (params: {
    plugins: PluginsToHandlersMap<TPlugins>
    userId: string | null
    traits?: Record<string, unknown>
  }) => void
  track: (params: {
    plugins: PluginsToHandlersMap<TPlugins>
    event: string
    properties?: Record<string, unknown>
  }) => void
  page: (params: {
    plugins: PluginsToHandlersMap<TPlugins>
    name?: string
    properties?: Record<string, unknown>
  }) => void
  reset: (params: { 
    plugins: PluginsToHandlersMap<TPlugins> 
  }) => void
}

// Plugins map - strongly typed based on plugin names
type PluginsToHandlersMap<TPlugins extends readonly AnalyticsPlugin[]> = {
  [K in TPlugins[number]["name"]]: Partial<AnalyticsHandlers>
}

// Context interface
interface AnalyticsContextType<TFlags> {
  flags: TFlags
  identify: (userId: string | null, traits?: Record<string, unknown>) => void
  track: (event: string, properties?: Record<string, unknown>) => void
  page: (name?: string, properties?: Record<string, unknown>) => void
  reset: () => void
}

Philosophy

This package follows the StartupKit minimal package philosophy:

What it does:

  • Provides reusable React patterns for analytics
  • Handles auto page tracking (filters route groups, replaces IDs)
  • Memoizes handlers for performance
  • Includes ready-to-use plugins for popular services

What it doesn't do:

  • Force you to use specific analytics providers
  • Make decisions about your analytics architecture

You can use the built-in plugins, create your own, or implement custom handlers.

Peer Dependencies

  • next >= 14.0.0 (for App Router hooks)
  • react >= 18.2.0

Plugin-specific dependencies (only install what you use):

  • posthog-js - For PostHogPlugin
  • @openpanel/sdk - For OpenPanelPlugin
  • (GoogleAnalyticsPlugin and AhrefsPlugin work via script injection)

Learn More

Support

Having issues? Open an issue on GitHub

License

ISC © 2025 01 Studio

FAQs

Package last updated on 08 Jan 2026

Related posts