How to Implement Product Analytics in 30 Minutes: Step-by-Step Guide
Complete step-by-step tutorial for implementing product analytics in your app or website. Learn event tracking, user identification, and funnel analysis setup with code examples.
How to Implement Product Analytics in 30 Minutes
Product analytics is essential for understanding user behavior and making data-driven product decisions. This guide walks you through implementing analytics from scratch, regardless of which tool you choose.
##Table of Contents
- Prerequisites
- Step 1: Choose Your Analytics Platform
- Step 2: Install the SDK
- Step 3: Identify Users
- Step 4: Track Events
- Step 5: Set Up Funnels
- Step 6: Verify Implementation
- Common Mistakes to Avoid
Prerequisites
Before you begin, ensure you have:
- Access to your application's codebase
- Admin access to create analytics accounts
- Basic understanding of JavaScript (for web) or relevant SDK language
- 30 minutes of uninterrupted time
Skill Level: Beginner to Intermediate Time Required: 30 minutes Tools Needed: Code editor, terminal, web browser
Step 1: Choose Your Analytics Platform
Decision Criteria
Consider these factors:
- Budget: Free tier vs. paid plans
- Features: Session replay, A/B testing, funnel analysis
- Privacy: GDPR compliance, data residency
- Integration: SDK support for your tech stack
Recommended Platforms
| Platform | Best For | Free Tier |
|---|---|---|
| PostHog | All-in-one, privacy-focused | 1M events/month |
| Mixpanel | Event tracking, ease of use | 100K MTU |
| Amplitude | Enterprise, advanced analytics | 10M actions/month |
| Google Analytics 4 | Web analytics, beginners | Unlimited (with limits) |
For this tutorial, we'll use PostHog as an example, but the concepts apply to any platform.
Step 2: Install the SDK
For Web Applications (React/Next.js)
Option A: Using NPM/Yarn
npm install posthog-js
# or
yarn add posthog-js
Option B: Using CDN (HTML)
<script>
!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
posthog.init('YOUR_PROJECT_API_KEY',{api_host:'https://app.posthog.com'})
</script>
Initialize in Your App
React/Next.js Example:
// lib/analytics.js
import posthog from 'posthog-js'
export const initAnalytics = () => {
if (typeof window !== 'undefined') {
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY, {
api_host: 'https://app.posthog.com',
// Enable session recordings
capture_pageview: true,
capture_pageleave: true,
// Privacy settings
respect_dnt: true,
persistence: 'localStorage',
})
}
}
export default posthog
Initialize on App Load:
// pages/_app.js (Next.js) or App.js (React)
import { useEffect } from 'react'
import { initAnalytics } from '../lib/analytics'
function MyApp({ Component, pageProps }) {
useEffect(() => {
initAnalytics()
}, [])
return <Component {...pageProps} />
}
For Mobile Apps
iOS (Swift):
import PostHog
PostHogSDK.shared.setup(PostHogConfig(
apiKey: "YOUR_API_KEY",
host: "https://app.posthog.com"
))
Android (Kotlin):
import com.posthog.android.PostHog
PostHog.setup(
this,
"YOUR_API_KEY",
"https://app.posthog.com"
)
Step 3: Identify Users
User identification connects events to specific users across sessions and devices.
When to Identify Users
- After signup/login: Immediately when user authenticates
- On session start: If user is already logged in
- After profile updates: When user information changes
Implementation
import posthog from './lib/analytics'
// Basic identification
export const identifyUser = (userId, userProperties = {}) => {
posthog.identify(userId, {
email: userProperties.email,
name: userProperties.name,
plan: userProperties.subscriptionPlan,
createdAt: userProperties.createdAt,
// Add custom properties relevant to your product
})
}
// Usage after login
const handleLogin = async (credentials) => {
const user = await loginUser(credentials)
// Identify user in analytics
identifyUser(user.id, {
email: user.email,
name: user.name,
plan: user.subscription?.plan || 'free',
createdAt: user.createdAt,
})
}
Group Analytics (B2B Products)
For B2B products, track both users and organizations:
// Identify the organization/company
posthog.group('company', companyId, {
name: 'Acme Corp',
plan: 'enterprise',
employees: 500,
industry: 'Technology',
})
// Then identify the user
posthog.identify(userId, {
email: 'john@acme.com',
role: 'admin',
})
Step 4: Track Events
Events are the core of product analytics. Track user actions to understand behavior.
Event Naming Conventions
Follow this structure: Object + Action
Good Examples:
button_clickedfeature_enabledsignup_completedcheckout_startedvideo_played
Avoid:
click(too vague)button1(not descriptive)user did something(inconsistent naming)
Basic Event Tracking
import posthog from './lib/analytics'
// Track a simple event
export const trackEvent = (eventName, properties = {}) => {
posthog.capture(eventName, properties)
}
// Usage examples
trackEvent('signup_completed', {
method: 'email',
referrer: 'google',
})
trackEvent('feature_used', {
feature_name: 'dark_mode',
enabled: true,
})
trackEvent('purchase_completed', {
product_id: 'pro-plan',
amount: 99,
currency: 'USD',
})
Automatic Event Tracking
Most platforms support autocapture for clicks and page views:
// PostHog autocapture (enabled by default)
posthog.init('YOUR_KEY', {
autocapture: true, // Tracks all clicks automatically
capture_pageview: true, // Tracks page views
})
// Disable autocapture for specific elements
<button data-ph-capture-attribute-disabled>
Don't Track This Button
</button>
Page View Tracking
For Single Page Apps (SPA):
// Next.js example using useEffect
import { useEffect } from 'react'
import { useRouter } from 'next/router'
import posthog from './lib/analytics'
export function usePageTracking() {
const router = useRouter()
useEffect(() => {
const handleRouteChange = () => {
posthog.capture('$pageview')
}
router.events.on('routeChangeComplete', handleRouteChange)
return () => {
router.events.off('routeChangeComplete', handleRouteChange)
}
}, [router.events])
}
Track Custom Events
// Track with context
export const trackWithContext = (eventName, additionalProps = {}) => {
posthog.capture(eventName, {
// Automatic context
$current_url: window.location.href,
$referrer: document.referrer,
// Custom properties
...additionalProps,
})
}
// Usage in components
const FeatureCard = ({ feature }) => {
const handleFeatureClick = () => {
trackWithContext('feature_card_clicked', {
feature_id: feature.id,
feature_name: feature.name,
card_position: feature.position,
})
}
return (
<div onClick={handleFeatureClick}>
{feature.name}
</div>
)
}
Step 5: Set Up Funnels
Funnels track user progression through key workflows.
Define Your Funnels
Common product funnels:
Signup Funnel
- Landing page viewed
- Signup form opened
- Email entered
- Email verified
- Profile completed
Activation Funnel
- Account created
- First project created
- First feature used
- Invited team member
Purchase Funnel
- Pricing page viewed
- Checkout started
- Payment information entered
- Purchase completed
Implement Funnel Tracking
// Track signup funnel
export const trackSignupFunnel = {
viewLanding: () => {
trackEvent('signup_funnel_step_1_landing_viewed')
},
openForm: () => {
trackEvent('signup_funnel_step_2_form_opened')
},
enterEmail: (email) => {
trackEvent('signup_funnel_step_3_email_entered', {
email_domain: email.split('@')[1],
})
},
verifyEmail: () => {
trackEvent('signup_funnel_step_4_email_verified')
},
completeProfile: (profileData) => {
trackEvent('signup_funnel_step_5_profile_completed', {
has_company: !!profileData.company,
has_role: !!profileData.role,
})
},
}
// Usage in signup flow
const SignupFlow = () => {
useEffect(() => {
trackSignupFunnel.viewLanding()
}, [])
const handleEmailSubmit = (email) => {
trackSignupFunnel.enterEmail(email)
// ... rest of logic
}
return (/* ... */)
}
Create Funnel in Dashboard
In PostHog:
- Go to "Insights" → "New Insight" → "Funnel"
- Add steps in order:
- Step 1:
signup_funnel_step_1_landing_viewed - Step 2:
signup_funnel_step_2_form_opened - Step 3:
signup_funnel_step_3_email_entered - Step 4:
signup_funnel_step_4_email_verified - Step 5:
signup_funnel_step_5_profile_completed
- Step 1:
- Set time window (e.g., 7 days)
- Add filters if needed (e.g., by traffic source)
Step 6: Verify Implementation
Testing Checklist
1. Check Events Are Firing
// Enable debug mode during development
posthog.init('YOUR_KEY', {
debug: true, // Logs all events to console
api_host: 'https://app.posthog.com',
})
2. Verify in Dashboard
- Open your analytics dashboard
- Go to "Live Events" or "Recent Activity"
- Perform actions in your app
- Confirm events appear within 1-2 minutes
3. Check User Properties
- Trigger an identify call
- Look up your test user in the dashboard
- Verify all properties are correctly set
4. Test Funnel Tracking
- Complete a funnel workflow
- Wait 5-10 minutes for processing
- Check funnel completion rates
Common Issues & Fixes
| Problem | Solution |
|---|---|
| Events not appearing | Check API key, ensure init() called before events |
| User not identified | Call identify() after authentication |
| Properties missing | Verify property names match, check for undefined values |
| Duplicate events | Remove multiple init() calls, prevent double-tracking |
Development vs. Production
const isProduction = process.env.NODE_ENV === 'production'
posthog.init('YOUR_KEY', {
api_host: 'https://app.posthog.com',
debug: !isProduction, // Debug only in development
autocapture: isProduction, // Autocapture only in production
// Use separate project for development/production
opt_out_capturing_by_default: !isProduction,
})
Common Mistakes to Avoid
1. ❌ Tracking Too Many Events
Problem: Tracking every click creates noise
// Bad: Too granular
trackEvent('mouse_moved')
trackEvent('scrolled_5px')
trackEvent('hovered_over_button')
Solution: Track meaningful user actions
// Good: Meaningful events
trackEvent('important_feature_used')
trackEvent('purchase_completed')
trackEvent('signup_started')
2. ❌ Inconsistent Event Naming
Problem: Different naming conventions
// Bad: Inconsistent
trackEvent('UserSignedUp')
trackEvent('button-clicked')
trackEvent('feature used')
Solution: Use consistent snake_case
// Good: Consistent naming
trackEvent('user_signed_up')
trackEvent('button_clicked')
trackEvent('feature_used')
3. ❌ Not Using Super Properties
Problem: Repeating the same properties
// Bad: Repetitive
trackEvent('page_viewed', { plan: 'pro', userId: '123' })
trackEvent('feature_used', { plan: 'pro', userId: '123' })
trackEvent('button_clicked', { plan: 'pro', userId: '123' })
Solution: Set super properties once
// Good: Set once, applied to all events
posthog.register({
plan: 'pro',
user_id: '123',
})
trackEvent('page_viewed')
trackEvent('feature_used')
trackEvent('button_clicked')
4. ❌ Ignoring Privacy Regulations
Problem: Not respecting user consent
// Bad: Always track
posthog.init('YOUR_KEY')
trackEvent('page_viewed')
Solution: Check for consent
// Good: Respect user preferences
const userConsent = getCookieConsent()
if (userConsent.analytics) {
posthog.init('YOUR_KEY')
trackEvent('page_viewed')
} else {
posthog.opt_out_capturing()
}
5. ❌ Not Tracking Errors
Problem: Missing error tracking
Solution: Track error events
// Track errors for debugging
const trackError = (error, context = {}) => {
posthog.capture('error_occurred', {
error_message: error.message,
error_stack: error.stack,
...context,
})
// Also send to error tracking (Sentry, etc.)
console.error(error)
}
try {
await riskyOperation()
} catch (error) {
trackError(error, {
operation: 'user_signup',
step: 'email_verification',
})
}
Next Steps
1. Set Up Dashboards
Create dashboards for key metrics:
- User growth (daily/weekly/monthly)
- Feature adoption rates
- Funnel conversion rates
- Retention cohorts
2. Configure Alerts
Set up alerts for:
- Sudden drops in signups
- Funnel conversion below threshold
- High error rates
- Unusual traffic patterns
3. Team Training
- Share analytics access with team
- Document event taxonomy
- Create runbooks for common analyses
4. Iterate
- Review analytics weekly
- Identify friction points in funnels
- A/B test improvements
- Refine tracking as product evolves
Conclusion
You've now implemented a complete product analytics solution! Remember:
✅ Choose the right platform for your needs ✅ Identify users properly for accurate tracking ✅ Track meaningful events consistently ✅ Set up funnels for key workflows ✅ Verify implementation before launch ✅ Respect user privacy and consent
Analytics is an ongoing process—continue refining your tracking as your product grows.
Resources
- PostHog Documentation
- Mixpanel Implementation Guide
- Amplitude SDK Reference
- Event Naming Best Practices
Last updated: November 2025
Related Tools Mentioned
Free plan for up to 10 million actions/month; Contact for Enterprise pricing
Best for Companies seeking deep insights into user behavior with an intuitive interface
Free plan available; Growth plan from $24/month; Enterprise pricing on request
Best for Teams looking for detailed user action tracking across platforms
Free for first 1 million events; Cloud hosted from $450/month
Best for Teams looking for an open-source analytics solution
Related Guides
Continue learning with these related articles and tutorials


