6 min read

How to Visualize Session Duration in PostHog

If you're trying to understand how long users spend in your app, session duration is one of the most telling metrics. PostHog tracks this automatically, but actually *seeing* the data requires knowing where to look—and how to ask the right questions.

Set up session tracking

PostHog's JavaScript SDK captures session duration automatically, but you need to initialize it first.

Initialize PostHog in your app

Install the PostHog SDK and initialize it with your project key. PostHog will automatically track session properties, including $session_duration (in seconds).

javascript
import posthog from 'posthog-js';

posthog.init('your-project-key', {
  api_host: 'https://us.posthog.com',
  capture_pageview: true,
  session_recording: {
    maskAllInputs: true,
  },
});

// Session duration is now tracked automatically
posthog.capture('user_action', {
  custom_property: 'value',
  // $session_duration will be included automatically
});
PostHog SDK initialization with automatic session tracking

Verify session properties are captured

Open the PostHog dashboard and navigate to Live Events to confirm that $session_duration is being tracked. You should see this property in the event list within a few seconds.

javascript
// Check the current session ID
console.log(posthog.get_session_id());

// Verify session properties are present
console.log(posthog.getProperties());
// Output includes $session_duration in seconds

// Custom event with session duration auto-included
posthog.capture('page_viewed', {
  page_title: 'Dashboard',
});
Verify PostHog is tracking your session
Watch out: Session duration only counts *active* time—if a user is idle, the timer pauses. Ensure you're capturing events frequently enough to see meaningful session data.

Create a session duration insight

Once session tracking is working, visualize the data in Insights using aggregations and filters.

Navigate to Insights and add a new query

Go to Insights > + New insight in PostHog. Choose Trends to see session duration over time, or Funnels to analyze duration within a specific user journey.

javascript
// Query session events via the PostHog API
const query = {
  kind: 'EventsQuery',
  select: ['properties.$session_duration', 'timestamp'],
  where: [
    'timestamp > now() - interval 7 day',
    'properties.$session_duration is not null',
  ],
  orderBy: ['timestamp DESC'],
  limit: 1000,
};

const response = await fetch('https://us.posthog.com/api/insights/query/', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.POSTHOG_API_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(query),
});

const data = await response.json();
console.log('Session duration data:', data);
Query session duration events via PostHog API

Add filters for session duration ranges

In the Filters section, add $session_duration with a condition (e.g., greater than 60 seconds). This isolates engaged users from those who bounced immediately.

javascript
// Filter for sessions longer than 60 seconds
const filteredQuery = {
  events: [
    {
      id: 'pageview',  // or your custom event
      properties: [
        {
          key: '$session_duration',
          value: 60,
          operator: 'gt',  // greater than
          type: 'number',
        },
      ],
    },
  ],
};

// Add a breakdown by browser or user property
const withBreakdown = {
  ...filteredQuery,
  breakdownBy: 'properties',
  breakdownProperties: ['$browser', '$country'],
};

console.log('Analyzing sessions > 60s by browser:', withBreakdown);
Filter and segment session duration by user properties

Export data for deeper analysis

Click Export to download your results as CSV, or use the PostHog API to fetch raw events programmatically. This is useful if you want to analyze session patterns in your own tools.

javascript
// Fetch raw session events for custom analysis
async function analyzeSessionDuration() {
  const response = await fetch(
    'https://us.posthog.com/api/events/?limit=1000&orderBy=-timestamp',
    {
      headers: {
        'Authorization': `Bearer ${process.env.POSTHOG_API_TOKEN}`,
      },
    }
  );

  const events = await response.json();
  
  // Calculate percentiles
  const durations = events.results
    .map(e => e.properties.$session_duration)
    .filter(Boolean)
    .sort((a, b) => a - b);
  
  const p50 = durations[Math.floor(durations.length * 0.5)];
  const p95 = durations[Math.floor(durations.length * 0.95)];
  
  console.log(`P50: ${p50}s, P95: ${p95}s`);
}
Fetch and analyze session duration percentiles
Tip: Use Trends to spot seasonality (e.g., "users engage longer on weekends"), or Retention to see if engaged users (high session duration) return more often.

Monitor with a dashboard

Save your session insights to a dashboard for ongoing monitoring without rebuilding queries.

Save your insight to a dashboard

Click Save on your session duration insight and choose an existing dashboard or create a new one. Name it "Session Metrics" or "User Engagement" for easy reference.

javascript
// Create a dashboard via the PostHog API
const dashboardPayload = {
  name: 'Session Metrics Dashboard',
  description: 'Monitor session duration trends and cohort engagement',
};

const dashResponse = await fetch('https://us.posthog.com/api/dashboards/', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.POSTHOG_API_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(dashboardPayload),
});

const dashboard = await dashResponse.json();
console.log('Dashboard created:', dashboard.id);
Create a new dashboard for session insights

Add multiple session views to the dashboard

Add tiles showing average session duration over time, session duration by cohort, and bounce rate (sessions under 10 seconds). This gives you a complete picture of user engagement.

javascript
// Add insights to dashboard via API
const insightPayload = {
  name: 'Avg Session Duration',
  filters: {
    events: [
      {
        id: 'pageview',
        properties: [
          {
            key: '$session_duration',
            value: 0,
            operator: 'gt',
          },
        ],
      },
    ],
  },
  display: 'line',  // Time series
};

const insightResponse = await fetch('https://us.posthog.com/api/insights/', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.POSTHOG_API_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(insightPayload),
});

const insight = await insightResponse.json();
console.log('Insight added to dashboard:', insight.id);
Add session duration insights to your dashboard

Common Pitfalls

  • Session duration only includes *active* time—idle periods don't count. If users leave the app open without interacting, the timer doesn't advance.
  • Sessions reset on page refresh or after 30 minutes of inactivity (default PostHog setting). Monitor this separately if session continuity matters for your analysis.
  • New or bounced users have zero or near-zero session duration. Always filter by $session_duration > 0 to exclude these cases from engagement analysis.
  • Events captured outside the PostHog SDK (e.g., via API or third-party tools) won't include $session_duration automatically. Ensure all events come from the SDK for consistent data.

Wrapping Up

Session duration reveals whether users are *actually* engaging with your product, not just visiting. With PostHog's built-in tracking and dashboard tools, you can spot trends, identify your most committed users, and catch engagement drops before they become problems. 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