6 min read

How to Track Unique Users in PostHog

PostHog counts unique users by distinct_id — but only if you've actually identified them. If you're seeing inflated numbers or struggling to segment by user properties, your identification isn't set up right. Here's how to do it correctly.

Identify Users with posthog.identify()

PostHog needs a consistent identifier for each user to count them as unique. The most common approach is to identify them when they log in or sign up.

Call identify() when a user logs in or signs up

As soon as you know who the user is, call posthog.identify() with their user ID and optional properties. PostHog uses this ID to track that user across sessions and devices.

javascript
// When user logs in or signs up
const userId = user.id; // e.g., "user_12345"
const userProperties = {
  email: user.email,
  name: user.name,
  plan: user.subscription_plan,
  created_at: user.created_at
};

posthog.identify(userId, userProperties);
Identify the user with a stable ID and set properties

Always use the same distinct_id for the same user

PostHog's unique user count is based on distinct IDs. If the same user gets different IDs in different sessions, PostHog counts them as multiple users. Use your database user ID — not session IDs or email addresses (which can change).

javascript
// ❌ Wrong: Using email as distinct_id
posthog.identify(user.email); // Email can change

// ✅ Right: Using stable user ID from your database
posthog.identify(user.id); // Doesn't change
Pick a stable identifier that doesn't change

Pass user properties to enable segmentation

The second argument to identify() should be an object of user properties. These let you segment unique users by plan, country, company, or other attributes in the Insights UI.

javascript
posthog.identify(userId, {
  email: user.email,
  company_id: user.company_id,
  plan: 'professional',
  signup_date: user.created_at,
  is_active: true
});
Properties enable filtering and breakdowns in PostHog insights
Tip: Call identify() once per session, not every time you capture an event. PostHog batches calls automatically, so you won't waste quota.

View Unique Users in Insights

Once users are identified, you can query unique user counts in the Insights tab and break them down by properties, dates, or events.

Create a new insight with the Unique Users metric

Navigate to Insights and click + New insight. In the metric dropdown, select Unique users instead of total events. This counts how many distinct user IDs fired an event in your time range.

javascript
// This is what PostHog does under the hood:
// SELECT count(DISTINCT distinct_id) FROM events WHERE {filters};

// Your JavaScript SDK doesn't need to do anything—
// just make sure you called identify() earlier.
PostHog query equivalent

Segment unique users by properties or events

In the insight builder, click Breakdown by and choose a user property like plan or country. Now you'll see unique user counts for each segment. Use Filter to restrict to specific cohorts or event types.

javascript
// No SDK code needed for this—it's all in the UI.
// But make sure your events are capturing context:

posthog.capture('page_view', {
  page: '/pricing',
  utm_source: 'google',
  user_plan: user.plan
});
Enrich events with context so you can filter in insights

Compare unique users across time ranges

Use the date range picker at the top of the insight to compare unique user counts week-over-week or month-over-month. The Change column shows the percentage difference automatically.

javascript
// SDK-side, ensure you're tracking user activity consistently:

posthog.capture('feature_used', {
  feature: 'export_data',
  export_format: 'csv'
});

// PostHog will aggregate these by day/week/month based on your insight settings.
Consistent event capture enables time-series analysis
Watch out: If you change a user's distinct_id (e.g., after a logout), PostHog will count them as a new user. Use posthog.alias(old_id, new_id) to merge IDs instead.

Debug Unique User Counts

If your unique user count seems off, check that users are actually being identified and events are tagged with the right distinct_id.

Verify identify() is being called

Check your browser console or SDK logs to confirm posthog.identify() is firing when users log in. If it's not being called at all, PostHog will use anonymous IDs (your distinct_id will be a UUID), which inflates your unique count.

javascript
// Add a debug log to confirm identify() is called:
posthog.identify(userId, props);
console.log(`Identified user: ${userId}`);

// Check the PostHog SDK state:
console.log(posthog.getDistinctId()); // Should return your userId, not a UUID
Verify the current distinct_id

Check user properties in the PostHog interface

Go to Data Management > People and search for a specific user. You should see their distinct_id and all properties you set via identify(). If properties are missing or the ID looks like a random string, your identification code isn't running.

javascript
// If your user doesn't appear in PostHog People, check:
if (typeof posthog !== 'undefined') {
  posthog.identify(userId, { email: user.email });
} else {
  console.error('PostHog SDK not loaded');
}
Guard against SDK loading issues
Tip: Use PostHog's Network tab in the browser DevTools to inspect API calls. Search for identify or capture requests and check the distinct_id and properties being sent.

Common Pitfalls

  • Calling identify() with non-stable IDs (like session tokens or email addresses) — your unique count balloons because the same user gets counted multiple times.
  • Not calling identify() at all — PostHog assigns random UUID distinct_ids, making it impossible to link users across devices or sessions.
  • Capturing events before identifying users — events won't be tied to the user unless you call identify() first (or in the same batch).
  • Mixing identified and anonymous events — if part of your traffic identifies users and part doesn't, your unique count will be hard to interpret.

Wrapping Up

Tracking unique users in PostHog boils down to identifying users with a stable ID, attaching user properties for segmentation, and checking the Unique users metric in Insights. If your counts seem off, make sure identify() is being called and you're using the same ID consistently. If you want to track this automatically across tools, Product Analyst can help.

Track these metrics automatically

Product Analyst connects to your stack and surfaces the insights that matter.

Try Product Analyst — Free