Mixpanel JavaScript SDK: The Complete Implementation Guide

published on 19 March 2026

This guide is based on a real-world implementation we delivered for a financial services client. It covers every technical decision point we encountered — so you don't have to learn them the hard way. We'll use the JavaScript (Browser) SDK, the most common entry point for web applications.

1. Installing the Mixpanel JavaScript SDK

The fastest way to get started is the snippet method: paste the Mixpanel loader script into your HTML <head>, just before the closing </head> tag. This asynchronously loads the SDK from Mixpanel's CDN without blocking your page render.

/* Paste inside  — before  */
/* Full snippet: https://docs.mixpanel.com/docs/quickstart/install-mixpanel?sdk=javascript */

npm / ES module alternative: if you're on a modern JS framework (React, Vue, Angular), install via npm install mixpanel-browser and import it at your app's entry point. The API is identical.

2. Configuring the SDK Correctly

Right after the snippet (still inside <head>), initialize Mixpanel with your project token and a config object:

mixpanel.init("YOUR_TOKEN", {
  track_pageview: false,  // ← set to false; track page views manually
  persistence:     "localStorage",
  debug:           false   // set to true during development
});

To find your Project Token, go to Settings → Project Settings in Mixpanel and scroll down to the Project Token field.

Best practice — use two projects: create a QA project and a Production project. During development point your token at QA; swap it to Production only after you've validated every event in your Tracking Plan. This prevents polluting your real data with test noise.

⚠️ Keep track_pageview: false unless you intentionally want Mixpanel to fire a $pageview event on every navigation. In SPAs this almost always double-counts views. Define page-view events explicitly in your Tracking Plan instead.

3. Tracking Events & Event Properties

Everything in Mixpanel revolves around events — discrete actions a user takes in your product. You track them with mixpanel.track().

// Basic event — no properties
mixpanel.track("Signed Up");

// Event with properties (recommended — always add context)
mixpanel.track("Played Song", {
  genre:    "hip-hop",
  duration: 187,
  premium:  true
});

// Manual page view (since we disabled auto-tracking above)
mixpanel.track_pageview({ page: "Pricing" });

💡 Naming convention: use Title Case for event names ("Clicked CTA") and snake_case for property keys (plan_type, button_label). Pick one convention and stick to it across your entire Tracking Plan — your analysts will thank you.

4. Default & Reserved Event Properties

The JavaScript SDK automatically attaches a set of useful properties to every event — you get them for free: $browser, $device, $current_url, $screen_height, $screen_width, $os, $referrer, mp_country_code, and more.

⚠️ Some property names are reserved by Mixpanel for special processing (e.g. $email, $name, $created). Avoid using these as custom property names unless you intentionally want that special behaviour.

5. Automatic UTM Tracking

You don't need to write any extra code for UTM parameters. When the JavaScript SDK initializes, it reads utm_source, utm_medium, utm_campaign, utm_content, and utm_term from the page URL and automatically attaches them to the first event fired in that session.

These UTM values are also persisted as Super Properties (more on those in step 10), so they travel with subsequent events in the same session — giving you attribution data across the entire user journey, not just the landing page hit.

6. User Identification & Simplified ID Management

Getting identity management right is the single most important part of a Mixpanel implementation. Mess this up and you'll end up with duplicate users, broken funnels, and sessions that don't connect across devices or domains.

The three IDs in Simplified ID Management

device_id: auto-generated by the SDK on first visit. Identifies anonymous sessions. | user_id: your app's internal identifier — passed to Mixpanel on login/signup. | distinct_id: Mixpanel's canonical identifier — equals device_id before login, equals user_id after.

ℹ️ This guide uses Simplified ID Management. Check your project's ID Management setting in Settings → Project Settings → ID Management before reading the docs, as the recommended API calls differ between modes.

The user journey — step by step

1. First visit (anonymous): SDK initializes → auto-generates device_id = $device:abcdistinct_id = device_id → stored in localStorage/cookie.

2. User browses and triggers events: all events are recorded under the anonymous distinct_id.

3. User signs up or logs in: call mixpanel.identify("<user_id>") → anonymous history is merged with the identified profile → distinct_id = user_id.

4. User logs out: call mixpanel.reset() — this creates a fresh anonymous device_id, preventing session bleed if another person uses the same device.

// Identify on login / signup
// Call AFTER you have confirmed the user's identity.
// Use a stable, permanent ID (hashed user ID, UUID, etc.).

mixpanel.identify("usr_98765");

// Reset on logout
// CRITICAL: prevents next user on same device inheriting this session.

mixpanel.reset();

🚨 Never use PII as a user ID. Don't pass email addresses, phone numbers, or government IDs directly to identify(). Use a hashed or opaque internal ID. This keeps your Mixpanel data GDPR-compliant and protects your users.

7. Tracking User Profile Properties

Beyond events, Mixpanel lets you build a rich user profile — persistent attributes that describe who the user is, not just what they did. You can then filter any report by these properties.

// Set one or more user properties at once.
mixpanel.people.set({
  plan:               "pro",
  account_type:       "savings",
  has_active_credit:  true,
  country:            "BO"
});

// set_once — only writes if the property doesn't already exist.
// Perfect for "First Seen Date", "Signup Source", etc.
mixpanel.people.set_once({
  first_login_date: new Date().toISOString()
});

💡 User properties are only useful after mixpanel.identify() has been called. If you call people.set() before identifying the user, the properties will attach to the anonymous profile and may not merge cleanly. Always identify first, then set user properties.

8. Cross-Domain Session Continuity

This is the trickiest part of most implementations. When a user navigates from domain-a.com to domain-b.com, the browser creates a new localStorage/cookie scope for the second domain. Mixpanel sees this as a brand-new anonymous user — breaking your funnel entirely.

The fix is to carry identity information in the URL as query parameters and re-initialize Mixpanel on the second domain.

// On Domain 1: build the hand-off URL
// Call AFTER mixpanel.identify() if the user has already logged in.

const deviceId = mixpanel.get_distinct_id();       // before identify()
const userId   = mixpanel.get_property("$user_id"); // after  identify()

let destination = "https://domain-b.com/home";
destination += `?device_id=${encodeURIComponent(deviceId)}`;

if (userId) {
  destination += `&$user_id=${encodeURIComponent(userId)}`;
}

window.location.href = destination;
// On Domain 2: rehydrate the Mixpanel session
// CRITICAL: run IMMEDIATELY after mixpanel.init()
// and BEFORE any mixpanel.track() calls.

const params     = new URLSearchParams(window.location.search);
const prevDistId = params.get("device_id");
const userId     = params.get("$user_id");

if (prevDistId) {
  if (userId) {
    // User was already identified on Domain 1
    mixpanel.register({ "$device_id": prevDistId.replace("$device:", "") });
    mixpanel.identify(userId);
  } else {
    // User is still anonymous — carry over the device_id only
    mixpanel.register({
      "distinct_id": prevDistId,
      "$device_id":  prevDistId.replace("$device:", "")
    });
  }
}

⚠️ Sub-domains are fine. Moving between app.example.com and blog.example.com does not require this pattern — Mixpanel can share the cookie across sub-domains automatically. This technique is only needed when the root domain changes.

9. Server-Side Tracking

Browser-side tracking is convenient but lossy: ad-blockers, aggressive privacy settings, and script errors can silently drop events. For business-critical actions (purchases, sign-ups, password resets), server-side tracking gives you guaranteed delivery.

Mixpanel has official SDKs for Node.js, Python, Ruby, PHP, Go, and Java. If none of those fit your stack, use the Ingestion API /import endpoint — it accepts JSON batches over HTTPS and is language-agnostic.

// Node.js example (npm install mixpanel)
const Mixpanel = require("mixpanel");
const mp = Mixpanel.init("YOUR_TOKEN");

mp.track("Purchase Completed", {
  distinct_id: "usr_98765",
  amount:      199.00,
  currency:    "USD",
  plan:        "pro"
});

🛡️ Server-side tracking also bypasses ad-blockers that block requests to *.mixpanel.com from the browser. For high-stakes conversion events, fire both a client-side event (for real-time dashboards) and a server-side event (as the source of truth).

10. Super Properties

Super Properties are event properties that are automatically appended to every single event you fire — without passing them manually in each track() call. They are persisted in the Mixpanel cookie / localStorage.

Classic use cases: product line (product: "24 Online"), user segment (user_tier: "premium"), app version (app_version: "4.2.1"), environment (env: "production").

// Register Super Properties — call once at app initialization
mixpanel.register({
  product:     "24 Online",
  platform:    "web",
  app_version: "4.2.1"
});

// register_once — only sets if the property doesn't exist yet
mixpanel.register_once({
  first_visit_date: new Date().toISOString()
});

// Remove a super property when it's no longer relevant
mixpanel.unregister("temporary_campaign_flag");

⚠️ Cross-domain note: Super Properties live in the domain's cookie. When the user moves to a second domain, they don't carry over automatically. Re-register any critical ones after the hand-off (see Step 8).

11. Firewall & Ad-Blocker Considerations

If your users sit behind a corporate firewall — common in banking, insurance, and government — outbound requests to *.mixpanel.com or the CDN at cdn.mxpnl.com may be silently blocked. Your options:

Option 1 — Whitelist: add *.mixpanel.com and cdn.mxpnl.com to your firewall's allowlist. Fast to deploy, but requires IT buy-in.

Option 2 — Proxy server: set up a proxy on your own domain (e.g. analytics.yourdomain.com) that forwards requests to Mixpanel's ingestion endpoint. Configure the SDK with the api_host option in mixpanel.init(). This also defeats most ad-blockers.

Option 3 — Server-side: use server-side tracking for critical events (see Step 9). Events originate from your backend — no browser restrictions apply.

12. Privacy: Opt-Out & Secure Cookies

When a user explicitly withdraws tracking consent, call mixpanel.opt_out_tracking(). To re-enable: mixpanel.opt_in_tracking(). Hook this into your cookie consent banner — when the user clicks "Reject All", call opt_out before any track() fires.

// Stop all tracking and clear stored data for this user.
mixpanel.opt_out_tracking();

// Re-enable if the user later grants consent.
mixpanel.opt_in_tracking();

// Check the current opt-out state.
if (mixpanel.has_opted_out_tracking()) {
  console.log("User has opted out — no events will fire.");
}

// Force HTTPS-only cookies (required for PCI/DSS)
mixpanel.set_config({ secure_cookie: true });

🚨 Required for PCI/DSS and most financial compliance frameworks. If your app handles payment data, set secure_cookie: true from day one — retrofitting it later can briefly reset existing Mixpanel cookies.

Implementation Checklist

  • SDK snippet installed before </head>
  • Two projects set up: QA and Production
  • track_pageview: false configured (unless intentional)
  • All events defined in a Tracking Plan
  • mixpanel.identify() called on login/signup
  • mixpanel.reset() called on logout
  • Cross-domain hand-off implemented (if applicable)
  • Server-side tracking for critical conversions
  • Opt-out hooked into the cookie consent banner
  • secure_cookie: true on HTTPS sites
  • Firewall whitelisting / proxy configured (if applicable)
  • QA pass: all events verified in Mixpanel Live View

Need help implementing Mixpanel in your product? At Bildung Data we help product and engineering teams set up clean, scalable analytics stacks — from Tracking Plan design to full SDK implementation and dashboard buildout. Let's talk →

Read more