Mixpanel Event Tracking | Blue Frog Docs

Mixpanel Event Tracking

Complete guide to Mixpanel event tracking and measurement

Mixpanel Event Tracking

Overview

Mixpanel is built from the ground up as an event-based analytics platform designed for product teams. Unlike web analytics tools that focus on pageviews, Mixpanel tracks granular user actions - button clicks, feature usage, form submissions - and connects them to individual user journeys over time.

The core philosophy is simple: understand what users do and who they are, then analyze retention, engagement, and conversion based on actual behavior, not just traffic. This makes Mixpanel exceptionally powerful for SaaS, mobile apps, and any product where user engagement matters more than page hits.

Event Model

How Mixpanel Events Work

Every event in Mixpanel consists of:

  1. Event Name: What happened (e.g., "Song Played", "Purchase Completed")
  2. Properties: Key-value pairs providing context (e.g., {"song_name": "Bohemian Rhapsody", "genre": "Rock"})
  3. Distinct ID: Unique identifier for the user
  4. Timestamp: When the event occurred (auto-captured or custom)

Event Structure:

{
  "event": "Song Played",
  "properties": {
    "distinct_id": "user_12345",
    "time": 1640000000,
    "song_name": "Bohemian Rhapsody",
    "artist": "Queen",
    "genre": "Rock",
    "duration_seconds": 354,
    "platform": "mobile_app"
  }
}

Key Concepts

  • Events: Individual occurrences (plays, clicks, purchases)
  • Event Properties: Attributes describing the event
  • User Properties: Attributes describing the user (set via people.set())
  • Super Properties: Properties sent with every event automatically
  • Distinct ID: Unique user identifier (persists across sessions)

Limits

  • Event name: 255 characters
  • Property name: 255 characters
  • Property value: 255 characters for strings
  • Events per project: Unlimited (billed by volume)
  • Properties per event: 255 properties

Standard Events

Mixpanel doesn't enforce predefined events like GA4, but provides recommended event naming conventions for common use cases.

Authentication:

  • Sign Up: User creates account
  • Login: User authenticates
  • Logout: User logs out

Content Engagement:

  • Page Viewed: User views a page/screen
  • Content Viewed: User views specific content
  • Search Performed: User searches
  • Filter Applied: User filters results

Social Actions:

  • Share: User shares content
  • Comment: User comments
  • Like: User likes content
  • Follow: User follows another user

Product Usage:

  • Feature Used: Generic feature interaction
  • Button Clicked: Button/CTA clicked
  • Form Submitted: Form completion
  • Video Played: Video engagement

Implementation Examples

// Sign Up
mixpanel.track('Sign Up', {
  'source': 'homepage',
  'method': 'email',
  'referrer': document.referrer
});

// Content Engagement
mixpanel.track('Page Viewed', {
  'page_name': 'Product Details',
  'product_id': 'SKU_12345',
  'category': 'Electronics'
});

// Social Action
mixpanel.track('Share', {
  'content_type': 'article',
  'content_id': 'blog_post_123',
  'platform': 'Twitter'
});

Custom Events

Custom events are the heart of Mixpanel. You define events that matter to your product.

Creating Custom Events

JavaScript SDK:

// Basic event
mixpanel.track('Button Clicked');

// Event with properties
mixpanel.track('Video Watched', {
  'video_title': 'Getting Started Tutorial',
  'video_length': 180,
  'percent_watched': 75,
  'quality': '1080p'
});

// Event with user context
mixpanel.track('Feature Enabled', {
  'feature_name': 'Dark Mode',
  'subscription_tier': 'Pro',
  'enabled_from': 'settings_page'
});

Python SDK:

from mixpanel import Mixpanel

mp = Mixpanel('YOUR_PROJECT_TOKEN')

# Track event
mp.track('user_12345', 'Purchase Completed', {
    'product_id': 'SKU_789',
    'price': 49.99,
    'currency': 'USD',
    'payment_method': 'credit_card'
})

# Track with timestamp
import time
mp.track('user_12345', 'App Opened', {
    'platform': 'iOS',
    'version': '2.1.0'
}, meta={'time': int(time.time())})

Mobile (iOS - Swift):

// Track event
Mixpanel.mainInstance().track(event: "Level Completed", properties: [
    "level_name": "Forest Temple",
    "level_number": 5,
    "score": 8750,
    "time_seconds": 234
])

// Increment user property
Mixpanel.mainInstance().people.increment(property: "levels_completed", by: 1)

Mobile (Android - Kotlin):

val mixpanel = MixpanelAPI.getInstance(context, "YOUR_PROJECT_TOKEN")

// Track event
val properties = JSONObject()
properties.put("level_name", "Forest Temple")
properties.put("level_number", 5)
properties.put("score", 8750)
properties.put("time_seconds", 234)

mixpanel.track("Level Completed", properties)

Event Naming Best Practices

✅ Good Event Names:

  • Purchase Completed (clear action)
  • Video Played (specific behavior)
  • Onboarding Step Completed (descriptive)

❌ Bad Event Names:

  • click (too generic)
  • PurchaseCompleted (use Title Case with spaces)
  • purchase_completed_successfully_by_user (too verbose)

Ecommerce Events

Mixpanel supports comprehensive ecommerce tracking through custom events and properties.

Product Discovery

// Product List Viewed
mixpanel.track('Product List Viewed', {
  'list_id': 'search_results',
  'category': 'Electronics',
  'products_count': 24,
  'filters_applied': ['price_low_to_high', 'in_stock']
});

// Product Viewed
mixpanel.track('Product Viewed', {
  'product_id': 'SKU_12345',
  'product_name': 'Wireless Headphones',
  'price': 199.99,
  'currency': 'USD',
  'category': 'Audio',
  'brand': 'BrandName',
  'in_stock': true,
  'variant': 'Black'
});

Cart Actions

// Product Added
mixpanel.track('Product Added', {
  'product_id': 'SKU_12345',
  'product_name': 'Wireless Headphones',
  'price': 199.99,
  'quantity': 1,
  'cart_total': 199.99,
  'cart_item_count': 1
});

// Product Removed
mixpanel.track('Product Removed', {
  'product_id': 'SKU_12345',
  'reason': 'user_removed',
  'cart_total': 0
});

// Cart Viewed
mixpanel.track('Cart Viewed', {
  'cart_total': 399.98,
  'cart_item_count': 2,
  'product_ids': ['SKU_12345', 'SKU_67890']
});

Checkout Flow

// Checkout Started
mixpanel.track('Checkout Started', {
  'checkout_id': 'CHK_ABC123',
  'cart_total': 399.98,
  'item_count': 2,
  'checkout_type': 'express'
});

// Payment Info Added
mixpanel.track('Payment Info Added', {
  'checkout_id': 'CHK_ABC123',
  'payment_method': 'credit_card',
  'card_type': 'visa'
});

// Order Completed
mixpanel.track('Order Completed', {
  'order_id': 'ORDER_12345',
  'revenue': 399.98,
  'tax': 32.00,
  'shipping': 15.00,
  'total': 446.98,
  'currency': 'USD',
  'item_count': 2,
  'payment_method': 'credit_card',
  'coupon_code': 'SAVE20',
  'discount_amount': 80.00,
  'is_first_purchase': true
});

// Track revenue (appears in Revenue report)
mixpanel.people.track_charge(446.98, {
  'order_id': 'ORDER_12345',
  'products': ['SKU_12345', 'SKU_67890']
});

Subscription Events

// Subscription Started
mixpanel.track('Subscription Started', {
  'plan_name': 'Pro Annual',
  'plan_price': 299.99,
  'billing_cycle': 'yearly',
  'trial_days': 14,
  'payment_method': 'credit_card'
});

// Subscription Upgraded
mixpanel.track('Subscription Upgraded', {
  'old_plan': 'Basic Monthly',
  'new_plan': 'Pro Monthly',
  'price_difference': 20.00
});

// Subscription Cancelled
mixpanel.track('Subscription Cancelled', {
  'plan_name': 'Pro Monthly',
  'cancellation_reason': 'too_expensive',
  'months_subscribed': 6
});

User Properties

User properties (called "People Properties" in Mixpanel) describe who the user is, not what they did.

Setting User Properties

JavaScript:

// Set properties (overwrites)
mixpanel.people.set({
  'name': 'John Doe',
  'email': 'john@example.com',
  'subscription_tier': 'Pro',
  'signup_date': '2024-01-15',
  'total_purchases': 3
});

// Set once (never overwrites)
mixpanel.people.set_once({
  'first_visit': new Date().toISOString(),
  'initial_referrer': document.referrer
});

// Increment numeric properties
mixpanel.people.increment('page_views');
mixpanel.people.increment('credits_balance', 10);

// Append to list
mixpanel.people.append('favorite_categories', 'Electronics');

// Union (add unique values to list)
mixpanel.people.union('devices_used', ['iPhone', 'iPad']);

Python:

# Set properties
mp.people_set('user_12345', {
    'name': 'John Doe',
    'email': 'john@example.com',
    'subscription_tier': 'Pro'
})

# Increment
mp.people_increment('user_12345', {'login_count': 1})

# Append
mp.people_append('user_12345', {
    'transactions': 'ORDER_12345'
})

Standard User Properties

Mixpanel recognizes these special properties:

  • $email: Email address (used for messaging)
  • $name: Full name
  • $created: Account creation date
  • $phone: Phone number
  • $avatar: Profile picture URL

Setting Standard Properties:

mixpanel.people.set({
  '$email': 'john@example.com',
  '$name': 'John Doe',
  '$created': '2024-01-15T10:30:00',
  '$phone': '+1-555-123-4567'
});

Custom User Properties

mixpanel.people.set({
  'company_size': '50-100',
  'industry': 'Technology',
  'role': 'Product Manager',
  'feature_flags': {
    'new_dashboard': true,
    'beta_features': true
  },
  'lifetime_value': 1299.99,
  'last_active': new Date().toISOString()
});

Event Properties

Event properties provide context about what happened during an event.

Default Properties

Mixpanel automatically captures:

  • $browser: Browser name
  • $browser_version: Browser version
  • $os: Operating system
  • $device: Device model
  • $screen_height, $screen_width: Screen dimensions
  • $city, $region, $country: Geographic location
  • $referrer: Referring URL
  • $referring_domain: Referring domain
  • mp_lib: SDK name/version

Super Properties

Properties that automatically attach to every event:

// Register super property (persists across sessions)
mixpanel.register({
  'app_version': '2.1.0',
  'environment': 'production',
  'subscription_tier': 'Pro'
});

// Register once (won't overwrite)
mixpanel.register_once({
  'initial_utm_source': 'google',
  'first_landing_page': '/pricing'
});

// Unregister super property
mixpanel.unregister('environment');

Custom Event Properties

// Rich event properties
mixpanel.track('Article Read', {
  'article_id': 'blog_123',
  'article_title': 'Getting Started with Analytics',
  'word_count': 1500,
  'read_time_seconds': 240,
  'scroll_depth_percent': 85,
  'author': 'Jane Smith',
  'category': 'Tutorial',
  'tags': ['analytics', 'getting-started', 'beginner'],
  'published_date': '2024-01-10',
  'is_premium_content': false
});

Property Data Types

Mixpanel supports:

  • String: "Premium User"
  • Number: 29.99, 42
  • Boolean: true, false
  • Date: new Date(), ISO 8601 strings
  • Array: ["tag1", "tag2"] (use for multi-select)
  • Object: {key: "value"} (limited support, prefer flat structure)

Implementation Methods

1. JavaScript SDK (Web)

Installation:

<!-- Snippet (Recommended) -->
<script type="text/javascript">
(function(f,b){if(!b.__SV){var e,g,i,h;window.mixpanel=b;b._i=[];b.init=function(e,f,c){function g(a,d){var b=d.split(".");2==b.length&&(a=a[b[0]],d=b[1]);a[d]=function(){a.push([d].concat(Array.prototype.slice.call(arguments,0)))}}var a=b;"undefined"!==typeof c?a=b[c]=[]:c="mixpanel";a.people=a.people||[];a.toString=function(a){var d="mixpanel";"mixpanel"!==c&&(d+="."+c);a||(d+=" (stub)");return d};a.people.toString=function(){return a.toString(1)+".people (stub)"};i="disable time_event track track_pageview track_links track_forms track_with_groups add_group set_group remove_group register register_once alias unregister identify name_tag set_config reset opt_in_tracking opt_out_tracking has_opted_in_tracking has_opted_out_tracking clear_opt_in_out_tracking start_batch_senders people.set people.set_once people.unset people.increment people.append people.union people.track_charge people.clear_charges people.delete_user people.remove".split(" ");
for(h=0;h<i.length;h++)g(a,i[h]);var j="set set_once union unset remove delete".split(" ");a.get_group=function(){function b(c){d[c]=function(){call2_args=arguments;call2=[c].concat(Array.prototype.slice.call(call2_args,0));a.push([e,call2])}}for(var d={},e=["get_group"].concat(Array.prototype.slice.call(arguments,0)),c=0;c<j.length;c++)b(j[c]);return d};b._i.push([e,f,c])};b.__SV=1.2;e=f.createElement("script");e.type="text/javascript";e.async=!0;e.src="undefined"!==typeof MIXPANEL_CUSTOM_LIB_URL?
MIXPANEL_CUSTOM_LIB_URL:"file:"===f.location.protocol&&"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^\/\//)?"https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js":"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";g=f.getElementsByTagName("script")[0];g.parentNode.insertBefore(e,g)}})(document,window.mixpanel||[]);

mixpanel.init('YOUR_PROJECT_TOKEN', {
  debug: false,
  track_pageview: true,
  persistence: 'localStorage'
});
</script>

NPM:

npm install mixpanel-browser
import mixpanel from 'mixpanel-browser';

mixpanel.init('YOUR_PROJECT_TOKEN', {
  debug: true,
  ignore_dnt: true
});

// Track event
mixpanel.track('Page Viewed');

2. Server-Side SDKs

Node.js:

const Mixpanel = require('mixpanel');
const mixpanel = Mixpanel.init('YOUR_PROJECT_TOKEN');

// Track event
mixpanel.track('Server Action', {
  distinct_id: 'user_123',
  action_type: 'api_call',
  endpoint: '/api/users'
});

// Set user properties
mixpanel.people.set('user_123', {
  $email: 'user@example.com',
  plan: 'Enterprise'
});

Python:

from mixpanel import Mixpanel

mp = Mixpanel('YOUR_PROJECT_TOKEN')

# Track event
mp.track('user_123', 'API Request', {
    'endpoint': '/api/data',
    'method': 'GET',
    'response_time_ms': 45
})

# Set people properties
mp.people_set('user_123', {
    '$email': 'user@example.com',
    'plan': 'Enterprise'
})

Ruby:

require 'mixpanel-ruby'
tracker = Mixpanel::Tracker.new('YOUR_PROJECT_TOKEN')

# Track event
tracker.track('user_123', 'Purchase', {
  'product_id' => 'SKU_789',
  'price' => 49.99
})

# Set properties
tracker.people.set('user_123', {
  '$email' => 'user@example.com',
  'total_purchases' => 5
})

3. Mobile SDKs

iOS (Swift):

import Mixpanel

// Initialize
Mixpanel.initialize(token: "YOUR_PROJECT_TOKEN")

// Track
Mixpanel.mainInstance().track(event: "Button Tapped", properties: [
    "button_name": "signup",
    "screen": "home"
])

// Identify user
Mixpanel.mainInstance().identify(distinctId: "user_123")

// Set user properties
Mixpanel.mainInstance().people.set(properties: [
    "$email": "user@example.com",
    "name": "John Doe"
])

Android (Kotlin):

import com.mixpanel.android.mpmetrics.MixpanelAPI

val mixpanel = MixpanelAPI.getInstance(context, "YOUR_PROJECT_TOKEN")

// Track
val props = JSONObject()
props.put("button_name", "signup")
props.put("screen", "home")
mixpanel.track("Button Tapped", props)

// Identify
mixpanel.identify("user_123")

// Set user properties
mixpanel.people.set("email", "user@example.com")
mixpanel.people.set("name", "John Doe")

4. HTTP API (Direct)

curl https://api.mixpanel.com/track \
  -d 'data=eyJldmVudCI6ICJTaWduIFVwIiwgInByb3BlcnRpZXMiOiB7InRva2VuIjogIllPVVJfVE9LRU4iLCAiZGlzdGluY3RfaWQiOiAidXNlcl8xMjMiLCAic291cmNlIjogImhvbWVwYWdlIn19'

Where data is base64 encoded JSON:

{
  "event": "Sign Up",
  "properties": {
    "token": "YOUR_TOKEN",
    "distinct_id": "user_123",
    "source": "homepage"
  }
}

Debugging & Validation

1. Mixpanel Debugger (Browser Console)

Enable debug mode:

mixpanel.init('YOUR_PROJECT_TOKEN', {debug: true});

Look for console logs:

[Mixpanel] Tracking "Page Viewed" with properties: {...}
[Mixpanel] Sent request to Mixpanel API

2. Live View

In Mixpanel interface:

  1. Navigate to Events > Live View
  2. Perform actions on your site/app
  3. See events appear in real-time (within seconds)
  4. Inspect event properties and user profiles

3. Events Page

  • Events > All Events: See all event names
  • Events > Event Details: Dive into specific event
  • Click event to see sample properties and volume

4. Network Tab Inspection

Look for requests to:

https://api.mixpanel.com/track
https://api.mixpanel.com/engage (for People properties)

Inspect payload (base64 decode):

// Decode in console
atob('BASE64_STRING_FROM_NETWORK_TAB')

5. Mixpanel SDK Helpers

// Check current distinct_id
console.log(mixpanel.get_distinct_id());

// Check super properties
console.log(mixpanel.persistence.properties());

// Get all tracked data
console.log(mixpanel.get_config());

6. Data Validation

Check for:

  • Events appearing in Live View
  • Correct property names and values
  • User profiles updating (People page)
  • No duplicate users (merge if needed)
  • Proper distinct_id assignment

Best Practices

Event Design

✅ Do:

  • Use clear, action-based event names: "Purchase Completed" not "Purchase"
  • Track user intent, not just clicks: "Search Performed" not "Button Clicked"
  • Include relevant context in properties
  • Be consistent with naming conventions (Title Case)
  • Track both successes and failures

❌ Don't:

  • Create overly specific events: "HomePage_BlueButton_Clicked_MorningSession"
  • Use generic names: "Event1", "Action", "Click"
  • Track PII without hashing
  • Send excessive events (performance impact)

Property Strategy

✅ Do:

  • Use descriptive property names: video_title not vt
  • Keep property names consistent across events
  • Use appropriate data types (numbers for metrics, not strings)
  • Document property definitions
  • Use arrays for multi-value properties

❌ Don't:

  • Send empty/null values
  • Use inconsistent property names: user_id vs userId
  • Nest objects deeply (flatten when possible)
  • Exceed property limits

User Identity

// Before login (anonymous)
mixpanel.track('Page Viewed');

// After sign up - create alias
mixpanel.alias('user_12345'); // Links anonymous ID to user ID

// After login - identify
mixpanel.identify('user_12345');

// Set user properties
mixpanel.people.set({
  '$email': 'user@example.com',
  'name': 'John Doe'
});

Identity Best Practices:

  • Call alias() once when user first signs up
  • Call identify() on every login/session start
  • Use consistent distinct_id format
  • Don't reuse distinct_ids across different users

Performance

  • Initialize SDK early in page load
  • Batch events when possible (server-side)
  • Avoid tracking every scroll/mouse move
  • Use sampling for high-volume events
  • Consider async tracking for non-critical events

Privacy & Compliance

✅ Do:

  • Implement opt-out mechanisms
  • Hash sensitive identifiers
  • Configure EU data residency if needed
  • Document data retention policies
  • Respect Do Not Track (optional)
// Opt user out
mixpanel.opt_out_tracking();

// Opt user in
mixpanel.opt_in_tracking();

// Check opt-out status
if (!mixpanel.has_opted_out_tracking()) {
  mixpanel.track('Event');
}

❌ Don't:

  • Track PII without consent
  • Send passwords, credit cards, SSNs
  • Ignore regional privacy laws (GDPR, CCPA)

Testing

  • Use separate projects for dev/staging/prod
  • Test identity merging scenarios
  • Validate event properties before launch
  • Monitor for duplicate events
  • Set up alerts for anomalies

Additional Resources:

// SYS.FOOTER