Loading tutorials…
Loading tutorials…
When Mixpanel data is wrong, every report built on top of it is wrong. The diagnosis isn't usually 'Mixpanel broke' — it's an instrumentation issue, an identification issue, or a taxonomy drift. This is the order of operations to find it.
Who this is forPMs, growth marketers, and engineering leads who've noticed Mixpanel data doesn't match reality — funnel numbers conflicting with Stripe, retention curves that look wrong, missing events, split user profiles. This is the systematic debugging path.
What you'll need
Step 1
Don't troubleshoot 'Mixpanel is wrong'. Pick ONE specific report and document the discrepancy. Specific symptoms have specific causes.
Write the symptom precisely: 'Mixpanel shows 1,247 purchase events last month; Stripe shows 1,389 charges. 142 events missing.'
Or: 'Funnel from signup_completed → activation shows 18% conversion; manual SQL on database shows 34% completion rate.'
Or: 'User john@acme.com has 2 profiles in Mixpanel with different distinct_ids.'
Or: 'Day-7 retention chart shows a vertical drop on April 15 — looks like data stopped flowing for a day.'
Without a specific symptom, you'll run in circles. With one, you can hypothesize the cause and test it.
Bring the specific numbers to the diagnosis. 'Funnel shows 18% but reality is 34%' is debuggable; 'funnel looks low' is not.
Step 2
In Mixpanel left sidebar: Events → Live View. Fire the suspect event from a real session. Confirm it appears within 60 seconds.
Open Mixpanel → Events → Live View (top tab).
Filter to your own distinct_id (find it in your browser's DevTools → Application → localStorage → mixpanel cookie, or via mixpanel.get_distinct_id() in the console).
In a separate tab, fire the suspect event. Click the button, complete the flow, do whatever should trigger it.
Within 30-60 seconds, the event should appear in Live View. Click to expand and check all properties.
If it doesn't appear: open browser DevTools → Network tab. Filter for 'api.mixpanel.com'. You should see a POST request when the event fires. If you see 0 requests, the SDK isn't initialized or the event code isn't running. If you see requests but 401/403 responses, the project token is wrong.
If it DOES appear: the event is firing. The issue is downstream (taxonomy, identification, or report logic). Continue.
Step 3
Pull the count from your source of truth (database, Stripe, Salesforce). Compare to Mixpanel for the same window.
Pick a specific time range (e.g., 'yesterday, 9am-5pm Pacific'). Get the count from your source of truth.
In Mixpanel → Insights → +New → pick the suspect event → set the same time range → save.
Compare. A 3-10% gap is normal (ad blockers, consent rejection, client-side dropoff). A 30%+ gap means real instrumentation issues.
If Mixpanel is HIGHER than source of truth: you have duplicate events. The event is firing twice (page refresh, retry logic, double SDK install).
If Mixpanel is LOWER: events are being lost. Causes: client-side event fired but page closed before send, network errors, SDK initialization race, ad blockers.
For revenue events specifically, expect <2% gap between Mixpanel and Stripe. If gap is bigger, you have a real instrumentation issue (probably client-side firing on a thank-you page — see event-tracking tutorial).
Step 4
Data Management → Events (or Lexicon). Look for variants: "signup" vs "Sign Up" vs "signup_completed" — all tracking the same thing.
In Mixpanel left sidebar: Data Management → Events. You'll see every event ever recorded in the project.
Search for the suspect event. Look for variants with similar names. 'signup_completed' next to 'signup' next to 'Sign Up' = taxonomy drift.
Click each variant to see its event count and last-seen date. The variant that's been firing recently is the 'live' version; older variants are deprecated but still polluting reports.
Use the CREATE EVENT FROM EVENT transformation (Data Management → Events → click the event → Transform) to merge variants into the canonical name.
After merging, update your reports (funnels, cohorts, retention) to reference only the canonical event name. Archive the deprecated names in Lexicon.
Add the canonical name to your event spec doc with a 'do not create variants' note for the team.
Step 5
Users → search for a known user (by email). If you see 2+ profiles for the same person, identification is broken.
Go to Mixpanel → Users (left sidebar). Search by $email.
If a known user shows 2 profiles (different distinct_ids), they're split. Their event history is fragmented.
Common causes: (1) anonymous → identified merge didn't happen (alias not called on signup), (2) email used as distinct_id and user changed email, (3) client and server use different distinct_id formats.
Fix the root cause in code (see user-identification tutorial). For existing split profiles, use Mixpanel's Identity Management API to merge them: POST /track with $identify event including both IDs.
Validate after fix: pick a fresh test user, walk anonymous → signup → logged-in flow, confirm ONE profile.
Bulk-fix existing splits: export the user list, identify pairs by email, run Identity Merge API in batch. Or accept the historical splits and only fix going forward (cheaper for older projects).
Step 6
Click an event in Live View. Verify property TYPES (number vs string) and VALUES. Wrong types break aggregation silently.
In Live View, click any event. The expansion shows each property with a type icon: Σ (number), T (string), ✓ (boolean), [] (array).
Compare to your event spec. Is price_usd showing as T (string) when it should be Σ (number)? If so, Mixpanel can't sum it. Revenue reports show $0.
Check for null/undefined values. Property `plan_tier: null` shows as '(not set)' in Mixpanel and breaks breakdowns.
Check property name spelling. 'planTier' vs 'plan_tier' are different properties to Mixpanel. Camel-case vs snake-case mixing is the dominant cause of 'missing' properties.
Use Lexicon to document expected types. When a new event fires with a wrong type, Lexicon flags it.
Step 7
If events fire BEFORE mixpanel.init() runs, they're lost. Common in SSR apps and apps with async script loading.
Open browser DevTools → Console. Visit your site. Type `mixpanel` and press Enter. If it returns an object, the SDK loaded. If undefined, it didn't.
Type `mixpanel.has_opted_out_tracking()`. Should return false (or true if user opted out — separate issue).
Type `mixpanel.get_distinct_id()`. Should return a UUID or your user's ID. If undefined, the SDK didn't initialize.
If the SDK loaded but your earliest events are missing: check the order of operations in your code. mixpanel.init() must run BEFORE any track() calls. In SSR apps, this means firing track only in useEffect or after hydration.
Common race: page_view fires on mount → SDK initializes in useEffect after mount → page_view was lost. Fix by deferring page_view until SDK is ready, or by buffering events in a queue that flushes after init.
Step 8
Engineering pushed dev token to prod by accident, or vice versa. Symptom: events go to the wrong project.
Open Mixpanel → Settings → Project Settings → Access Keys. Copy the token.
In your production app: DevTools → Console → type `mixpanel.config.token` (or check your env var). Verify it matches the PRODUCTION token.
Common bug: deploy pipeline uses MIXPANEL_TOKEN env var. Dev pipeline sets it to dev token. Prod deploy didn't override. Events end up in the dev project.
Symptom: production data is empty; dev project is unexpectedly busy. Fix: rotate env vars, redeploy, validate.
Long-term fix: name env vars distinctly. MIXPANEL_TOKEN_DEV and MIXPANEL_TOKEN_PROD with explicit selection in code based on NODE_ENV. Less likely to ship the wrong one.
Common mistakes
Treating Mixpanel data as ground truth when source-of-truth disagrees
What goes wrong: Stripe shows $84K revenue last month; Mixpanel shows $96K. PM doesn't check, builds a dashboard based on Mixpanel revenue. CFO compares to Stripe and the trust in Mixpanel collapses. Six months of analytics work gets dismissed because nobody validated against source of truth.
How to avoid: Mixpanel is descriptive analytics, not source of truth. For revenue, always reconcile with Stripe/Recharge/Paddle weekly. For user count, reconcile with auth provider. For paying customers, reconcile with billing system. A 3-5% gap is normal; >10% means a real issue.
Ignoring taxonomy drift until the cleanup is huge
What goes wrong: Over 18 months, 'signup' becomes 'Sign Up' becomes 'signup_completed' becomes 'account_created'. Four events tracking the same thing, none aggregated. Funnels reference different ones. Reports show different numbers for the same concept. Cleanup is a 4-week engineering project nobody wants to lead.
How to avoid: Audit Lexicon monthly. Merge variants while there are 2-3, not 12. Run the CREATE EVENT FROM EVENT transformation each time you find drift. Add lint rules to your analytics helper preventing new variants from being deployed.
Wrong project token in production
What goes wrong: A new engineer ships with the dev project token in prod by accident. Production events go to the dev project for a week. Dev project gets 50K MTUs of unexpected traffic. Production project shows a vertical drop in events. PMs panic about 'product engagement collapsing'. Real cause is found 5 days later.
How to avoid: Validate the token in your CI/CD: a smoke test that fires a known event and verifies it lands in the correct project. Run on every prod deploy. Adds 30 seconds to CI; prevents 5-day fire drills.
Not validating after schema changes
What goes wrong: Engineering refactors the checkout flow. New code fires purchase_completed with different property names (price → price_usd). Old reports referencing `price` show zero. Funnels referencing `purchase_completed` work. CFO can't explain why revenue is $0 in the new dashboard.
How to avoid: Every schema change must be paired with: (1) update to the spec doc, (2) update to Lexicon, (3) update to dependent reports. Include 'analytics impact' as a checklist item on every PR that touches tracking code.
Dev test events polluting production project
What goes wrong: Engineers run integration tests against the production Mixpanel project. Funnel analysis includes 12,000 test sessions per week. Activation rate looks 8% lower than reality. PM builds onboarding 'fixes' for a problem that doesn't exist.
How to avoid: Maintain separate dev and prod projects (see set-up-mixpanel-project tutorial). Wire test/staging environments to the dev token. NEVER fire test events against the prod project even if "just a few".
Not handling SDK initialization race
What goes wrong: Single-page app with React. The first page view fires on mount. SDK initializes 200ms later in useEffect. The first page view is silently lost. New-user funnel starts at step 2, not step 1. Conversion math is off because step 1 is undercounted.
How to avoid: Initialize Mixpanel SDK as early as possible — ideally in the head <script> with synchronous loading. Or, in SPAs, buffer track calls until SDK is initialized. Most modern SDK wrappers (e.g., mixpanel-browser via npm) handle this internally if you call init at app entry point.
Recap
Done — what's next
How to set up Mixpanel event tracking the right way
Read the next tutorial
Hand it off
Data quality issues compound silently — every wrong event today produces wrong reports tomorrow. A vetted product analytics specialist can audit your event chain end-to-end, document every issue, and fix the underlying root causes in 1-2 weeks for $600-1,400 at $14-16/hr. That's usually cheaper than the engineering time it takes to manually triage each report's discrepancy.
See specialist rates
No — that's high. Normal gap is 2-5%. A 15% gap means events are being lost. Most common cause: purchase events fire client-side on a thank-you page, and users close the tab before redirect or have ad blockers. Fix: move revenue tracking to server-side (Stripe webhook → server SDK). Gap should drop to <2%.
Identity merge isn't happening. Three usual causes: (1) alias() not called on signup so anonymous events don't merge with identified events. (2) Email used as distinct_id and user changed email. (3) Client and server use different distinct_id formats. Fix the root cause in code, then use Mixpanel's Identity API to merge existing splits.
Lexicon hiding/archiving only affects what shows in the chart-builder picker. The underlying event data is still there. To actually remove an event from reports, use Data Management → Events → Delete (or merge into another event via Transform). Be careful — deletion is permanent within retention.
Symptom: the first event of every session is missing. To verify: open browser DevTools, throttle network to 'Slow 3G', refresh your site. If events that should fire on page-load don't appear in Live View, SDK is initializing too late. Fix by loading the SDK synchronously in <head> or buffering early events.
Depends on your audience. For B2B SaaS, <5% of business users run ad blockers — minimal data loss. For developer-focused tools or privacy-conscious audiences, can be 15-30%. For mass B2C, ad blockers are growing — 10-20% typical. If concerned, use server-side tracking for critical events (revenue, signup) to bypass client-side blocking.
Mixpanel
Mixpanel doesn't fail because events break — it fails because event names drift. Three engineers, three opinions, three versions of 'signup' over a year. Here's how to ship instrumentation that holds up.
Mixpanel
User identification is the single most-broken part of Mixpanel in DIY installs. Anonymous users never merge with logged-in users, retention curves look like 8% when reality is 40%, and every cohort is wrong. Here's the pattern that actually works.
Amplitude
Amplitude says you're over your event quota and your bill is about to spike. Don't just disable tracking — that'll create gaps. Here's the systematic diagnosis specialists run when this happens.
Mixpanel
Product analytics is a job, not a tool. The teams that pretend it's a tool spend 18 months building a Mixpanel project that doesn't answer their questions. The teams that hire someone get clean answers in a quarter. Here's how to know which path you're on.