PostHog vs Mixpanel vs Amplitude: Product Analytics (2026)
TL;DR
PostHog is the open-source product analytics suite — event tracking, session replay, feature flags, A/B testing, surveys, all in one platform, self-hostable. Mixpanel is the event-based analytics platform — powerful funnels, retention analysis, user flows, interactive reports, the pioneer in product analytics. Amplitude is the enterprise analytics platform — behavioral analytics, cohort analysis, data governance, experimentation, used by large product teams. In 2026: PostHog for all-in-one open-source analytics, Mixpanel for focused event analytics with great UX, Amplitude for enterprise behavioral analytics.
Key Takeaways
- PostHog: posthog-js ~500K weekly downloads — open-source, all-in-one, self-hostable
- Mixpanel: mixpanel-browser ~500K weekly downloads — event analytics, funnels, flows
- Amplitude: @amplitude/analytics-browser ~300K weekly downloads — behavioral, cohorts, enterprise
- PostHog bundles analytics + session replay + feature flags + surveys
- Mixpanel has the most intuitive analytics UI
- Amplitude excels at enterprise features and data governance
PostHog
PostHog — open-source product analytics:
Setup
import posthog from "posthog-js"
// Initialize:
posthog.init(process.env.POSTHOG_KEY!, {
api_host: "https://us.i.posthog.com", // Or self-hosted URL
person_profiles: "identified_only",
capture_pageview: true,
capture_pageleave: true,
autocapture: true, // Auto-track clicks, form submissions
})
Event tracking
import posthog from "posthog-js"
// Track event:
posthog.capture("package_compared", {
packages: ["react", "vue"],
comparison_type: "downloads",
})
// Track with groups:
posthog.capture("report_generated", {
report_type: "monthly",
packages_count: 10,
$groups: { organization: "org-123" },
})
// Identify user:
posthog.identify("user-123", {
email: "royce@example.com",
plan: "pro",
signup_date: "2026-01-15",
})
// Set user properties:
posthog.people.set({
last_active: new Date().toISOString(),
packages_tracked: 25,
})
// Page view:
posthog.capture("$pageview", {
$current_url: window.location.href,
})
Feature flags
import posthog from "posthog-js"
// Check feature flag:
if (posthog.isFeatureEnabled("new-comparison-ui")) {
renderNewComparisonUI()
} else {
renderClassicUI()
}
// Get flag payload:
const variant = posthog.getFeatureFlag("pricing-experiment")
// "control" | "variant-a" | "variant-b"
// React hook:
import { useFeatureFlagEnabled } from "posthog-js/react"
function ComparisonPage() {
const showNewUI = useFeatureFlagEnabled("new-comparison-ui")
return showNewUI ? <NewUI /> : <ClassicUI />
}
Session replay and surveys
import posthog from "posthog-js"
// Session replay is automatic (configured in PostHog dashboard)
// Records user sessions for debugging and UX analysis
// Trigger survey programmatically:
posthog.capture("$survey_shown", {
$survey_id: "survey-123",
})
// React:
import { PostHogProvider } from "posthog-js/react"
function App() {
return (
<PostHogProvider client={posthog}>
<Router />
</PostHogProvider>
)
}
Mixpanel
Mixpanel — event-based analytics:
Setup
import mixpanel from "mixpanel-browser"
// Initialize:
mixpanel.init(process.env.MIXPANEL_TOKEN!, {
debug: process.env.NODE_ENV === "development",
track_pageview: "url-with-path",
persistence: "localStorage",
ignore_dnt: false,
})
Event tracking
import mixpanel from "mixpanel-browser"
// Track event:
mixpanel.track("Package Compared", {
packages: ["react", "vue"],
comparison_type: "downloads",
result_count: 2,
})
// Track with timing:
const startTime = Date.now()
await generateReport()
mixpanel.track("Report Generated", {
duration_ms: Date.now() - startTime,
report_type: "monthly",
})
// Identify user:
mixpanel.identify("user-123")
// Set user profile:
mixpanel.people.set({
$email: "royce@example.com",
$name: "Royce",
plan: "pro",
signup_date: "2026-01-15",
packages_tracked: 25,
})
// Increment property:
mixpanel.people.increment("comparisons_made", 1)
// Track revenue:
mixpanel.people.track_charge(29.99, {
plan: "pro",
billing_cycle: "monthly",
})
Funnels and groups
import mixpanel from "mixpanel-browser"
// Track funnel steps:
mixpanel.track("Signup Started")
// ... user fills form ...
mixpanel.track("Signup Email Entered", { method: "email" })
// ... user completes ...
mixpanel.track("Signup Completed", { plan: "free" })
// Group analytics:
mixpanel.set_group("organization", "org-123")
mixpanel.get_group("organization", "org-123").set({
name: "PkgPulse Team",
plan: "enterprise",
member_count: 15,
})
// Super properties (sent with every event):
mixpanel.register({
app_version: "2.1.0",
platform: "web",
theme: "dark",
})
// Time events:
mixpanel.time_event("Search")
// ... user searches ...
mixpanel.track("Search", { query: "react", results: 150 })
// Automatically includes $duration
React integration
import { MixpanelProvider, useMixpanel } from "react-mixpanel-browser"
function App() {
return (
<MixpanelProvider token={process.env.MIXPANEL_TOKEN!}>
<Router />
</MixpanelProvider>
)
}
function ComparisonButton({ packages }: { packages: string[] }) {
const mixpanel = useMixpanel()
return (
<button onClick={() => {
mixpanel.track("Compare Clicked", { packages })
}}>
Compare
</button>
)
}
Amplitude
Amplitude — behavioral analytics:
Setup
import * as amplitude from "@amplitude/analytics-browser"
// Initialize:
amplitude.init(process.env.AMPLITUDE_API_KEY!, {
defaultTracking: {
sessions: true,
pageViews: true,
formInteractions: true,
fileDownloads: true,
},
})
Event tracking
import * as amplitude from "@amplitude/analytics-browser"
// Track event:
amplitude.track("Package Compared", {
packages: ["react", "vue"],
comparison_type: "downloads",
})
// Identify user:
const identifyEvent = new amplitude.Identify()
identifyEvent.set("email", "royce@example.com")
identifyEvent.set("plan", "pro")
identifyEvent.set("signup_date", "2026-01-15")
identifyEvent.setOnce("first_platform", "web")
identifyEvent.add("comparisons_made", 1)
amplitude.identify(identifyEvent)
// Set user ID:
amplitude.setUserId("user-123")
// Revenue tracking:
const revenue = new amplitude.Revenue()
.setProductId("pro-plan")
.setPrice(29.99)
.setQuantity(1)
.setRevenueType("subscription")
amplitude.revenue(revenue)
// Group analytics:
amplitude.setGroup("organization", "org-123")
Advanced tracking
import * as amplitude from "@amplitude/analytics-browser"
// User properties with operations:
const identify = new amplitude.Identify()
identify.set("plan", "pro")
identify.append("used_features", "comparison")
identify.prepend("recent_searches", "react")
identify.add("session_count", 1)
identify.unset("trial_expired")
amplitude.identify(identify)
// Flush events:
amplitude.flush()
// Track with groups:
amplitude.track("Report Downloaded", {
format: "pdf",
pages: 5,
}, {
groups: { organization: "org-123" },
})
// Session replay (Amplitude Session Replay):
amplitude.init(API_KEY, {
defaultTracking: { sessions: true },
plugins: [
amplitude.sessionReplayPlugin({
sampleRate: 0.1, // Record 10% of sessions
}),
],
})
React integration
import { useEffect } from "react"
import * as amplitude from "@amplitude/analytics-browser"
// Track page views:
function usePageTracking() {
useEffect(() => {
amplitude.track("Page Viewed", {
path: window.location.pathname,
referrer: document.referrer,
})
}, [])
}
// Track component interactions:
function PackageCard({ pkg }: { pkg: Package }) {
return (
<div
onClick={() => {
amplitude.track("Package Card Clicked", {
package_name: pkg.name,
position: pkg.rank,
})
}}
>
<h3>{pkg.name}</h3>
<p>{pkg.downloads.toLocaleString()} downloads</p>
</div>
)
}
// Experiment (A/B testing):
import { Experiment } from "@amplitude/experiment-js-client"
const experiment = Experiment.initializeWithAmplitudeAnalytics(
process.env.AMPLITUDE_DEPLOYMENT_KEY!
)
await experiment.fetch()
const variant = experiment.variant("new-pricing-page")
if (variant.value === "treatment") {
renderNewPricing()
}
Feature Comparison
| Feature | PostHog | Mixpanel | Amplitude |
|---|---|---|---|
| Open-source | ✅ | ❌ | ❌ |
| Self-hosted | ✅ | ❌ | ❌ |
| Event tracking | ✅ | ✅ | ✅ |
| Funnels | ✅ | ✅ | ✅ |
| Retention | ✅ | ✅ | ✅ |
| User flows | ✅ | ✅ | ✅ (Journeys) |
| Cohort analysis | ✅ | ✅ | ✅ |
| Session replay | ✅ (built-in) | ❌ | ✅ (add-on) |
| Feature flags | ✅ (built-in) | ❌ | ❌ |
| A/B testing | ✅ (built-in) | ❌ | ✅ (Experiment) |
| Surveys | ✅ (built-in) | ❌ | ❌ |
| Autocapture | ✅ | ✅ (limited) | ✅ |
| Data governance | ❌ | ✅ | ✅ (Taxonomy) |
| Group analytics | ✅ | ✅ | ✅ |
| SQL access | ✅ (HogQL) | ❌ | ❌ |
| Free tier | 1M events/mo | 20M events/mo | 50K MTUs |
| Pricing | Usage-based | Event-based | MTU-based |
When to Use Each
Use PostHog if:
- Want an all-in-one platform (analytics + replay + flags + surveys)
- Prefer open-source and self-hosting option
- Need feature flags and A/B testing alongside analytics
- Want to own your data (GDPR, data sovereignty)
Use Mixpanel if:
- Want the best event analytics UI and query builder
- Need powerful funnel analysis and user flows
- Building growth-focused products with detailed behavioral tracking
- Want the most generous free tier (20M events/month)
Use Amplitude if:
- Building enterprise products with large data volumes
- Need advanced behavioral analytics and cohort analysis
- Want data governance and taxonomy management
- Need experimentation platform (A/B testing)
Methodology
Download data from npm registry (weekly average, February 2026). Feature comparison based on posthog-js v1.x, mixpanel-browser v2.x, and @amplitude/analytics-browser v2.x.