From da511ec76a560711102dac6505e4cee9e2eb6a31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20D=27Eredit=C3=A0?= Date: Tue, 9 Sep 2025 07:57:59 +0200 Subject: [PATCH 1/3] refactor(queries): replace hardcoded event types with constants Replaced hardcoded `event_type` values with named constants from `EVENT_TYPE` for improved readability and to align these files to the named constant usage seen across the project. --- src/queries/sql/events/getWebsiteEvents.ts | 9 +++++---- src/queries/sql/reports/getUTM.ts | 5 +++-- src/queries/sql/sessions/getWebsiteSession.ts | 11 ++++++++--- src/queries/sql/sessions/getWebsiteSessionStats.ts | 6 +++--- src/queries/sql/sessions/getWebsiteSessions.ts | 8 ++++---- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/queries/sql/events/getWebsiteEvents.ts b/src/queries/sql/events/getWebsiteEvents.ts index 0cbc6ac6fc..65da0b32dd 100644 --- a/src/queries/sql/events/getWebsiteEvents.ts +++ b/src/queries/sql/events/getWebsiteEvents.ts @@ -1,5 +1,6 @@ import clickhouse from '@/lib/clickhouse'; import { CLICKHOUSE, getDatabaseType, POSTGRESQL, PRISMA, runQuery } from '@/lib/db'; +import { EVENT_TYPE } from '@/lib/constants'; import prisma from '@/lib/prisma'; import { PageParams, QueryFilters } from '@/lib/types'; @@ -44,8 +45,8 @@ async function relationalQuery(websiteId: string, filters: QueryFilters, pagePar ${filterQuery} ${ search - ? `and ((event_name ${like} {{search}} and event_type = 2) - or (url_path ${like} {{search}} and event_type = 1))` + ? `and ((event_name ${like} {{search}} and event_type = ${EVENT_TYPE.customEvent}) + or (url_path ${like} {{search}} and event_type = ${EVENT_TYPE.pageView}))` : '' } order by created_at desc @@ -82,8 +83,8 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters, pagePar ${filterQuery} ${ search - ? `and ((positionCaseInsensitive(event_name, {search:String}) > 0 and event_type = 2) - or (positionCaseInsensitive(url_path, {search:String}) > 0 and event_type = 1))` + ? `and ((positionCaseInsensitive(event_name, {search:String}) > 0 and event_type = ${EVENT_TYPE.customEvent}) + or (positionCaseInsensitive(url_path, {search:String}) > 0 and event_type = ${EVENT_TYPE.pageView}))` : '' } order by created_at desc diff --git a/src/queries/sql/reports/getUTM.ts b/src/queries/sql/reports/getUTM.ts index f96c62d3c2..7497ab8f50 100644 --- a/src/queries/sql/reports/getUTM.ts +++ b/src/queries/sql/reports/getUTM.ts @@ -1,6 +1,7 @@ import clickhouse from '@/lib/clickhouse'; import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; import prisma from '@/lib/prisma'; +import { EVENT_TYPE } from '@/lib/constants'; export async function getUTM( ...args: [ @@ -36,7 +37,7 @@ async function relationalQuery( where website_id = {{websiteId::uuid}} and created_at between {{startDate}} and {{endDate}} and coalesce(url_query, '') != '' - and event_type = 1 + and event_type = ${EVENT_TYPE.pageView} group by 1 `, { @@ -65,7 +66,7 @@ async function clickhouseQuery( where website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64} and url_query != '' - and event_type = 1 + and event_type = ${EVENT_TYPE.pageView} group by 1 `, { diff --git a/src/queries/sql/sessions/getWebsiteSession.ts b/src/queries/sql/sessions/getWebsiteSession.ts index 8c549ca302..6d90b0182d 100644 --- a/src/queries/sql/sessions/getWebsiteSession.ts +++ b/src/queries/sql/sessions/getWebsiteSession.ts @@ -1,6 +1,7 @@ import prisma from '@/lib/prisma'; import clickhouse from '@/lib/clickhouse'; -import { runQuery, PRISMA, CLICKHOUSE } from '@/lib/db'; +import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; +import { EVENT_TYPE } from '@/lib/constants'; export async function getWebsiteSession(...args: [websiteId: string, sessionId: string]) { return runQuery({ @@ -46,8 +47,12 @@ async function relationalQuery(websiteId: string, sessionId: string) { session.city, min(website_event.created_at) as min_time, max(website_event.created_at) as max_time, - sum(case when website_event.event_type = 1 then 1 else 0 end) as views, - sum(case when website_event.event_type = 2 then 1 else 0 end) as events + sum(case when website_event.event_type = ${ + EVENT_TYPE.pageView + } then 1 else 0 end) as views, + sum(case when website_event.event_type = ${ + EVENT_TYPE.customEvent + } then 1 else 0 end) as events from session join website_event on website_event.session_id = session.session_id where session.website_id = {{websiteId::uuid}} diff --git a/src/queries/sql/sessions/getWebsiteSessionStats.ts b/src/queries/sql/sessions/getWebsiteSessionStats.ts index 4adaf07178..cdcc5fb4ae 100644 --- a/src/queries/sql/sessions/getWebsiteSessionStats.ts +++ b/src/queries/sql/sessions/getWebsiteSessionStats.ts @@ -1,5 +1,5 @@ import clickhouse from '@/lib/clickhouse'; -import { EVENT_COLUMNS } from '@/lib/constants'; +import { EVENT_COLUMNS, EVENT_TYPE } from '@/lib/constants'; import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; import prisma from '@/lib/prisma'; import { QueryFilters } from '@/lib/types'; @@ -33,7 +33,7 @@ async function relationalQuery( count(distinct website_event.session_id) as "visitors", count(distinct website_event.visit_id) as "visits", count(distinct session.country) as "countries", - sum(case when website_event.event_type = 2 then 1 else 0 end) as "events" + sum(case when website_event.event_type = ${EVENT_TYPE.customEvent} then 1 else 0 end) as "events" from website_event ${cohortQuery} join session on website_event.session_id = session.session_id @@ -61,7 +61,7 @@ async function clickhouseQuery( if (EVENT_COLUMNS.some(item => Object.keys(filters).includes(item))) { sql = ` select - sumIf(1, event_type = 1) as "pageviews", + sumIf(1, event_type = ${EVENT_TYPE.pageView}) as "pageviews", uniq(session_id) as "visitors", uniq(visit_id) as "visits", uniq(country) as "countries", diff --git a/src/queries/sql/sessions/getWebsiteSessions.ts b/src/queries/sql/sessions/getWebsiteSessions.ts index db2ea5aa3d..6693dd9ce6 100644 --- a/src/queries/sql/sessions/getWebsiteSessions.ts +++ b/src/queries/sql/sessions/getWebsiteSessions.ts @@ -1,5 +1,5 @@ import clickhouse from '@/lib/clickhouse'; -import { EVENT_COLUMNS } from '@/lib/constants'; +import { EVENT_COLUMNS, EVENT_TYPE } from '@/lib/constants'; import { CLICKHOUSE, getDatabaseType, POSTGRESQL, PRISMA, runQuery } from '@/lib/db'; import prisma from '@/lib/prisma'; import { PageParams, QueryFilters } from '@/lib/types'; @@ -39,7 +39,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters, pagePar min(website_event.created_at) as "firstAt", max(website_event.created_at) as "lastAt", count(distinct website_event.visit_id) as "visits", - sum(case when website_event.event_type = 1 then 1 else 0 end) as "views", + sum(case when website_event.event_type = ${EVENT_TYPE.pageView} then 1 else 0 end) as "views", max(website_event.created_at) as "createdAt" from website_event ${cohortQuery} @@ -96,7 +96,7 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters, pagePar ${getDateStringSQL('min(created_at)')} as firstAt, ${getDateStringSQL('max(created_at)')} as lastAt, uniq(visit_id) as visits, - sumIf(views, event_type = 1) as views, + sumIf(views, event_type = ${EVENT_TYPE.pageView}) as views, lastAt as createdAt from website_event ${cohortQuery} @@ -131,7 +131,7 @@ async function clickhouseQuery(websiteId: string, filters: QueryFilters, pagePar ${getDateStringSQL('min(min_time)')} as firstAt, ${getDateStringSQL('max(max_time)')} as lastAt, uniq(visit_id) as visits, - sumIf(views, event_type = 1) as views, + sumIf(views, event_type = ${EVENT_TYPE.pageView}) as views, lastAt as createdAt from website_event_stats_hourly website_event ${cohortQuery} From 6e9ffd9c4be5e971d51e623a9049f2935314a325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20D=27Eredit=C3=A0?= Date: Tue, 9 Sep 2025 08:21:31 +0200 Subject: [PATCH 2/3] feat(queries): include custom event tracking for bounces Updated bounce calculations to account for sessions containing custom events (`EVENT_TYPE.customEvent`), improving accuracy in `getWebsiteStats` and `getInsights` queries. Standardized usage of event type constants and adjusted query logic accordingly. --- src/queries/sql/getWebsiteStats.ts | 47 ++++++++++++++++++-------- src/queries/sql/reports/getInsights.ts | 29 +++++++++++----- 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/src/queries/sql/getWebsiteStats.ts b/src/queries/sql/getWebsiteStats.ts index 9a6d8b19a5..e13ff8f13f 100644 --- a/src/queries/sql/getWebsiteStats.ts +++ b/src/queries/sql/getWebsiteStats.ts @@ -1,9 +1,8 @@ import clickhouse from '@/lib/clickhouse'; -import { EVENT_TYPE } from '@/lib/constants'; import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; import prisma from '@/lib/prisma'; import { QueryFilters } from '@/lib/types'; -import { EVENT_COLUMNS } from '@/lib/constants'; +import { EVENT_COLUMNS, EVENT_TYPE } from '@/lib/constants'; export async function getWebsiteStats( ...args: [websiteId: string, filters: QueryFilters] @@ -34,21 +33,28 @@ async function relationalQuery( sum(t.c) as "pageviews", count(distinct t.session_id) as "visitors", count(distinct t.visit_id) as "visits", - sum(case when t.c = 1 then 1 else 0 end) as "bounces", + sum(case when t.c = 1 and t.has_event = 0 then 1 else 0 end) as "bounces", sum(${getTimestampDiffSQL('t.min_time', 't.max_time')}) as "totaltime" from ( select website_event.session_id, website_event.visit_id, - count(*) as "c", + sum(case when website_event.event_type = ${EVENT_TYPE.pageView} then 1 else 0 end) as "c", min(website_event.created_at) as "min_time", - max(website_event.created_at) as "max_time" + max(website_event.created_at) as "max_time", + max(case when exists ( + select 1 + from website_event we2 + where we2.website_id = website_event.website_id + and we2.session_id = website_event.session_id + and we2.created_at between {{startDate}} and {{endDate}} + and we2.event_type = ${EVENT_TYPE.customEvent} + ) then 1 else 0 end) as "has_event" from website_event ${cohortQuery} ${joinSession} where website_event.website_id = {{websiteId::uuid}} and website_event.created_at between {{startDate}} and {{endDate}} - and event_type = {{eventType}} ${filterQuery} group by 1, 2 ) as t @@ -77,23 +83,30 @@ async function clickhouseQuery( sum(t.c) as "pageviews", uniq(t.session_id) as "visitors", uniq(t.visit_id) as "visits", - sum(if(t.c = 1, 1, 0)) as "bounces", + sumIf(1, t.c = 1 and ifNull(e.has_event, 0) = 0) as "bounces", sum(max_time-min_time) as "totaltime" from ( select session_id, visit_id, - count(*) c, + countIf(event_type = ${EVENT_TYPE.pageView}) as c, min(created_at) min_time, max(created_at) max_time from website_event ${cohortQuery} where website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64} - and event_type = {eventType:UInt32} ${filterQuery} group by session_id, visit_id - ) as t; + ) as t + left join ( + select session_id, toUInt8(count() > 0) as has_event + from website_event + where website_id = {websiteId:UUID} + and created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_type = ${EVENT_TYPE.customEvent} + group by session_id + ) as e using session_id; `; } else { sql = ` @@ -101,22 +114,28 @@ async function clickhouseQuery( sum(t.c) as "pageviews", uniq(session_id) as "visitors", uniq(visit_id) as "visits", - sumIf(1, t.c = 1) as "bounces", + sumIf(1, t.c = 1 and ifNull(e.has_event, 0) = 0) as "bounces", sum(max_time-min_time) as "totaltime" from (select session_id, visit_id, - sum(views) c, + sumIf(views, event_type = ${EVENT_TYPE.pageView}) as c, min(min_time) min_time, max(max_time) max_time from website_event_stats_hourly "website_event" ${cohortQuery} where website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64} - and event_type = {eventType:UInt32} ${filterQuery} group by session_id, visit_id - ) as t; + ) as t + left join ( + select session_id, toUInt8(sumIf(views, event_type = ${EVENT_TYPE.customEvent}) > 0) as has_event + from website_event_stats_hourly + where website_id = {websiteId:UUID} + and created_at between {startDate:DateTime64} and {endDate:DateTime64} + group by session_id + ) as e using session_id; `; } diff --git a/src/queries/sql/reports/getInsights.ts b/src/queries/sql/reports/getInsights.ts index f4adc5bff8..2eed964921 100644 --- a/src/queries/sql/reports/getInsights.ts +++ b/src/queries/sql/reports/getInsights.ts @@ -41,7 +41,7 @@ async function relationalQuery( sum(t.c) as "views", count(distinct t.session_id) as "visitors", count(distinct t.visit_id) as "visits", - sum(case when t.c = 1 then 1 else 0 end) as "bounces", + sum(case when t.c = 1 and t.has_events = 0 then 1 else 0 end) as "bounces", sum(${getTimestampDiffSQL('t.min_time', 't.max_time')}) as "totaltime", ${parseFieldsByName(fields)} from ( @@ -49,15 +49,22 @@ async function relationalQuery( ${parseFields(fields)}, website_event.session_id, website_event.visit_id, - count(*) as "c", + sum(case when website_event.event_type = ${EVENT_TYPE.pageView} then 1 else 0 end) as "c", min(website_event.created_at) as "min_time", - max(website_event.created_at) as "max_time" + max(website_event.created_at) as "max_time", + max(case when exists ( + select 1 + from website_event we2 + where we2.website_id = website_event.website_id + and we2.session_id = website_event.session_id + and we2.created_at between {{startDate}} and {{endDate}} + and we2.event_type = ${EVENT_TYPE.customEvent} + ) then 1 else 0 end) as "has_events" from website_event ${cohortQuery} ${joinSession} where website_event.website_id = {{websiteId::uuid}} and website_event.created_at between {{startDate}} and {{endDate}} - and event_type = {{eventType}} ${filterQuery} group by ${parseFieldsByName(fields)}, website_event.session_id, website_event.visit_id @@ -83,7 +90,6 @@ async function clickhouseQuery( const { parseFilters, rawQuery } = clickhouse; const { filterQuery, cohortQuery, params } = await parseFilters(websiteId, { ...filters, - eventType: EVENT_TYPE.pageView, }); return rawQuery( @@ -92,7 +98,7 @@ async function clickhouseQuery( sum(t.c) as "views", count(distinct t.session_id) as "visitors", count(distinct t.visit_id) as "visits", - sum(if(t.c = 1, 1, 0)) as "bounces", + sumIf(1, t.c = 1 and ifNull(e.has_event, 0) = 0) as "bounces", sum(max_time-min_time) as "totaltime", ${parseFieldsByName(fields)} from ( @@ -100,18 +106,25 @@ async function clickhouseQuery( ${parseFields(fields)}, session_id, visit_id, - count(*) c, + countIf(event_type = ${EVENT_TYPE.pageView}) as c, min(created_at) min_time, max(created_at) max_time from website_event ${cohortQuery} where website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64} - and event_type = {eventType:UInt32} ${filterQuery} group by ${parseFieldsByName(fields)}, session_id, visit_id ) as t + left join ( + select session_id, toUInt8(count() > 0) as has_event + from website_event + where website_id = {websiteId:UUID} + and created_at between {startDate:DateTime64} and {endDate:DateTime64} + and event_type = ${EVENT_TYPE.customEvent} + group by session_id + ) as e using session_id group by ${parseFieldsByName(fields)} order by 1 desc, 2 desc limit 500 From e93636e1d8df84620fafc76247a74611648c3d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20D=27Eredit=C3=A0?= Date: Tue, 9 Sep 2025 09:13:57 +0200 Subject: [PATCH 3/3] feat(queries): add `BOUNCE_THRESHOLD` and enhance bounce calculation logic Introduced `BOUNCE_THRESHOLD` constant for configurable bounce definitions. Updated bounce calculation logic in `getWebsiteStats` and `getInsights` to use `events_count`. --- docker-compose.yml | 1 + src/lib/constants.ts | 4 ++++ src/queries/sql/getWebsiteStats.ts | 20 ++++++++++---------- src/queries/sql/reports/getInsights.ts | 14 +++++++------- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7b51db66ca..0a57142dae 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,6 +8,7 @@ services: DATABASE_URL: postgresql://umami:umami@db:5432/umami DATABASE_TYPE: postgresql APP_SECRET: replace-me-with-a-random-string + # BOUNCE_THRESHOLD: 2 # OPTIONAL: set the minimum amount custom events to trigger a bounce depends_on: db: condition: service_healthy diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 2718c135c8..f3e7323333 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -1,4 +1,8 @@ export const CURRENT_VERSION = process.env.currentVersion; +export const BOUNCE_THRESHOLD = Math.max( + 1, + Number.parseInt(process.env.BOUNCE_THRESHOLD || '1', 10) || 1, +); export const AUTH_TOKEN = 'umami.auth'; export const LOCALE_CONFIG = 'umami.locale'; export const TIMEZONE_CONFIG = 'umami.timezone'; diff --git a/src/queries/sql/getWebsiteStats.ts b/src/queries/sql/getWebsiteStats.ts index e13ff8f13f..48e0612b38 100644 --- a/src/queries/sql/getWebsiteStats.ts +++ b/src/queries/sql/getWebsiteStats.ts @@ -2,7 +2,7 @@ import clickhouse from '@/lib/clickhouse'; import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; import prisma from '@/lib/prisma'; import { QueryFilters } from '@/lib/types'; -import { EVENT_COLUMNS, EVENT_TYPE } from '@/lib/constants'; +import { BOUNCE_THRESHOLD, EVENT_COLUMNS, EVENT_TYPE } from '@/lib/constants'; export async function getWebsiteStats( ...args: [websiteId: string, filters: QueryFilters] @@ -33,7 +33,7 @@ async function relationalQuery( sum(t.c) as "pageviews", count(distinct t.session_id) as "visitors", count(distinct t.visit_id) as "visits", - sum(case when t.c = 1 and t.has_event = 0 then 1 else 0 end) as "bounces", + sum(case when t.c = 1 and t.events_count < ${BOUNCE_THRESHOLD} then 1 else 0 end) as "bounces", sum(${getTimestampDiffSQL('t.min_time', 't.max_time')}) as "totaltime" from ( select @@ -42,14 +42,14 @@ async function relationalQuery( sum(case when website_event.event_type = ${EVENT_TYPE.pageView} then 1 else 0 end) as "c", min(website_event.created_at) as "min_time", max(website_event.created_at) as "max_time", - max(case when exists ( - select 1 + max(( + select count(*) from website_event we2 where we2.website_id = website_event.website_id and we2.session_id = website_event.session_id and we2.created_at between {{startDate}} and {{endDate}} and we2.event_type = ${EVENT_TYPE.customEvent} - ) then 1 else 0 end) as "has_event" + )) as "events_count" from website_event ${cohortQuery} ${joinSession} @@ -83,7 +83,7 @@ async function clickhouseQuery( sum(t.c) as "pageviews", uniq(t.session_id) as "visitors", uniq(t.visit_id) as "visits", - sumIf(1, t.c = 1 and ifNull(e.has_event, 0) = 0) as "bounces", + sumIf(1, t.c = 1 and ifNull(e.events_count, 0) < ${BOUNCE_THRESHOLD}) as "bounces", sum(max_time-min_time) as "totaltime" from ( select @@ -99,8 +99,8 @@ async function clickhouseQuery( ${filterQuery} group by session_id, visit_id ) as t - left join ( - select session_id, toUInt8(count() > 0) as has_event + left join ( + select session_id, toUInt32(count()) as events_count from website_event where website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64} @@ -114,7 +114,7 @@ async function clickhouseQuery( sum(t.c) as "pageviews", uniq(session_id) as "visitors", uniq(visit_id) as "visits", - sumIf(1, t.c = 1 and ifNull(e.has_event, 0) = 0) as "bounces", + sumIf(1, t.c = 1 and ifNull(e.events_count, 0) < ${BOUNCE_THRESHOLD}) as "bounces", sum(max_time-min_time) as "totaltime" from (select session_id, @@ -130,7 +130,7 @@ async function clickhouseQuery( group by session_id, visit_id ) as t left join ( - select session_id, toUInt8(sumIf(views, event_type = ${EVENT_TYPE.customEvent}) > 0) as has_event + select session_id, toUInt32(sumIf(views, event_type = ${EVENT_TYPE.customEvent})) as events_count from website_event_stats_hourly where website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64} diff --git a/src/queries/sql/reports/getInsights.ts b/src/queries/sql/reports/getInsights.ts index 2eed964921..4b3d78a2a3 100644 --- a/src/queries/sql/reports/getInsights.ts +++ b/src/queries/sql/reports/getInsights.ts @@ -1,7 +1,7 @@ import { CLICKHOUSE, PRISMA, runQuery } from '@/lib/db'; import prisma from '@/lib/prisma'; import clickhouse from '@/lib/clickhouse'; -import { EVENT_TYPE, FILTER_COLUMNS, SESSION_COLUMNS } from '@/lib/constants'; +import { BOUNCE_THRESHOLD, EVENT_TYPE, FILTER_COLUMNS, SESSION_COLUMNS } from '@/lib/constants'; import { QueryFilters } from '@/lib/types'; export async function getInsights( @@ -41,7 +41,7 @@ async function relationalQuery( sum(t.c) as "views", count(distinct t.session_id) as "visitors", count(distinct t.visit_id) as "visits", - sum(case when t.c = 1 and t.has_events = 0 then 1 else 0 end) as "bounces", + sum(case when t.c = 1 and t.events_count < ${BOUNCE_THRESHOLD} then 1 else 0 end) as "bounces", sum(${getTimestampDiffSQL('t.min_time', 't.max_time')}) as "totaltime", ${parseFieldsByName(fields)} from ( @@ -52,14 +52,14 @@ async function relationalQuery( sum(case when website_event.event_type = ${EVENT_TYPE.pageView} then 1 else 0 end) as "c", min(website_event.created_at) as "min_time", max(website_event.created_at) as "max_time", - max(case when exists ( - select 1 + max(( + select count(*) from website_event we2 where we2.website_id = website_event.website_id and we2.session_id = website_event.session_id and we2.created_at between {{startDate}} and {{endDate}} and we2.event_type = ${EVENT_TYPE.customEvent} - ) then 1 else 0 end) as "has_events" + )) as "events_count" from website_event ${cohortQuery} ${joinSession} @@ -98,7 +98,7 @@ async function clickhouseQuery( sum(t.c) as "views", count(distinct t.session_id) as "visitors", count(distinct t.visit_id) as "visits", - sumIf(1, t.c = 1 and ifNull(e.has_event, 0) = 0) as "bounces", + sumIf(1, t.c = 1 and ifNull(e.events_count, 0) < ${BOUNCE_THRESHOLD}) as "bounces", sum(max_time-min_time) as "totaltime", ${parseFieldsByName(fields)} from ( @@ -118,7 +118,7 @@ async function clickhouseQuery( session_id, visit_id ) as t left join ( - select session_id, toUInt8(count() > 0) as has_event + select session_id, toUInt32(count()) as events_count from website_event where website_id = {websiteId:UUID} and created_at between {startDate:DateTime64} and {endDate:DateTime64}