Welcome to FixPanel, a modern, React + Next.js + Tailwind series of demo sites for 6 different industry use cases. It showcases the power of Mixpanel's SDKs and how its core capabilities might be implemented in a modern web app.
- Node.js (v16 or later)
- npm
git clone https://github.com/mixpanel/fixpanel.git
cd fixpanel
npm install
npm run devOpen http://localhost:3000 to view the landing page.
npm run dev # Start development server
npm run build # Build for production (includes copying oneoffs)
npm start # Start production server
npm run lint # Run ESLint
npm run typecheck # Run TypeScript type checking
npm run test:app # Core-app Playwright smoke tests (REQUIRED to merge)
npm run test:oneoffs # Oneoff load tests (advisory)
npm run test # Run the full Playwright suite
npm run sanity # Serve dev build locally
npm run sanity:prod # Serve production build locally
npm run oneoffs # Serve oneoffs directory standaloneThe app is pre-configured to send data to the demo Mixpanel project.
Data Architecture: All microsites send data to the same Mixpanel project (ID: 3276012), but each vertical has its own dedicated data view for filtering and analysis:
- weBuy (Ecommerce): View 4354009
- iBank (Financial): View 4354010
- meTube (Media): View 4354011
- youAdmin (SaaS): View 4354012
- ourHeart (Healthcare): View 4354013
- theyRead (Social): View 4354015
The Header and Footer Mixpanel links automatically route users to the appropriate vertical-specific view based on which microsite they're viewing.
To use your own Mixpanel project, create a .env file:
REACT_APP_MIXPANEL_TOKEN=your_token_herefixpanel/
├── app/ # Next.js app router pages
│ ├── page.tsx # Landing page (vertical selector)
│ ├── financial/ # Financial services demo (fully built)
│ ├── checkout/ # Ecommerce demo (scaffolded)
│ ├── streaming/ # Media & streaming demo (scaffolded)
│ ├── admin/ # SaaS B2B demo (scaffolded)
│ ├── lifestyle/ # Subscription B2C demo (scaffolded)
│ └── wellness/ # Healthcare demo (scaffolded)
│
├── components/ # React components
│ ├── ui/ # shadcn/ui components (Button, Card, etc.)
│ ├── Header.tsx # Context-aware navigation header
│ ├── Modal.tsx # Feature flag demo (exp_customerStory)
│ └── ...
│
├── lib/ # Utilities
│ ├── analytics.ts # Mixpanel initialization and config
│ └── utils.ts # Tailwind class merging utilities
│
├── oneoffs/ # Standalone microsites (copied to build)
│ ├── payments/ # PayFlow payment demo (vanilla HTML/CSS/JS)
│ ├── dev/ # Developer demo microsite
│ ├── hud/ # HUD demo microsite
│ └── metube/ # YouTube-like demo
│
├── scripts/ # Build and automation
│ ├── copy-oneoffs.js # Postbuild script (copies oneoffs to out/)
│ └── headless.js # Headless automation script
│
├── public/ # Static assets
├── out/ # Production build output (Next.js + oneoffs)
└── dev/ # Development assets
app/ClientLayout.tsx- Mixpanel initialization viainitMixpanel()lib/analytics.ts- Mixpanel SDK setup (auto-capture, session replay, feature flags)components/Modal.tsx- Feature flagging example usingmixpanel.flags.get_variant_value()tailwind.config.js- Custom color palette and theme configurationscripts/copy-oneoffs.js- Copies standalone demos from./oneoffs/to./out/during build
- Client-side only: Next.js configured for static export (
output: "export"), all components use"use client" - Mixpanel integration: Initialized in
ClientLayout.tsx, exposeswindow.mixpanelandwindow.RESET()globally - Feature flags: Demo experiment
exp_customerStorycontrols homepage modal variants - Styling: Tailwind CSS with custom brand colors (primary purple:
#7856FF) - Components: shadcn/ui library with Radix UI primitives
/- Landing page with industry vertical selection/financial/*- Complete FixPanel financial services demo/checkout/*- Ecommerce demo (scaffolded)/streaming/*- Media & streaming demo (scaffolded)/admin/*- SaaS B2B demo (scaffolded)/lifestyle/*- Subscription B2C demo (scaffolded)
/payments/- PayFlow payment demo/dev/- Developer demo/hud/- HUD interface demo/metube/- Video platform demo/mixstake/- iGaming casino & sportsbook demo (+/mixstake/admin.htmlevent generator)- ...and more — see the full auto-generated index
Oneoffs are automatically copied to the build output during npm run build via the postbuild script.
TL;DR for SEs: most contributions are your own oneoff demo. Branch → open a PR → wait for CI green → squash-merge it yourself. Direct pushes to
mainare blocked for everyone.
main is protected. Nobody pushes to main directly — all changes land
through a pull request.
- Branch off
main:git checkout -b my-demo - Make your changes and push the branch.
- Open a PR into
main. CI runs automatically. - Once the required checks are green, squash-merge your own PR — no second reviewer required (review is welcome, just not enforced).
What CI checks (and what blocks a merge):
| Check | What it runs | Blocks merge? |
|---|---|---|
verify |
npm run lint |
✅ yes |
build |
npm run build (+ npm run typecheck) |
✅ yes |
test-app |
npm run test:smoke (core app) |
✅ yes |
test-oneoffs |
npm run test:oneoffs (oneoff loads) |
The core FixPanel app is protected hard. Oneoff load tests run for visibility
but don't block your merge — so a hiccup in your own demo won't stop you.
Run npm run test:app and npm run typecheck locally before pushing to get
green fast.
- Create a new directory under
app/(e.g.,app/travel/) - Add a
page.tsxwith"use client"directive - Import and use Mixpanel tracking from
lib/analytics.ts - Update the landing page (
app/page.tsx) to include your new vertical
A oneoff is a self-contained, client-side-only microsite (vanilla HTML/CSS/JS, no build step, no server). Convention:
-
Create a directory in
./oneoffs/(e.g.,./oneoffs/mynewdemo/) with anindex.htmlas the entry point. Extra pages (e.g. anadmin.html) are fine — seeoneoffs/mixstake/for a two-page example. -
Wire up Mixpanel with the standard snippet, using your own project token and the shared FixPanel proxy (matches every other oneoff — avoids ad blockers):
mixpanel.init('YOUR_PROJECT_TOKEN', { api_host: 'https://express-proxy-lmozz6xkha-uc.a.run.app', record_sessions_percent: 100, flags: true, });
Don't set
remote_settings_mode— the proxy doesn't serve that route and it'll throw a/settings/404 in the console. -
npm run buildregenerates the listing atoneoffs/index.htmland copies your demo to./out/mynewdemo/automatically — no manual registration. -
(Optional) Link it on the landing page in
app/page.tsx(the "Additional standalone demos" row) so people can find it. -
npm run test:oneoffsto confirm it loads with no uncaught JS errors. New oneoffs are auto-discovered by the test — no test edits needed.
Access your demo at /mynewdemo/ (e.g. https://mixpanel.github.io/fixpanel/mynewdemo/).
import mixpanel from 'mixpanel-browser';
// Track event
mixpanel.track('Button Clicked', { button_name: 'Submit' });
// Set user properties
mixpanel.people.set({ plan_type: 'Premium' });
// Identify user
mixpanel.identify('user_123');const variant = mixpanel.flags.get_variant_value('exp_flag_name');
if (variant === 'control') {
// Show control experience
} else if (variant === 'test') {
// Show test experience
}- Use Tailwind utility classes
- Follow existing component patterns from
components/ui/ - Brand colors defined in
tailwind.config.js - Prettier configured for 120 character line width
Each microsite has its own data view for focused analysis: