Mixpanel delivers product analytics with funnels, retention, and user profiles — mixpanel.init(token, { persistence: "localStorage", track_pageview: false }) initializes. mixpanel.identify(userId) merges anonymous events with the user’s profile. mixpanel.people.set({ $email, $name, plan, createdAt }) updates the user profile in Mixpanel People. mixpanel.track("Button Clicked", { buttonName, page, variant }) fires an event. mixpanel.time_event("Checkout") starts a timer — the next mixpanel.track("Checkout") call auto-appends $duration. Super properties: mixpanel.register({ plan, environment }) attaches to every subsequent event automatically. mixpanel.track_links("#nav a", "Nav Link Clicked") auto-tracks all anchor clicks. Group analytics (B2B): mixpanel.set_group("company", companyId) and mixpanel.get_group("company", companyId).set({ name, plan }). Server-side Node.js: const Mixpanel = require("mixpanel"), const mp = Mixpanel.init(token), mp.track("event", { distinct_id: userId, ...properties }), mp.people.set(userId, traits). mixpanel.alias(newId, oldId) links anonymous → identified. Claude Code generates Mixpanel event tracking, user profiles, and server-side analytics pipelines.
CLAUDE.md for Mixpanel
## Mixpanel Stack
- Browser version: mixpanel-browser >= 2.55
- Server version: mixpanel >= 0.18 (Node.js)
- Browser init: mixpanel.init(process.env.NEXT_PUBLIC_MIXPANEL_TOKEN!, { persistence: "localStorage", track_pageview: false })
- Identify: mixpanel.identify(userId) — call after login
- Profile: mixpanel.people.set({ $email, $name, plan }) — $ prefix = Mixpanel reserved properties
- Track: mixpanel.track("Event Name", { prop1: value, prop2: value2 })
- Duration: mixpanel.time_event("Video Watched"); later: mixpanel.track("Video Watched") — adds $duration
- Super props: mixpanel.register({ plan, version }) — appended to every event silently
- Reset: mixpanel.reset() — call on sign-out to clear identity
Typed Mixpanel Client
// lib/mixpanel/client.ts — typed Mixpanel browser analytics
import mixpanel from "mixpanel-browser"
let initialized = false
export function initMixpanel() {
if (initialized || typeof window === "undefined") return
mixpanel.init(process.env.NEXT_PUBLIC_MIXPANEL_TOKEN!, {
persistence: "localStorage",
track_pageview: false, // We fire page events manually for SPA accuracy
ignore_dnt: false,
batch_requests: true,
batch_flush_interval_ms: 2000,
debug: process.env.NODE_ENV === "development",
})
initialized = true
}
// ── Typed event catalog ────────────────────────────────────────────────────
type EventMap = {
"Page Viewed": { pageName: string; path: string; referrer?: string }
"Button Clicked": { buttonName: string; page: string; variant?: string }
"Form Submitted": { formName: string; success: boolean }
"Feature Used": { feature: string; context?: string }
"Subscription Started": { plan: string; billing: "monthly" | "annual"; amount: number }
"Subscription Cancelled": { plan: string; reason?: string; daysActive: number }
"Search Performed": { query: string; resultCount: number; category?: string }
"Video Played": { videoId: string; videoTitle: string }
"Error Occurred": { errorCode: string; errorMessage: string; page: string }
}
type EventName = keyof EventMap
export function track<E extends EventName>(event: E, properties: EventMap[E]): void {
if (!initialized) return
mixpanel.track(event, properties as Record<string, unknown>)
}
export function identifyUser(
userId: string,
profile: {
email?: string
name?: string
plan?: string
createdAt?: string
company?: string
} = {},
): void {
if (!initialized) return
mixpanel.identify(userId)
if (Object.keys(profile).length > 0) {
mixpanel.people.set({
$email: profile.email,
$name: profile.name,
plan: profile.plan,
createdAt: profile.createdAt,
company: profile.company,
})
}
}
export function setGroup(groupName: string, groupId: string, traits: Record<string, unknown> = {}): void {
if (!initialized) return
mixpanel.set_group(groupName, groupId)
if (Object.keys(traits).length > 0) {
mixpanel.get_group(groupName, groupId).set(traits)
}
}
export function setSuperProperties(props: Record<string, string | number | boolean>): void {
if (!initialized) return
mixpanel.register(props)
}
/** Start timing an event — call before the action, track after */
export function timeEvent(eventName: EventName): void {
if (!initialized) return
mixpanel.time_event(eventName)
}
/** Increment a People counter (e.g. total orders) */
export function incrementPeopleProperty(property: string, value = 1): void {
if (!initialized) return
mixpanel.people.increment({ [property]: value })
}
export function resetIdentity(): void {
if (!initialized) return
mixpanel.reset()
}
React Analytics Hook
// hooks/useAnalytics.ts — convenient React analytics interface
"use client"
import { useCallback } from "react"
import { track, timeEvent, type EventMap } from "@/lib/mixpanel/client"
type EventName = keyof EventMap
export function useAnalytics() {
const trackEvent = useCallback(
<E extends EventName>(event: E, properties: EventMap[E]) => {
track(event, properties)
},
[],
)
const startTimer = useCallback((event: EventName) => {
timeEvent(event)
}, [])
return { trackEvent, startTimer }
}
// Usage:
// const { trackEvent } = useAnalytics()
// <button onClick={() => trackEvent("Button Clicked", { buttonName: "Upgrade", page: "/pricing" })}>
// Upgrade
// </button>
Next.js Analytics Provider
// components/MixpanelProvider.tsx — init + page views + user identity
"use client"
import { useEffect } from "react"
import { usePathname } from "next/navigation"
import { initMixpanel, identifyUser, track, setSuperProperties } from "@/lib/mixpanel/client"
type Props = {
userId?: string
userEmail?: string
userName?: string
userPlan?: string
children: React.ReactNode
}
export default function MixpanelProvider({
userId,
userEmail,
userName,
userPlan,
children,
}: Props) {
const pathname = usePathname()
// Initialize once
useEffect(() => {
initMixpanel()
if (userId) {
identifyUser(userId, { email: userEmail, name: userName, plan: userPlan })
}
setSuperProperties({
environment: process.env.NODE_ENV ?? "development",
appVersion: process.env.NEXT_PUBLIC_APP_VERSION ?? "0.0.0",
})
}, [userId, userEmail, userName, userPlan])
// Page views
useEffect(() => {
track("Page Viewed", {
pageName: document.title,
path: pathname,
referrer: document.referrer,
})
}, [pathname])
return <>{children}</>
}
Server-Side Node.js Tracking
// lib/mixpanel/server.ts — server-side Mixpanel for backend events
import Mixpanel from "mixpanel"
const mp = Mixpanel.init(process.env.MIXPANEL_TOKEN!, {
host: "api.mixpanel.com",
protocol: "https",
verbose: process.env.NODE_ENV === "development",
})
export async function serverTrack(
userId: string,
event: string,
properties: Record<string, unknown> = {},
ip?: string,
): Promise<void> {
return new Promise((resolve, reject) => {
mp.track(event, { distinct_id: userId, ip, ...properties }, (err) => {
if (err) reject(err)
else resolve()
})
})
}
export async function serverPeopleSet(
userId: string,
traits: Record<string, unknown>,
): Promise<void> {
return new Promise((resolve, reject) => {
mp.people.set(userId, traits, (err) => {
if (err) reject(err)
else resolve()
})
})
}
// app/api/checkout/route.ts usage:
// await serverTrack(session.userId, "Checkout Completed", { revenue: amount, plan })
// await serverPeopleSet(session.userId, { plan, lastPaymentAt: new Date().toISOString() })
For the Amplitude alternative when needing Amplitude’s Charts, user-level behavioral cohorts, Amplitude Experiment A/B testing with statistical significance calculations, or the Amplitude CDP for reverse ETL — Amplitude has a more sophisticated statistical analysis layer while Mixpanel is often preferred for its simpler event-based querying and JQL (JavaScript Query Language) for custom reports, see the Amplitude guide. For the PostHog alternative when needing an open-source, self-hostable product analytics tool that combines Mixpanel-like funnels with session recording, feature flags, and experiments in one platform — PostHog is the full-stack open-source alternative to Mixpanel with no per-event pricing on the self-hosted tier, see the PostHog guide. The Claude Skills 360 bundle includes Mixpanel skill sets covering event tracking, user profiles, and server-side analytics. Start with the free tier to try product analytics generation.