PostHog Analytics¶
Complete guide for product analytics with PostHog in the Freeze Design webshop.
Status 2026-06-10: PostHog is not receiving events
The PostHog project currently receives no events — the instrumentation is broken/missing. Do not use PostHog to verify errors or traffic until this is fixed; Sentry is the working error tracker. The sections below describe the intended setup and remain valid as reference once instrumentation is restored.
Overview¶
PostHog provides product analytics, session recording, and feature flags. We use the EU-hosted instance for GDPR compliance.
| Feature | Status | Free Tier |
|---|---|---|
| Product Analytics | ⚠️ Configured (no events arriving) | 1M events/month |
| Session Recording | ⚠️ Configured (no events arriving) | 5K recordings/month |
| Feature Flags | ✅ Available | Unlimited |
| A/B Testing | ✅ Available | Unlimited |
Setup¶
1. Create PostHog Account¶
- Go to eu.posthog.com (EU instance for GDPR)
- Sign up with GitHub or email
- Create a new project (e.g., "Freeze Design Production")
- Copy your Project API Key from Settings → Project → Project API Key
2. Configure Environment¶
Add to frontend/.env.local:
For production, add these as secrets in your deployment platform.
3. Verify Installation¶
- Start the frontend:
npm run dev - Accept the analytics cookies in the cookie banner (capturing is opt-out by default)
- Open browser DevTools → Network tab
- Filter by "posthog"
- Navigate between pages (non-admin pages — PostHog is not loaded on admin routes)
- You should see requests to
eu.i.posthog.com
Architecture¶
┌─────────────────┐ ┌──────────────────┐ ┌─────────────┐
│ layout.tsx │────▶│ PostHogProvider │────▶│ posthog.ts │
│ (root layout) │ │ (pageview track) │ │ (init/API) │
└─────────────────┘ └──────────────────┘ └─────────────┘
│
▼
┌─────────────────┐
│ eu.i.posthog.com│
└─────────────────┘
Admin routes are excluded
app/layout.tsx loads PostHogProvider via a dynamic import and only
mounts it in the non-admin branch of the layout. Admin sessions are
deliberately kept out of the product analytics (and posthog-js stays out
of the admin bundle).
Automatic Tracking¶
These events are tracked automatically:
| Event | Trigger | Data |
|---|---|---|
$pageview |
Page navigation | URL, referrer |
$pageleave |
Page exit | Time on page |
$autocapture |
Clicks, inputs | Element info |
Custom E-commerce Events¶
Import and use the e-commerce event helpers:
import { ecommerceEvents } from '@/lib/posthog';
// Product viewed
ecommerceEvents.viewProduct('prod-123', 'T-Shirt Classic', 24.99);
// Added to cart
ecommerceEvents.addToCart('prod-123', 'T-Shirt Classic', 2, 24.99);
// Removed from cart
ecommerceEvents.removeFromCart('prod-123', 'T-Shirt Classic');
// Checkout started
ecommerceEvents.beginCheckout(149.97, 3);
// Order completed
ecommerceEvents.completeCheckout('order-456', 149.97, 3);
// Design created in designer
ecommerceEvents.designCreated('prod-123', 'custom-print');
// Design saved
ecommerceEvents.designSaved('design-789');
Custom Events¶
Track any custom event:
import { trackEvent } from '@/lib/posthog';
// Track with properties
trackEvent('team_order_created', {
teamSize: 15,
productType: 'polo-shirt',
hasCustomDesign: true,
});
// Track simple event
trackEvent('newsletter_subscribed');
User Identification¶
Identify logged-in users for cross-session tracking:
import { identifyUser, resetUser } from '@/lib/posthog';
// After login
identifyUser(user.id, {
email: user.email,
name: user.name,
plan: user.subscriptionPlan,
});
// After logout
resetUser();
Feature Flags¶
Create a Feature Flag¶
- Go to PostHog → Feature Flags
- Click "New feature flag"
- Set the key (e.g.,
new-checkout-flow) - Configure rollout percentage or user targeting
- Save
Use in Code¶
import posthog from 'posthog-js';
// Check if feature is enabled
if (posthog.isFeatureEnabled('new-checkout-flow')) {
// Show new checkout
} else {
// Show old checkout
}
// Get feature flag value (for multivariate flags)
const variant = posthog.getFeatureFlag('pricing-experiment');
if (variant === 'discount-10') {
// Show 10% discount
}
React Hook Pattern¶
import { useFeatureFlagEnabled } from 'posthog-js/react';
function CheckoutButton() {
const showNewCheckout = useFeatureFlagEnabled('new-checkout-flow');
if (showNewCheckout) {
return <NewCheckoutButton />;
}
return <LegacyCheckoutButton />;
}
A/B Testing¶
Create an Experiment¶
- Go to PostHog → Experiments
- Click "New experiment"
- Set experiment name and feature flag key
- Define variants (control, test)
- Set goal metric (e.g.,
order_completed) - Set minimum sample size
- Launch experiment
Track Experiment Goal¶
// The goal event is automatically tracked when you use ecommerceEvents
ecommerceEvents.completeCheckout(orderId, orderValue, itemCount);
// Or track custom goal
trackEvent('experiment_goal_reached', {
experiment: 'pricing-test',
variant: 'discount-10',
});
Session Recording¶
Session recordings are enabled by default. Configure in lib/posthog.ts:
posthog.init(POSTHOG_KEY, {
// Disable to save quota
disable_session_recording: false,
// Mask sensitive data
mask_all_text: false, // Set true to mask all text
mask_all_element_attributes: false,
});
View Recordings¶
- Go to PostHog → Recordings
- Filter by:
- Page URL
- User properties
- Events performed
- Watch recording to understand user behavior
Dashboard Setup¶
Recommended Dashboards¶
Create these dashboards in PostHog:
1. E-commerce Funnel¶
- Go to Insights → New insight
- Select "Funnel"
- Add steps:
product_viewed,product_added_to_cart,checkout_started,order_completed - Save to dashboard
2. Key Metrics¶
| Metric | Insight Type | Event |
|---|---|---|
| Daily Active Users | Trends | $pageview (unique users) |
| Conversion Rate | Funnel | Full e-commerce funnel |
| Avg Order Value | Trends | order_completed → avg of orderValue |
| Cart Abandonment | Funnel | Cart → Checkout drop-off |
3. Designer Usage¶
Track product designer engagement:
design_created- New designs starteddesign_saved- Designs saved- Time in designer (session recording)
GDPR Compliance¶
Our PostHog setup is GDPR compliant:
| Setting | Value | Purpose |
|---|---|---|
api_host |
eu.i.posthog.com |
EU data residency |
respect_dnt |
true |
Honor Do Not Track |
opt_out_capturing_by_default |
true |
No capture before cookie-consent opt-in |
property_denylist |
['$ip'] |
Don't store IP addresses |
persistence |
localStorage+cookie |
User consent controls |
Cookie Consent Integration¶
The cookie banner is implemented in frontend/components/CookieConsent.tsx.
It stores the choice under the cookie_consent key in localStorage;
lib/posthog.ts restores it on init via the loaded callback:
import posthog from 'posthog-js';
// User accepts analytics cookies
function acceptAnalytics() {
posthog.opt_in_capturing();
}
// User rejects analytics cookies
function rejectAnalytics() {
posthog.opt_out_capturing();
}
// Check current status
const isOptedIn = posthog.has_opted_in_capturing();
Debugging¶
Enable Debug Mode¶
Debug mode is automatically enabled in development. For production debugging:
Common Issues¶
| Issue | Solution |
|---|---|
| No events appearing | Check NEXT_PUBLIC_POSTHOG_KEY is set |
| No events despite key set | Capturing is opt-out by default (opt_out_capturing_by_default: true) — accept analytics cookies first |
| No events on admin pages | Expected: PostHog is deliberately not loaded on admin routes |
| Events delayed | PostHog batches events, wait 1-2 minutes |
| Session recording not working | Check disable_session_recording setting |
| User not identified | Call identifyUser() after login |
Test Event Capture¶
Then check PostHog → Activity → Live Events.
Best Practices¶
- Use semantic event names:
order_completednotclick_buy_button - Include relevant properties: Product ID, value, category
- Don't track PII: No passwords, full credit card numbers
- Use feature flags for rollouts: Gradual feature releases
- Set up alerts: For conversion rate drops
Related Documentation¶
- Monitoring Runbook - Full monitoring stack
- Configuration Guide - Environment setup
- PostHog Official Docs - Full API reference