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).
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
});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.
// 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',
});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.
// 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);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.
// 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);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.
// 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`);
}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.
// 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);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.
// 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);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 > 0to exclude these cases from engagement analysis. - Events captured outside the PostHog SDK (e.g., via API or third-party tools) won't include
$session_durationautomatically. 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.