Type-safe Mixpanel events in React
Stop shipping typos as new Mixpanel events. Define your tracking plan in Ordaze, generate a typed TypeScript wrapper around mixpanel-browser, and run the scanner in CI to catch any drift before it reaches production.
Mixpanel's JavaScript SDK hands you a single, stringly-typed method: mixpanel.track(eventName, properties). That is fine for a prototype. In a React app with real traffic it means every new event is a naming decision made under pressure inside a feature branch, and every analytics-powered dashboard depends on those strings staying stable forever.
The fix is a small indirection. Instead of calling Mixpanel directly from your components, call a thin typed wrapper whose shape is derived from your tracking plan. Ordaze generates that wrapper for you in TypeScript, and the scanner statically verifies that every tracking call in your React source matches the plan.
The Mixpanel SDK
This guide assumes you are installing the official Mixpanel SDK. The typed wrapper Ordaze generates sits on top of it and calls into it directly. You are not replacing your analytics provider, just adding a type-safe layer.
npm install mixpanel-browserSetup in 5 steps
- 1
Install Mixpanel and initialize it in a client component
Add the official Mixpanel browser SDK and initialize it once, typically in a top-level provider component. Initialization has to happen on the client, so if you are on Next.js App Router this needs the "use client" directive.
npm install mixpanel-browser npm install --save-dev @types/mixpanel-browser - 2
Define your events in Ordaze
Create a new tracking plan or open an existing one. Add events with typed properties, required properties are enforced at the type level in the generated code.
- 3
Generate the TypeScript wrapper
From the Ordaze dashboard, export the TypeScript codegen for Mixpanel. You get a single file with a typed method per event, each calling mixpanel.track under the hood.
// Generated: src/analytics/events.ts import mixpanel from 'mixpanel-browser'; export const track = { signUpCompleted: (props: { plan: 'free' | 'pro' | 'enterprise'; referrer?: string }) => { mixpanel.track('Sign Up Completed', props); }, // ... one method per event }; - 4
Replace raw mixpanel.track calls with the typed wrapper
Search your codebase for mixpanel.track( and replace with the typed method. IDE autocomplete now guides every new call. TypeScript errors catch missing required properties at build time.
// Before mixpanel.track('Sign Up Completed', { plan: 'pro' }); // After track.signUpCompleted({ plan: 'pro' }); - 5
Add the Ordaze scanner to CI
Install @ordaze/scanner and run it as a GitHub Action on every pull request. The scanner reads your React source, finds every analytics call, and fails the build when a call does not match the plan.
# .github/workflows/scan.yml - uses: ordaze/scanner-action@v1 with: project-id: ${{ secrets.ORDAZE_PROJECT_ID }}
Before and after
Untyped, every call is a string literal a human typed
function SignUpButton({ plan }: { plan: string }) {
return (
<button
onClick={() => {
mixpanel.track('Sign Up Complete', { Plan: plan });
// ^ typo: should be 'Completed'
// ^ wrong case: vs 'plan'
}}
>
Sign up
</button>
);
}Typed, the shape comes from the tracking plan
import { track } from '@/analytics/events';
function SignUpButton({ plan }: { plan: 'free' | 'pro' | 'enterprise' }) {
return (
<button
onClick={() => {
track.signUpCompleted({ plan });
// TypeScript error if plan is missing or a string like 'starter'
}}
>
Sign up
</button>
);
}React + Mixpanel gotchas
Do not initialize Mixpanel inside a useEffect
React's Strict Mode runs effects twice in development. Mixpanel will complain about double initialization and, more importantly, you will double-send events fired during the second mount. Initialize at module scope or inside a one-shot check on window.mixpanel.
Turn off autotrack to avoid double-counting
Mixpanel's autotrack feature fires its own events on clicks and form submits. If you also call track.buttonClicked() explicitly, you end up with two events per click, reported under different names. Disable autotrack in mixpanel.init and track explicitly.
Server components cannot call mixpanel-browser
If you are on Next.js App Router, mixpanel-browser fails in a Server Component because window is undefined. Either use a client component for the tracking call, or send the event server-side via the HTTP API from a Server Action.
React events fire before navigation completes
Tracking a button click inside onClick runs before any navigation the handler triggers. If the event needs the destination URL, capture it before calling track, or use a route change listener instead.
Why Ordaze for this combo
Not a Mixpanel replacement
The generated wrapper still calls mixpanel.track under the hood. You keep the Mixpanel SDK, the Mixpanel dashboard, and every Mixpanel feature. Ordaze is a layer on top, not a switch you flip.
One schema, thirteen languages
The same tracking plan feeds React, Swift, Kotlin, Python, and ten more targets. Your iOS team and your web team call the same conceptual event, with types generated natively for each.
Static drift detection
The scanner reads your TypeScript source without running it. It flags calls where the event name or properties drifted from the plan, and it runs in CI before you merge.
Frequently asked questions
Keep reading
Typed Mixpanel events in a weekend
Free plan includes 100 events, unlimited team members, and full TypeScript codegen. No credit card.
Get Started Free