As a developer, I’ve always had a love-hate relationship with analytics. Most tools feel like they were built for marketing teams—lots of pretty charts, but very little technical granularity. When I first started looking for a way to track exactly how users interact with my features without spending hours in a dashboard, I found PostHog. This posthog tutorial for developers is designed to get you from zero to a fully instrumented application using the tools we actually use daily.

PostHog isn’t just an analytics tool; it’s a product OS. It combines event tracking, session recording, feature flags, and A/B testing into one platform. If you’re debating between different options, you might find my PostHog vs Amplitude comparison useful, but for most indie hackers and small engineering teams, PostHog’s all-in-one approach is a game changer.

Prerequisites

Before we dive into the code, make sure you have the following ready:

Step 1: Initializing PostHog in Your Project

The first step is getting the snippet into your app. While you can use the JS snippet in your HTML head, I prefer the posthog-js library for better type safety and control in modern frameworks.

npm install posthog-js

Now, create a PostHog initialization file (e.g., lib/posthog.ts) to ensure the client is a singleton across your app:

import posthog from 'posthog-js';

export const ph = posthog.init('<YOUR_PROJECT_API_KEY>', {
  api_host: 'https://us.i.posthog.com',
  person_profiles: 'identified_only',
  capture_pageview: false // We'll handle this manually for SPAs
});

In my experience, setting capture_pageview: false is critical for Next.js or React apps to avoid duplicate page views during client-side routing.

Step 2: Tracking Custom Events

Page views are great, but they don’t tell you how a user is using your tool. The core of any posthog tutorial for developers is mastering custom events. Instead of generic clicks, track intent-based actions.

For example, if you have a ‘Export PDF’ button, don’t just track a click; track the export event with properties:

const handleExport = (fileType) => {
  ph.capture('document_exported', {
    format: fileType,
    page_url: window.location.pathname,
    is_premium_user: user.plan === 'pro'
  });
  // ... rest of your export logic
};

As shown in the image below, these events will appear in real-time in your Live Event stream, allowing you to verify your implementation immediately.

PostHog Live Event stream showing real-time custom event capture
PostHog Live Event stream showing real-time custom event capture

Step 3: Identifying Users

By default, PostHog assigns a random UUID to every visitor. To link these events to a real user in your database, you need to identify them after they log in.

// Call this immediately after a successful login or signup
ph.identify(
  'user_id_12345',
  {
    email: 'dev@example.com',
    name: 'Jane Developer',
    plan: 'Enterprise'
  }
);

Once identified, you can create cohorts based on these properties, such as “Users on the Enterprise plan who haven’t exported a document in 7 days.”

Step 4: Implementing Feature Flags

This is where PostHog moves from “analytics” to “development tool.” Feature flags allow you to merge code to production but keep the feature hidden until you’re ready.

if (ph.isFeatureEnabled('new-dashboard-v2')) {
  return <NewDashboard />
} 

return <OldDashboard />

I’ve found that using feature flags drastically reduces my deployment anxiety. You can roll out a feature to 10% of users, monitor the event logs for errors, and then scale to 100%.

Pro Tips for Developer Instrumentation

Troubleshooting Common Issues

Events not showing up? First, check your AdBlocker. Most blockers stop PostHog by default. To fix this in production, you should proxy PostHog through your own domain.

Duplicate Events? This usually happens in React’s StrictMode where components mount twice. Ensure your posthog.init is outside the component lifecycle or wrapped in a check.

What’s Next?

Now that you have the basics down, I recommend exploring Session Replays. It’s like having a DVR for your app; you can watch exactly where a user got stuck before they dropped off. If you’re looking to scale your infrastructure, check out my guide on self-hosted analytics platforms for developers to see if hosting your own instance makes sense for your privacy requirements.