Skip to content

Commit 54c66dc

Browse files
committed
accurate stats
1 parent b2ef887 commit 54c66dc

File tree

9 files changed

+53
-52
lines changed

9 files changed

+53
-52
lines changed

apps/api/src/query/builders/sessions.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ export const SessionsBuilders: Record<string, SimpleQueryConfig> = {
66
table: Analytics.events,
77
fields: [
88
"COUNT(DISTINCT session_id) as total_sessions",
9-
"AVG(CASE WHEN time_on_page > 0 THEN time_on_page / 1000 ELSE NULL END) as avg_session_duration",
10-
"AVG(CASE WHEN is_bounce = 1 THEN 100 ELSE 0 END) as bounce_rate",
9+
"median(CASE WHEN time_on_page > 0 THEN time_on_page / 1000 ELSE NULL END) as median_session_duration",
1110
"COUNT(*) as total_events",
1211
],
1312
where: ["event_name = 'screen_view'"],
@@ -19,13 +18,13 @@ export const SessionsBuilders: Record<string, SimpleQueryConfig> = {
1918
table: Analytics.events,
2019
fields: [
2120
"CASE " +
22-
"WHEN time_on_page < 30 THEN '0-30s' " +
23-
"WHEN time_on_page < 60 THEN '30s-1m' " +
24-
"WHEN time_on_page < 300 THEN '1m-5m' " +
25-
"WHEN time_on_page < 900 THEN '5m-15m' " +
26-
"WHEN time_on_page < 3600 THEN '15m-1h' " +
27-
"ELSE '1h+' " +
28-
"END as duration_range",
21+
"WHEN time_on_page < 30 THEN '0-30s' " +
22+
"WHEN time_on_page < 60 THEN '30s-1m' " +
23+
"WHEN time_on_page < 300 THEN '1m-5m' " +
24+
"WHEN time_on_page < 900 THEN '5m-15m' " +
25+
"WHEN time_on_page < 3600 THEN '15m-1h' " +
26+
"ELSE '1h+' " +
27+
"END as duration_range",
2928
"COUNT(DISTINCT session_id) as sessions",
3029
"COUNT(DISTINCT anonymous_id) as visitors",
3130
],
@@ -42,7 +41,7 @@ export const SessionsBuilders: Record<string, SimpleQueryConfig> = {
4241
"device_type as name",
4342
"COUNT(DISTINCT session_id) as sessions",
4443
"COUNT(DISTINCT anonymous_id) as visitors",
45-
"ROUND(AVG(CASE WHEN time_on_page > 0 THEN time_on_page / 1000 ELSE NULL END), 2) as avg_session_duration",
44+
"ROUND(median(CASE WHEN time_on_page > 0 THEN time_on_page / 1000 ELSE NULL END), 2) as median_session_duration",
4645
],
4746
where: ["event_name = 'screen_view'", "device_type != ''"],
4847
groupBy: ["device_type"],
@@ -57,7 +56,7 @@ export const SessionsBuilders: Record<string, SimpleQueryConfig> = {
5756
"browser_name as name",
5857
"COUNT(DISTINCT session_id) as sessions",
5958
"COUNT(DISTINCT anonymous_id) as visitors",
60-
"ROUND(AVG(CASE WHEN time_on_page > 0 THEN time_on_page / 1000 ELSE NULL END), 2) as avg_session_duration",
59+
"ROUND(median(CASE WHEN time_on_page > 0 THEN time_on_page / 1000 ELSE NULL END), 2) as median_session_duration",
6160
],
6261
where: ["event_name = 'screen_view'", "browser_name != ''"],
6362
groupBy: ["browser_name"],
@@ -73,7 +72,7 @@ export const SessionsBuilders: Record<string, SimpleQueryConfig> = {
7372
"toDate(time) as date",
7473
"COUNT(DISTINCT session_id) as sessions",
7574
"COUNT(DISTINCT anonymous_id) as visitors",
76-
"ROUND(AVG(CASE WHEN time_on_page > 0 THEN time_on_page / 1000 ELSE NULL END), 2) as avg_session_duration",
75+
"ROUND(median(CASE WHEN time_on_page > 0 THEN time_on_page / 1000 ELSE NULL END), 2) as median_session_duration",
7776
],
7877
where: ["event_name = 'screen_view'"],
7978
groupBy: ["toDate(time)"],

apps/api/src/query/builders/summary.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ export const SummaryBuilders: Record<string, SimpleQueryConfig> = {
3232
name: "bounce_rate",
3333
type: "number",
3434
label: "Bounce Rate",
35-
description: "Percentage of single-page sessions",
35+
description: "Percentage of non-engaged sessions (single pageview, < 10s duration, no interactions)",
3636
unit: "%",
3737
},
3838
{
39-
name: "avg_session_duration",
39+
name: "median_session_duration",
4040
type: "number",
41-
label: "Avg Session Duration",
42-
description: "Average session duration in seconds",
41+
label: "Median Session Duration",
42+
description: "Median session duration in seconds",
4343
unit: "seconds",
4444
},
4545
{
@@ -108,6 +108,7 @@ export const SummaryBuilders: Record<string, SimpleQueryConfig> = {
108108
session_agg AS (
109109
SELECT session_id,
110110
countIf(event_name = 'screen_view') as page_count,
111+
countIf(event_name != 'screen_view') as engagement_count,
111112
dateDiff('second', min(normalized_time), max(normalized_time)) as duration
112113
FROM base_events
113114
GROUP BY session_id
@@ -118,9 +119,9 @@ export const SummaryBuilders: Record<string, SimpleQueryConfig> = {
118119
uniq(if(event_name = 'screen_view', anonymous_id, null)) as unique_visitors
119120
FROM base_events
120121
)
121-
SELECT ea.pageviews, ea.unique_visitors, count() as sessions,
122-
round(countIf(sa.page_count = 1) * 100.0 / nullIf(count(), 0), 2) as bounce_rate,
123-
round(medianIf(sa.duration, sa.duration >= 0), 2) as avg_session_duration,
122+
SELECT ea.pageviews, ea.unique_visitors, countIf(sa.page_count >= 1) as sessions,
123+
round(countIf(sa.page_count = 1 AND sa.duration < 10 AND sa.engagement_count = 0) * 100.0 / nullIf(countIf(sa.page_count >= 1), 0), 2) as bounce_rate,
124+
round(medianIf(sa.duration, sa.page_count >= 1 AND sa.duration >= 0), 2) as median_session_duration,
124125
ea.total_events
125126
FROM session_agg sa
126127
CROSS JOIN event_agg ea
@@ -217,14 +218,14 @@ export const SummaryBuilders: Record<string, SimpleQueryConfig> = {
217218
name: "bounce_rate",
218219
type: "number",
219220
label: "Bounce Rate",
220-
description: "Bounce rate for the period",
221+
description: "Percentage of non-engaged sessions (single pageview, < 10s duration, no interactions)",
221222
unit: "%",
222223
},
223224
{
224-
name: "avg_session_duration",
225+
name: "median_session_duration",
225226
type: "number",
226-
label: "Avg Session Duration",
227-
description: "Average session duration",
227+
label: "Median Session Duration",
228+
description: "Median session duration in seconds",
228229
unit: "seconds",
229230
},
230231
{
@@ -296,8 +297,9 @@ export const SummaryBuilders: Record<string, SimpleQueryConfig> = {
296297
${baseEventsQuery}
297298
session_agg AS (
298299
SELECT session_id,
299-
${timeBucketFn}(min(normalized_time)) as time_bucket,
300+
${timeBucketFn}(minIf(normalized_time, event_name = 'screen_view')) as time_bucket,
300301
countIf(event_name = 'screen_view') as page_count,
302+
countIf(event_name != 'screen_view') as engagement_count,
301303
dateDiff('second', min(normalized_time), max(normalized_time)) as duration
302304
FROM base_events
303305
GROUP BY session_id
@@ -311,8 +313,8 @@ export const SummaryBuilders: Record<string, SimpleQueryConfig> = {
311313
)
312314
SELECT ${dateFormat} as date, ea.pageviews, ea.visitors,
313315
count(sa.session_id) as sessions,
314-
round(countIf(sa.page_count = 1) * 100.0 / nullIf(count(sa.session_id), 0), 2) as bounce_rate,
315-
round(medianIf(sa.duration, sa.duration >= 0), 2) as avg_session_duration,
316+
round(countIf(sa.page_count = 1 AND sa.duration < 10 AND sa.engagement_count = 0) * 100.0 / nullIf(count(sa.session_id), 0), 2) as bounce_rate,
317+
round(medianIf(sa.duration, sa.duration >= 0), 2) as median_session_duration,
316318
round(ea.pageviews * 1.0 / nullIf(count(sa.session_id), 0), 2) as pages_per_session
317319
FROM event_agg ea
318320
LEFT JOIN session_agg sa ON ea.time_bucket = sa.time_bucket

apps/dashboard/app/(main)/websites/[id]/_components/tabs/overview-tab.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ type ChartDataPoint = {
5353
visitors?: number;
5454
sessions?: number;
5555
bounce_rate?: number;
56-
avg_session_duration?: number;
56+
median_session_duration?: number;
5757
[key: string]: unknown;
5858
};
5959

@@ -369,7 +369,7 @@ export function WebsiteOverviewTab({
369369
unique_visitors: 0,
370370
sessions: 0,
371371
bounce_rate: 0,
372-
avg_session_duration: 0,
372+
median_session_duration: 0,
373373
pages_per_session: 0,
374374
}
375375
);
@@ -390,7 +390,7 @@ export function WebsiteOverviewTab({
390390
unique_visitors: 0,
391391
sessions: 0,
392392
bounce_rate: 0,
393-
avg_session_duration: 0,
393+
median_session_duration: 0,
394394
pages_per_session: 0,
395395
}
396396
);
@@ -428,9 +428,9 @@ export function WebsiteOverviewTab({
428428
...(visibleMetrics.bounce_rate && {
429429
bounce_rate: event.bounce_rate as number,
430430
}),
431-
...(visibleMetrics.avg_session_duration && {
432-
avg_session_duration: event.avg_session_duration as number,
433-
}),
431+
...(visibleMetrics.median_session_duration && {
432+
median_session_duration: event.median_session_duration as number,
433+
}),
434434
})
435435
),
436436
[processedEventsData, dateRange.granularity, visibleMetrics]
@@ -467,7 +467,7 @@ export function WebsiteOverviewTab({
467467
pagesPerSession: createChartSeries("pages_per_session"),
468468
bounceRate: createChartSeries("bounce_rate"),
469469
sessionDuration: createChartSeries(
470-
"avg_session_duration",
470+
"median_session_duration",
471471
formatSessionDuration
472472
),
473473
};
@@ -676,7 +676,7 @@ export function WebsiteOverviewTab({
676676
sessions: currentSummary.sessions || 0,
677677
pageviews: currentSummary.pageviews || 0,
678678
bounceRate: currentSummary.bounce_rate || 0,
679-
sessionDuration: currentSummary.avg_session_duration || 0,
679+
sessionDuration: currentSummary.median_session_duration || 0,
680680
pagesPerSession: 0,
681681
};
682682
currentMetrics.pagesPerSession =
@@ -689,7 +689,7 @@ export function WebsiteOverviewTab({
689689
sessions: previousSummary.sessions || 0,
690690
pageviews: previousSummary.pageviews || 0,
691691
bounceRate: previousSummary.bounce_rate || 0,
692-
sessionDuration: previousSummary.avg_session_duration || 0,
692+
sessionDuration: previousSummary.median_session_duration || 0,
693693
pagesPerSession: 0,
694694
};
695695
previousMetrics.pagesPerSession =
@@ -840,9 +840,9 @@ export function WebsiteOverviewTab({
840840
},
841841
{
842842
id: "session-duration-chart",
843-
title: "Avg Duration",
843+
title: "Median Duration",
844844
value: (() => {
845-
const duration = analytics.summary?.avg_session_duration;
845+
const duration = analytics.summary?.median_session_duration;
846846
if (!duration) {
847847
return "0s";
848848
}

apps/dashboard/components/charts/metrics-chart.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ const DEFAULT_METRICS = [
163163
"visitors",
164164
"sessions",
165165
"bounce_rate",
166-
"avg_session_duration",
166+
"median_session_duration",
167167
];
168168

169169
export function MetricsChart({

apps/dashboard/components/charts/metrics-constants.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ export type ChartDataRow = {
137137
unique_visitors?: number;
138138
sessions?: number;
139139
bounce_rate?: number;
140-
avg_session_duration?: number;
141-
avg_session_duration_formatted?: string;
140+
median_session_duration?: number;
141+
median_session_duration_formatted?: string;
142142
// Load time metrics
143143
avg_load_time?: number;
144144
p50_load_time?: number;
@@ -227,13 +227,13 @@ export const ANALYTICS_METRICS: MetricConfig[] = [
227227
(value) => `${value.toFixed(1)}%`
228228
),
229229
createMetric(
230-
"avg_session_duration",
230+
"median_session_duration",
231231
"Session Duration",
232232
"session_duration",
233233
TrendingUp,
234234
(value, row) =>
235-
typeof row.avg_session_duration_formatted === "string"
236-
? row.avg_session_duration_formatted
235+
typeof row.median_session_duration_formatted === "string"
236+
? row.median_session_duration_formatted
237237
: formatDuration(value)
238238
),
239239
];

apps/dashboard/stores/jotai/chartAtoms.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ export interface MetricVisibilityState {
66
visitors: boolean;
77
sessions: boolean;
88
bounce_rate: boolean;
9-
avg_session_duration: boolean;
9+
median_session_duration: boolean;
1010
}
1111

1212
const defaultVisibleMetrics: MetricVisibilityState = {
1313
pageviews: true,
1414
visitors: true,
1515
sessions: false,
1616
bounce_rate: false,
17-
avg_session_duration: false,
17+
median_session_duration: false,
1818
};
1919

2020
export const metricVisibilityAtom = atomWithStorage<MetricVisibilityState>(

packages/shared/src/types/analytics.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export type SummaryMetricsData = {
5555
pageviews: number;
5656
bounce_rate: number;
5757
bounce_rate_pct: string;
58-
avg_session_duration: number;
59-
avg_session_duration_formatted: string;
58+
median_session_duration: number;
59+
median_session_duration_formatted: string;
6060
pages_per_session: number;
6161
};

packages/shared/src/types/realtime.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export interface EventsByDateData {
2121
unique_visitors: number;
2222
sessions: number;
2323
bounce_rate: number;
24-
avg_session_duration: number;
24+
median_session_duration: number;
2525
revenue_by_currency: any;
2626
revenue_by_card_brand: any;
2727

packages/shared/src/types/sessions.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export interface SessionReferrer {
1515

1616
export interface SessionMetrics {
1717
total_sessions: number;
18-
avg_session_duration: number;
18+
median_session_duration: number;
1919
bounce_rate: number;
2020
total_events: number;
2121
}
@@ -30,21 +30,21 @@ export interface SessionsByDevice {
3030
name: string;
3131
sessions: number;
3232
visitors: number;
33-
avg_session_duration: number;
33+
median_session_duration: number;
3434
}
3535

3636
export interface SessionsByBrowser {
3737
name: string;
3838
sessions: number;
3939
visitors: number;
40-
avg_session_duration: number;
40+
median_session_duration: number;
4141
}
4242

4343
export interface SessionTimeSeries {
4444
date: string;
4545
sessions: number;
4646
visitors: number;
47-
avg_session_duration: number;
47+
median_session_duration: number;
4848
}
4949

5050
export interface SessionFlow {

0 commit comments

Comments
 (0)