Amplitude provides behavioral product analytics with built-in experimentation — amplitude.init(apiKey, { defaultTracking: { pageViews: false } }) initializes. amplitude.setUserId(userId) identifies the user. amplitude.setUserProperties({ plan, role, company }) sets profile attributes. amplitude.track("Button Clicked", { name, page }) fires an event. Revenue: const revenue = new amplitude.Revenue(); revenue.setProductId("pro-plan").setPrice(49).setRevenue(49); amplitude.revenue(revenue) tracks purchases. Session Replay: amplitude.add(sessionReplayPlugin({ sampleRate: 0.1 })) records 10% of sessions. Identify operations: const identify = new Identify(); identify.set("plan", "pro").increment("loginCount", 1).append("features", "advanced"); amplitude.identify(identify) — operators set, setOnce, increment, append, prepend, unset. Group analytics: amplitude.setGroup("company", companyId) and amplitude.groupIdentify("company", companyId, new Identify().set("plan", "enterprise")). Amplitude Experiment: const experiment = Experiment.initialize(deploymentKey), await experiment.fetch({ userId }), const variant = experiment.variant("feature-flag"), if (variant.value === "treatment") showNewUI(). Claude Code generates Amplitude tracking, experiments, and revenue analytics pipelines.
CLAUDE.md for Amplitude
## Amplitude Stack
- Browser version: @amplitude/analytics-browser >= 2.x
- Node version: @amplitude/analytics-node >= 1.x
- Experiment: @amplitude/experiment-js-client >= 1.x
- Init: amplitude.init(AMPLITUDE_API_KEY, { defaultTracking: { pageViews: false, sessions: true, fileDownloads: false, formInteractions: false } })
- Identity: amplitude.setUserId(userId); amplitude.setUserProperties({ plan, email })
- Track: amplitude.track("Event Name", { prop: value })
- Identify ops: const id = new Identify(); id.set("plan", "pro").increment("sessions", 1); amplitude.identify(id)
- Session Replay: amplitude.add(sessionReplayPlugin({ sampleRate: 0.05 }))
Amplitude Browser Client
// lib/amplitude/client.ts — typed Amplitude analytics
import * as amplitude from "@amplitude/analytics-browser"
import { Identify } from "@amplitude/analytics-browser"
import { sessionReplayPlugin } from "@amplitude/plugin-session-replay-browser"
let initialized = false
export function initAmplitude() {
if (initialized || typeof window === "undefined") return
amplitude.init(process.env.NEXT_PUBLIC_AMPLITUDE_API_KEY!, {
defaultTracking: {
pageViews: false, // manual page view tracking
sessions: true,
fileDownloads: false,
formInteractions: false,
},
autocapture: false,
logLevel: process.env.NODE_ENV === "development" ? amplitude.Types.LogLevel.Debug : amplitude.Types.LogLevel.Warn,
})
// Session Replay — record a sample of sessions
const sampleRate = process.env.NODE_ENV === "production" ? 0.05 : 1.0
amplitude.add(sessionReplayPlugin({ sampleRate }))
initialized = true
}
// ── Event catalog ──────────────────────────────────────────────────────────
type EventProperties = {
"Page Viewed": { pageName: string; path: string }
"Button Clicked": { buttonId: string; buttonText: string; page: string }
"Feature Enabled": { feature: string }
"Trial Started": { plan: string; source: string }
"Subscription Started": { plan: string; interval: "monthly" | "annual"; amount: number }
"Subscription Cancelled": { plan: string; reason?: string }
"Invite Sent": { method: "email" | "link"; count: number }
"File Uploaded": { fileType: string; sizeMb: number }
"Export Completed": { format: string; rowCount: number }
"API Key Created": { purpose?: string }
"Error Displayed": { errorCode: string; page: string }
}
type EventName = keyof EventProperties
export function track<E extends EventName>(
event: E,
properties: EventProperties[E],
): void {
if (!initialized) return
amplitude.track(event, properties as Record<string, unknown>)
}
// ── Identity ───────────────────────────────────────────────────────────────
export function identifyUser(
userId: string,
properties: {
email?: string
name?: string
plan?: string
createdAt?: string
company?: string
role?: string
} = {},
): void {
if (!initialized) return
amplitude.setUserId(userId)
if (Object.keys(properties).length > 0) {
const identify = new Identify()
if (properties.email) identify.setOnce("email", properties.email)
if (properties.name) identify.set("name", properties.name)
if (properties.plan) identify.set("plan", properties.plan)
if (properties.createdAt) identify.setOnce("createdAt", properties.createdAt)
if (properties.company) identify.set("company", properties.company)
if (properties.role) identify.set("role", properties.role)
amplitude.identify(identify)
}
}
export function setGroup(groupType: string, groupId: string): void {
if (!initialized) return
amplitude.setGroup(groupType, groupId)
}
export function groupIdentify(
groupType: string,
groupId: string,
traits: Record<string, unknown>,
): void {
if (!initialized) return
const identify = new Identify()
Object.entries(traits).forEach(([k, v]) => identify.set(k, v as amplitude.Types.ValidPropertyType))
amplitude.groupIdentify(groupType, groupId, identify)
}
export function incrementUserProperty(property: string, value = 1): void {
if (!initialized) return
const identify = new Identify()
identify.increment(property, value)
amplitude.identify(identify)
}
export function trackRevenue(
productId: string,
price: number,
quantity = 1,
revenueType?: string,
): void {
if (!initialized) return
const revenue = new amplitude.Revenue()
revenue.setProductId(productId).setPrice(price).setQuantity(quantity).setRevenue(price * quantity)
if (revenueType) revenue.setRevenueType(revenueType)
amplitude.revenue(revenue)
}
export function resetIdentity(): void {
if (!initialized) return
amplitude.reset()
}
Amplitude Experiment (A/B Testing)
// lib/amplitude/experiment.ts — A/B experiments with Amplitude Experiment
import { Experiment } from "@amplitude/experiment-js-client"
let experiment: ReturnType<typeof Experiment.initialize> | null = null
export function initExperiment() {
if (experiment || typeof window === "undefined") return
experiment = Experiment.initialize(process.env.NEXT_PUBLIC_AMPLITUDE_EXPERIMENT_KEY!, {
fetchTimeoutMillis: 5000,
retryFetchOnFailure: true,
automaticFetchOnAmplitudeIdentityChange: true,
})
}
export async function fetchExperiments(userId: string): Promise<void> {
if (!experiment) initExperiment()
await experiment!.fetch({ userId })
}
export type ExperimentVariant = { value?: string; payload?: unknown }
export function getVariant(flagKey: string, fallback = "control"): ExperimentVariant {
if (!experiment) return { value: fallback }
return experiment.variant(flagKey) ?? { value: fallback }
}
// React hook:
// function useVariant(flagKey: string, fallback = "control") {
// const variant = getVariant(flagKey, fallback)
// return variant.value ?? fallback
// }
//
// Usage:
// const checkoutVariant = useVariant("new-checkout-flow")
// return checkoutVariant === "treatment" ? <NewCheckout /> : <OldCheckout />
Next.js Provider
// components/AmplitudeProvider.tsx — init, identity, page views
"use client"
import { useEffect } from "react"
import { usePathname } from "next/navigation"
import {
initAmplitude,
identifyUser,
track,
fetchExperiments,
} from "@/lib/amplitude/client"
type Props = {
userId?: string
userEmail?: string
userPlan?: string
company?: string
children: React.ReactNode
}
export default function AmplitudeProvider({
userId,
userEmail,
userPlan,
company,
children,
}: Props) {
const pathname = usePathname()
useEffect(() => {
initAmplitude()
if (userId) {
identifyUser(userId, { email: userEmail, plan: userPlan, company })
fetchExperiments(userId).catch(console.error)
}
}, [userId, userEmail, userPlan, company])
useEffect(() => {
track("Page Viewed", { pageName: document.title, path: pathname })
}, [pathname])
return <>{children}</>
}
For the Mixpanel alternative when needing simpler event-based funnel queries with JQL (JavaScript Query Language) for ad-hoc custom reports, or when per-event pricing is more budget-friendly than Amplitude’s MTU (monthly tracked user) model — Mixpanel’s JQL gives more query flexibility while Amplitude’s built-in experiment platform and statistical analysis make it the stronger choice for teams running continuous A/B tests, see the Mixpanel guide. For the PostHog alternative when needing an open-source, self-hostable product analytics tool that covers behavioral analytics, A/B testing, feature flags, session recording, and funnels all in one — PostHog is the full-stack self-hostable alternative to both Amplitude and Mixpanel with no per-user pricing on the self-hosted tier, see the PostHog guide. The Claude Skills 360 bundle includes Amplitude skill sets covering event tracking, experiments, and revenue analytics. Start with the free tier to try behavioral analytics generation.