Using Google Analytics 4, Mixpanel, and Sentry together: what to track, how to avoid duplicate events, and how instrumentation drove a 25% conversion lift and a 35% drop in frontend errors.
We used analytics as a product loop, not a tag dump.
| Tool | Question it answers |
|---|---|
| GA4 | Are we acquiring and converting? |
| Mixpanel | Which features get used, by whom, in what order? |
| Sentry | What is breaking, how often, and on which release? |
After wiring these to the new storefront we saw about a 25% conversion increase, 15% lower bounce rate, and 35% fewer frontend errors once Sentry issues were triaged weekly.
Name events as verbs a PM can read. Properties should be stable.
type ShopEvent =
| { name: 'product_viewed'; properties: { sku: string; category: string } }
| { name: 'add_to_cart'; properties: { sku: string; value: number } }
| { name: 'checkout_started'; properties: { itemCount: number; value: number } }
| { name: 'purchase_completed'; properties: { orderId: string; value: number } };
export function track(event: ShopEvent) {
mixpanel.track(event.name, event.properties);
gtag('event', event.name, event.properties);
}
Do not fire page_view from both the router and GA's enhanced measurement without a plan. Duplicate pageviews wreck bounce rate.
Keep a tracking plan in the repo:
| Event | Trigger | Properties | Owner |
| add_to_cart | click CTA | sku, value | Checkout |
If it is not in the plan, it does not ship.
GA4 is the language marketing already speaks. Send purchase with value and currency so revenue reports are not a second spreadsheet.
gtag('event', 'purchase', {
transaction_id: order.id,
value: order.total,
currency: 'USD',
items: order.lines.map((line) => ({
item_id: line.sku,
item_name: line.name,
price: line.price,
quantity: line.qty,
})),
});
Mark checkout steps as a funnel: view_item → add_to_cart → begin_checkout → purchase. When conversion moved 25%, this funnel showed where, not just that the homepage was prettier.
Mixpanel is for "do returning patients use the reorder flow?" and "does the new lab-results tab get a second session?"
mixpanel.identify(user.id);
mixpanel.people.set({
plan: user.plan,
lab_count: user.labCount,
});
mixpanel.track('results_tab_opened', {
panel: 'hormones',
source: 'email',
});
Cohorts beat vanity: users who opened results twice in 7 days vs. one-and-done. That is how we decided which nav item deserved the expensive redesign.
Analytics without error tracking celebrates a checkout that throws after the click.
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
environment: process.env.NEXT_PUBLIC_ENV,
});
Sentry.setUser({ id: user.id });
Tag releases with the git SHA. When error rate dropped 35%, it was not magic: we had a weekly triage of new issues, ownership, and a budget to fix the top five.
Filter noise:
Frontend engineers own the event stream. If Mixpanel is empty and Sentry is noisy, the product is flying blind. Instrument the funnel, then read it every week.