Mixpanel Analytics
"Mixpanel: event-based analytics, funnels, retention, user profiles, cohorts, group analytics, JavaScript/Node SDK"
Mixpanel is an event-based analytics platform focused on understanding user behavior through actions rather than page views. The core model revolves around tracking discrete events with rich properties, building user profiles, and analyzing sequences of actions through funnels and retention charts. Mixpanel encourages a "track actions, not pages" mindset where every ## Key Points - **Define a tracking plan** before instrumenting. Document every event name, its properties, - **Use `mixpanel.time_event()`** to measure durations of multi-step flows like onboarding, - **Register super properties** for context that applies to every event (app version, platform, - **Call `mixpanel.reset()` on logout** to clear the identity and super properties, preventing - **Prefer `track_with_groups`** over manually adding group IDs as event properties. This ensures - **Batch requests in production** by enabling `batch_requests` to reduce network overhead and - **Use `register_once` for attribution** data like first-touch channel or referral source so the - **Tracking page views as the primary metric.** Mixpanel is designed for event-based analysis. - **Creating too many unique event names.** Events like `clicked_button_save_v2_modal` create - **Calling `mixpanel.alias()` after `identify()`.** The alias call must happen before identify - **Sending arrays of objects as properties.** Mixpanel flattens complex nested structures - **Ignoring `distinct_id` on server-side events.** Every server-side track call requires an
skilldb get analytics-services-skills/Mixpanel AnalyticsFull skill: 306 linesMixpanel Analytics
Core Philosophy
Mixpanel is an event-based analytics platform focused on understanding user behavior through actions rather than page views. The core model revolves around tracking discrete events with rich properties, building user profiles, and analyzing sequences of actions through funnels and retention charts. Mixpanel encourages a "track actions, not pages" mindset where every meaningful interaction is captured as a named event with context-rich properties, enabling deep analysis of conversion paths, user segments, and product engagement patterns.
Setup
Client-Side Initialization
// lib/mixpanel.ts
import mixpanel, { type Config } from "mixpanel-browser";
const MIXPANEL_TOKEN = process.env.NEXT_PUBLIC_MIXPANEL_TOKEN!;
const config: Partial<Config> = {
debug: process.env.NODE_ENV === "development",
track_pageview: "url-with-path",
persistence: "localStorage",
ignore_dnt: false,
batch_requests: true,
batch_size: 10,
batch_flush_interval_ms: 5000,
};
export function initMixpanel(): void {
mixpanel.init(MIXPANEL_TOKEN, config);
}
export { mixpanel };
Node.js Server SDK
// lib/mixpanel-server.ts
import Mixpanel from "mixpanel";
const mixpanelServer = Mixpanel.init(process.env.MIXPANEL_TOKEN!, {
protocol: "https",
geolocate: true,
});
export { mixpanelServer };
React Provider
// app/providers.tsx
"use client";
import { useEffect } from "react";
import { initMixpanel } from "@/lib/mixpanel";
export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
useEffect(() => {
initMixpanel();
}, []);
return <>{children}</>;
}
Key Techniques
Event Tracking with Properties
import { mixpanel } from "@/lib/mixpanel";
// Track a user action with context
function trackSearch(query: string, resultCount: number, filters: string[]): void {
mixpanel.track("Search Performed", {
query,
result_count: resultCount,
filters_applied: filters,
has_filters: filters.length > 0,
search_source: "main_search_bar",
});
}
// Track a purchase event for funnel analysis
function trackPurchase(order: {
id: string;
items: Array<{ sku: string; price: number }>;
total: number;
coupon?: string;
}): void {
mixpanel.track("Order Completed", {
order_id: order.id,
item_count: order.items.length,
order_total: order.total,
has_coupon: !!order.coupon,
coupon_code: order.coupon,
items: order.items.map((i) => i.sku),
});
}
User Identity and Profiles
import { mixpanel } from "@/lib/mixpanel";
// Identify user after authentication
function identifyUser(user: {
id: string;
email: string;
name: string;
createdAt: Date;
plan: string;
}): void {
mixpanel.identify(user.id);
mixpanel.people.set({
$email: user.email,
$name: user.name,
$created: user.createdAt.toISOString(),
plan: user.plan,
last_login: new Date().toISOString(),
});
// Increment a counter on the profile
mixpanel.people.increment("login_count", 1);
}
// Reset identity on logout
function handleLogout(): void {
mixpanel.track("User Logged Out");
mixpanel.reset();
}
// Link anonymous activity to identified user
function handleSignup(userId: string): void {
// This merges pre-signup anonymous events with the new user profile
mixpanel.alias(userId);
mixpanel.identify(userId);
}
Group Analytics for B2B
import { mixpanel } from "@/lib/mixpanel";
// Associate user with a company for group analytics
function setCompanyGroup(company: {
id: string;
name: string;
plan: string;
employeeCount: number;
}): void {
mixpanel.set_group("company", company.id);
mixpanel.get_group("company", company.id).set({
$name: company.name,
plan: company.plan,
employee_count: company.employeeCount,
industry: "technology",
});
}
// Track event with group context
function trackFeatureUsage(feature: string, companyId: string): void {
mixpanel.track_with_groups(
"Feature Used",
{ feature_name: feature, timestamp: Date.now() },
{ company: companyId }
);
}
Server-Side Tracking
import { mixpanelServer } from "@/lib/mixpanel-server";
// Track server-side events (webhooks, background jobs)
function trackServerEvent(
userId: string,
event: string,
properties: Record<string, unknown>
): void {
mixpanelServer.track(event, {
distinct_id: userId,
...properties,
$source: "server",
});
}
// Update user profile from the server
function updateUserProfile(userId: string, properties: Record<string, unknown>): void {
mixpanelServer.people.set(userId, properties);
}
// Track revenue on user profile
function trackRevenue(userId: string, amount: number, plan: string): void {
mixpanelServer.people.track_charge(userId, amount, {
plan,
date: new Date().toISOString(),
});
}
Super Properties and Registration
import { mixpanel } from "@/lib/mixpanel";
// Set properties that are sent with every subsequent event
function registerGlobalProperties(appVersion: string, environment: string): void {
mixpanel.register({
app_version: appVersion,
environment,
platform: "web",
});
}
// Set a property once (will not overwrite if already set)
function registerFirstTouchChannel(channel: string): void {
mixpanel.register_once({
first_touch_channel: channel,
first_visit_date: new Date().toISOString(),
});
}
// Time an event to measure duration
function startTimingOnboarding(): void {
mixpanel.time_event("Onboarding Completed");
}
function completeOnboarding(stepsCompleted: number): void {
// Mixpanel automatically adds $duration since time_event was called
mixpanel.track("Onboarding Completed", {
steps_completed: stepsCompleted,
completed: stepsCompleted === 5,
});
}
Reusable Tracking Hook
// hooks/useTrack.ts
"use client";
import { useCallback } from "react";
import { mixpanel } from "@/lib/mixpanel";
type TrackFn = (event: string, properties?: Record<string, unknown>) => void;
export function useTrack(): TrackFn {
return useCallback((event: string, properties?: Record<string, unknown>) => {
mixpanel.track(event, {
...properties,
page_url: window.location.pathname,
timestamp: Date.now(),
});
}, []);
}
Best Practices
- Define a tracking plan before instrumenting. Document every event name, its properties, and expected types in a shared spreadsheet or wiki to keep data consistent.
- Use
mixpanel.time_event()to measure durations of multi-step flows like onboarding, checkout, or form completion without manual timestamp arithmetic. - Register super properties for context that applies to every event (app version, platform, user plan) so individual track calls stay focused on action-specific data.
- Call
mixpanel.reset()on logout to clear the identity and super properties, preventing events from being attributed to the wrong user on shared devices. - Prefer
track_with_groupsover manually adding group IDs as event properties. This ensures proper association in Mixpanel's group analytics features. - Batch requests in production by enabling
batch_requeststo reduce network overhead and improve page performance. - Use
register_oncefor attribution data like first-touch channel or referral source so the original value is preserved even if the user returns through a different channel.
Anti-Patterns
- Tracking page views as the primary metric. Mixpanel is designed for event-based analysis. Focusing on page views misses the behavioral insights that funnels and retention provide.
- Creating too many unique event names. Events like
clicked_button_save_v2_modalcreate fragmented data. Use a consistent event name with differentiating properties instead. - Calling
mixpanel.alias()afteridentify(). The alias call must happen before identify on first login. Reversing the order breaks identity merging permanently. - Sending arrays of objects as properties. Mixpanel flattens complex nested structures unpredictably. Keep properties as primitives, arrays of strings, or arrays of numbers.
- Ignoring
distinct_idon server-side events. Every server-side track call requires an explicitdistinct_id. Omitting it creates orphan events that cannot be tied to users. - Not using
$ignore_timewhen backfilling. When importing historical data, set$ignore_time: trueto prevent Mixpanel from updating the "last seen" timestamp on profiles.
Install this skill directly: skilldb add analytics-services-skills
Related Skills
Amplitude Analytics
"Amplitude: product analytics, behavioral cohorts, funnels, retention, experiment platform, user journeys, JavaScript SDK"
Heap
Heap: autocapture product analytics, session replay, retroactive event definition, funnel and retention analysis, JavaScript SDK
June.so
June.so: B2B product analytics, company-level insights, feature adoption reports, activation tracking, Node and JavaScript SDK
Plausible Analytics
"Plausible: privacy-friendly analytics, no cookies, lightweight script, custom events, goals, API, self-hosted option"
PostHog Analytics
"PostHog: product analytics, event tracking, feature flags, session recordings, A/B testing, self-hosted/cloud, Next.js SDK"
Segment
Segment: customer data platform, event routing, identity resolution, analytics.js, server-side sources, warehouse destinations