/template recipe-analytics
Commercial License Required
MakerKit requires a commercial license. While Orchestre can help you build with it, you must obtain a valid license from MakerKit for commercial use.
Access: /template recipe-analytics or /t recipe-analytics
Purpose
Implements a privacy-friendly, multi-provider analytics system that allows you to track user behavior, conversions, and custom events while respecting user privacy and GDPR compliance.
How It Actually Works
The recipe:
- Analyzes your current tracking setup
- Creates an analytics abstraction layer
- Implements provider-specific integrations
- Adds event tracking throughout your app
- Sets up conversion goals and funnels
- Ensures privacy compliance with consent management
Use Cases
- User Behavior Tracking: Page views, sessions, user flows
- Conversion Tracking: Signups, purchases, upgrades
- Feature Analytics: Feature adoption, usage patterns
- Performance Monitoring: Core Web Vitals, load times
- A/B Testing: Experiment tracking and analysis
Examples
Basic Analytics Setup
bash
/template recipe-analytics plausible
# Implements Plausible Analytics with:
# - Server-side tracking
# - Custom events
# - Goal conversions
# - No cookies requiredMulti-Provider Setup
bash
/template recipe-analytics multi posthog plausible
# Creates abstraction layer with:
# - Provider switching capability
# - Unified event API
# - Conditional loading
# - Privacy controlsEnterprise Analytics
bash
/template recipe-analytics enterprise matomo custom-domain
# Sets up self-hosted Matomo with:
# - Custom domain tracking
# - User ID tracking
# - E-commerce analytics
# - Custom dimensionsWhat Gets Created
1. Analytics Configuration
typescript
// packages/analytics/src/config.ts
export const analyticsConfig = {
providers: {
plausible: {
enabled: process.env.NEXT_PUBLIC_PLAUSIBLE_ENABLED === 'true',
domain: process.env.NEXT_PUBLIC_PLAUSIBLE_DOMAIN,
apiHost: process.env.NEXT_PUBLIC_PLAUSIBLE_HOST || 'https://plausible.io'
},
posthog: {
enabled: process.env.NEXT_PUBLIC_POSTHOG_ENABLED === 'true',
apiKey: process.env.NEXT_PUBLIC_POSTHOG_KEY,
apiHost: process.env.NEXT_PUBLIC_POSTHOG_HOST
},
matomo: {
enabled: process.env.NEXT_PUBLIC_MATOMO_ENABLED === 'true',
siteId: process.env.NEXT_PUBLIC_MATOMO_SITE_ID,
url: process.env.NEXT_PUBLIC_MATOMO_URL
}
},
privacy: {
requireConsent: true,
anonymizeIp: true,
respectDoNotTrack: true
}
};2. Analytics Provider
typescript
// packages/analytics/src/provider.tsx
export function AnalyticsProvider({ children }: { children: ReactNode }) {
const [consent, setConsent] = useState<ConsentState>();
useEffect(() => {
if (consent?.analytics) {
initializeAnalytics();
}
}, [consent]);
return (
<AnalyticsContext.Provider value={{ track, identify, page }}>
{children}
<ConsentBanner onConsent={setConsent} />
</AnalyticsContext.Provider>
);
}3. Event Tracking System
typescript
// packages/analytics/src/events.ts
export const events = {
// Authentication events
auth: {
signUp: (method: 'email' | 'google' | 'github') => ({
name: 'sign_up',
properties: { method }
}),
signIn: (method: string) => ({
name: 'sign_in',
properties: { method }
}),
signOut: () => ({ name: 'sign_out' })
},
// Billing events
billing: {
subscriptionStarted: (plan: string, interval: string) => ({
name: 'subscription_started',
properties: { plan, interval }
}),
subscriptionUpgraded: (from: string, to: string) => ({
name: 'subscription_upgraded',
properties: { from_plan: from, to_plan: to }
}),
paymentFailed: (reason: string) => ({
name: 'payment_failed',
properties: { reason }
})
},
// Feature events
feature: {
used: (feature: string, context?: any) => ({
name: 'feature_used',
properties: { feature, ...context }
}),
discovered: (feature: string) => ({
name: 'feature_discovered',
properties: { feature }
})
}
};
// Type-safe event tracking
export function trackEvent<T extends keyof typeof events>(
category: T,
event: keyof typeof events[T],
...args: Parameters<typeof events[T][typeof event]>
) {
const eventData = events[category][event](...args);
return track(eventData.name, eventData.properties);
}4. React Hooks
typescript
// packages/analytics/src/hooks.ts
export function useAnalytics() {
const analytics = useContext(AnalyticsContext);
return {
track: analytics.track,
page: analytics.page,
identify: analytics.identify,
trackEvent // Type-safe wrapper
};
}
export function usePageTracking() {
const { page } = useAnalytics();
const pathname = usePathname();
useEffect(() => {
page(pathname);
}, [pathname, page]);
}
export function useEventTracking(
event: string,
properties?: Record<string, any>
) {
const { track } = useAnalytics();
return useCallback(() => {
track(event, properties);
}, [track, event, properties]);
}5. Server-Side Tracking
typescript
// packages/analytics/src/server.ts
import { PostHog } from 'posthog-node';
import { headers } from 'next/headers';
const posthog = new PostHog(process.env.POSTHOG_API_KEY!);
export async function trackServerEvent(
distinctId: string,
event: string,
properties?: Record<string, any>
) {
const headersList = headers();
const userAgent = headersList.get('user-agent');
const ip = headersList.get('x-forwarded-for');
await posthog.capture({
distinctId,
event,
properties: {
...properties,
$ip: ip,
$user_agent: userAgent
}
});
}
// Usage in server actions
export async function createProject(data: ProjectData) {
const project = await db.projects.create(data);
await trackServerEvent(
data.userId,
'project_created',
{ project_id: project.id }
);
return project;
}6. Conversion Goals
typescript
// packages/analytics/src/goals.ts
export const goals = {
// Onboarding funnel
onboarding: {
started: 'onboarding_started',
profileCompleted: 'onboarding_profile_completed',
teamCreated: 'onboarding_team_created',
firstProjectCreated: 'onboarding_first_project',
completed: 'onboarding_completed'
},
// Revenue goals
revenue: {
trialStarted: 'trial_started',
subscriptionCreated: 'subscription_created',
revenueGenerated: 'revenue_generated'
}
};
// Track conversion funnel
export function trackFunnelStep(
funnel: keyof typeof goals,
step: keyof typeof goals[typeof funnel]
) {
const goalName = goals[funnel][step];
track('goal', { name: goalName });
}Technical Details
Provider Abstraction
typescript
// packages/analytics/src/providers/base.ts
export interface AnalyticsProvider {
initialize(config: ProviderConfig): Promise<void>;
track(event: string, properties?: Record<string, any>): void;
page(path: string, properties?: Record<string, any>): void;
identify(userId: string, traits?: Record<string, any>): void;
reset(): void;
}
// Provider implementations
class PlausibleProvider implements AnalyticsProvider {
async initialize(config) {
// Load Plausible script
}
track(event, properties) {
window.plausible?.(event, { props: properties });
}
page(path) {
window.plausible?.('pageview', { u: path });
}
identify() {
// Plausible doesn't support user identification
}
reset() {
// No-op for Plausible
}
}Privacy Compliance
typescript
// packages/analytics/src/consent.tsx
export function ConsentBanner() {
const [show, setShow] = useState(false);
useEffect(() => {
const consent = getStoredConsent();
if (!consent) {
setShow(true);
}
}, []);
const handleConsent = (choices: ConsentChoices) => {
storeConsent(choices);
if (choices.analytics) {
initializeAnalytics();
}
if (choices.marketing) {
initializeMarketing();
}
setShow(false);
};
if (!show) return null;
return (
<div className="consent-banner">
<h3>Privacy Settings</h3>
<p>We use cookies and similar technologies to:</p>
<ConsentOptions onAccept={handleConsent} />
</div>
);
}Custom Events
typescript
// Track custom business metrics
export function trackBusinessMetric(
metric: string,
value: number,
metadata?: Record<string, any>
) {
track('business_metric', {
metric,
value,
...metadata
});
// Send to monitoring service
if (process.env.NODE_ENV === 'production') {
sendToDatadog(metric, value, metadata);
}
}Memory Evolution
The recipe updates CLAUDE.md:
markdown
## Analytics System
The application uses a multi-provider analytics system:
### Providers
- Plausible: Primary analytics (privacy-friendly)
- PostHog: Product analytics and feature flags
- Custom: Business metrics to Datadog
### Key Events
- Authentication: sign_up, sign_in, sign_out
- Billing: subscription_started, payment_failed
- Features: feature_used, feature_discovered
- Business: mrr_updated, churn_prevented
### Privacy
- GDPR compliant with consent management
- No PII in analytics by default
- IP anonymization enabled
- Respects Do Not Track
### Implementation
- Provider abstraction in packages/analytics
- Server and client-side tracking
- Type-safe event system
- Conversion goal trackingBest Practices
- Privacy First: Always prioritize user privacy
- Meaningful Events: Track actions, not just page views
- Consistent Naming: Use standardized event names
- Avoid PII: Never send personal information
- Test Tracking: Verify events in development
Integration Points
- Authentication: Track signup/signin methods
- Billing: Monitor subscription lifecycle
- Features: Measure adoption and usage
- Performance: Track Core Web Vitals
- Errors: Capture and analyze failures
Common Patterns
Feature Adoption Tracking
typescript
export function FeatureWrapper({ feature, children }) {
const { trackEvent } = useAnalytics();
const [discovered, setDiscovered] = useState(false);
useEffect(() => {
if (!discovered) {
trackEvent('feature', 'discovered', feature);
setDiscovered(true);
}
}, []);
const handleUse = () => {
trackEvent('feature', 'used', feature);
};
return (
<div onMouseDown={handleUse}>
{children}
</div>
);
}Conversion Funnel
typescript
// Track progression through signup
export function SignupFlow() {
const { trackFunnelStep } = useAnalytics();
useEffect(() => {
trackFunnelStep('onboarding', 'started');
}, []);
const handleProfileComplete = () => {
trackFunnelStep('onboarding', 'profileCompleted');
};
// Continue for each step...
}Next Steps
- Choose your analytics providers
- Configure privacy settings
- Define conversion goals
- Set up custom events
- Create analytics dashboards
