diff --git a/src/app/(main)/reports/journey/JourneyView.tsx b/src/app/(main)/reports/journey/JourneyView.tsx
index b013a3e193..08a51ce2df 100644
--- a/src/app/(main)/reports/journey/JourneyView.tsx
+++ b/src/app/(main)/reports/journey/JourneyView.tsx
@@ -103,8 +103,6 @@ export default function JourneyView() {
return null;
}
- //console.log({ data, columns, selectedNode, activeNode });
-
return (
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx b/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx
index ea037852e2..617015f1d6 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx
@@ -18,6 +18,8 @@ import styles from './WebsiteExpandedView.module.css';
const views = {
url: PagesTable,
+ entry: PagesTable,
+ exit: PagesTable,
title: PagesTable,
referrer: ReferrersTable,
browser: BrowsersTable,
diff --git a/src/components/messages.ts b/src/components/messages.ts
index a4c43af22b..dd5eb9ddcc 100644
--- a/src/components/messages.ts
+++ b/src/components/messages.ts
@@ -88,6 +88,8 @@ export const labels = defineMessages({
leaveTeam: { id: 'label.leave-team', defaultMessage: 'Leave team' },
refresh: { id: 'label.refresh', defaultMessage: 'Refresh' },
pages: { id: 'label.pages', defaultMessage: 'Pages' },
+ entry: { id: 'label.entry', defaultMessage: 'Entry URL' },
+ exit: { id: 'label.exit', defaultMessage: 'Exit URL' },
referrers: { id: 'label.referrers', defaultMessage: 'Referrers' },
screens: { id: 'label.screens', defaultMessage: 'Screens' },
browsers: { id: 'label.browsers', defaultMessage: 'Browsers' },
diff --git a/src/components/metrics/PagesTable.tsx b/src/components/metrics/PagesTable.tsx
index d29952d4f3..767c4764b4 100644
--- a/src/components/metrics/PagesTable.tsx
+++ b/src/components/metrics/PagesTable.tsx
@@ -1,11 +1,10 @@
-import FilterLink from 'components/common/FilterLink';
+import { WebsiteContext } from 'app/(main)/websites/[websiteId]/WebsiteProvider';
import FilterButtons from 'components/common/FilterButtons';
-import MetricsTable, { MetricsTableProps } from './MetricsTable';
-import { useMessages } from 'components/hooks';
-import { useNavigation } from 'components/hooks';
+import FilterLink from 'components/common/FilterLink';
+import { useMessages, useNavigation } from 'components/hooks';
import { emptyFilter } from 'lib/filters';
import { useContext } from 'react';
-import { WebsiteContext } from 'app/(main)/websites/[websiteId]/WebsiteProvider';
+import MetricsTable, { MetricsTableProps } from './MetricsTable';
export interface PagesTableProps extends MetricsTableProps {
allowFilter?: boolean;
@@ -21,7 +20,7 @@ export function PagesTable({ allowFilter, ...props }: PagesTableProps) {
const { domain } = useContext(WebsiteContext);
const handleSelect = (key: any) => {
- router.push(renderUrl({ view: key }), { scroll: true });
+ router.push(renderUrl({ view: key }), { scroll: false });
};
const buttons = [
@@ -29,6 +28,14 @@ export function PagesTable({ allowFilter, ...props }: PagesTableProps) {
label: 'URL',
key: 'url',
},
+ {
+ label: formatMessage(labels.entry),
+ key: 'entry',
+ },
+ {
+ label: formatMessage(labels.exit),
+ key: 'exit',
+ },
{
label: formatMessage(labels.title),
key: 'title',
@@ -38,11 +45,13 @@ export function PagesTable({ allowFilter, ...props }: PagesTableProps) {
const renderLink = ({ x }) => {
return (
);
diff --git a/src/lib/constants.ts b/src/lib/constants.ts
index 745673e96c..f8447b8b7e 100644
--- a/src/lib/constants.ts
+++ b/src/lib/constants.ts
@@ -32,7 +32,7 @@ export const FILTER_RANGE = 'filter-range';
export const FILTER_REFERRERS = 'filter-referrers';
export const FILTER_PAGES = 'filter-pages';
export const UNIT_TYPES = ['year', 'month', 'hour', 'day', 'minute'];
-export const EVENT_COLUMNS = ['url', 'referrer', 'title', 'query', 'event'];
+export const EVENT_COLUMNS = ['url', 'entry', 'exit', 'referrer', 'title', 'query', 'event'];
export const SESSION_COLUMNS = [
'browser',
@@ -47,6 +47,8 @@ export const SESSION_COLUMNS = [
export const FILTER_COLUMNS = {
url: 'url_path',
+ entry: 'url_path',
+ exit: 'url_path',
referrer: 'referrer_domain',
title: 'page_title',
query: 'url_query',
diff --git a/src/queries/analytics/pageviews/getPageviewMetrics.ts b/src/queries/analytics/pageviews/getPageviewMetrics.ts
index 5f609c126e..67ccb04aab 100644
--- a/src/queries/analytics/pageviews/getPageviewMetrics.ts
+++ b/src/queries/analytics/pageviews/getPageviewMetrics.ts
@@ -1,7 +1,7 @@
-import prisma from 'lib/prisma';
import clickhouse from 'lib/clickhouse';
-import { runQuery, CLICKHOUSE, PRISMA } from 'lib/db';
import { EVENT_TYPE, FILTER_COLUMNS, SESSION_COLUMNS } from 'lib/constants';
+import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db';
+import prisma from 'lib/prisma';
import { QueryFilters } from 'lib/types';
export async function getPageviewMetrics(
@@ -31,17 +31,34 @@ async function relationalQuery(
{ joinSession: SESSION_COLUMNS.includes(type) },
);
+ let entryExitQuery = '';
let excludeDomain = '';
if (column === 'referrer_domain') {
excludeDomain = `and website_event.referrer_domain != {{websiteDomain}}
and website_event.referrer_domain is not null`;
}
+ if (type === 'entry' || type === 'exit') {
+ const aggregrate = type === 'entry' ? 'min' : 'max';
+
+ entryExitQuery = `
+ JOIN (select visit_id,
+ ${aggregrate}(created_at) target_created_at
+ from website_event
+ where website_event.website_id = {{websiteId::uuid}}
+ and website_event.created_at between {{startDate}} and {{endDate}}
+ and event_type = {{eventType}}
+ group by visit_id) x
+ ON x.visit_id = website_event.visit_id
+ and x.target_created_at = website_event.created_at`;
+ }
+
return rawQuery(
`
select ${column} x, count(*) y
from website_event
${joinSession}
+ ${entryExitQuery}
where website_event.website_id = {{websiteId::uuid}}
and website_event.created_at between {{startDate}} and {{endDate}}
and event_type = {{eventType}}
@@ -70,15 +87,32 @@ async function clickhouseQuery(
eventType: column === 'event_name' ? EVENT_TYPE.customEvent : EVENT_TYPE.pageView,
});
+ let entryExitQuery = '';
let excludeDomain = '';
if (column === 'referrer_domain') {
excludeDomain = `and referrer_domain != {websiteDomain:String} and referrer_domain != ''`;
}
+ if (type === 'entry' || type === 'exit') {
+ const aggregrate = type === 'entry' ? 'min' : 'max';
+
+ entryExitQuery = `
+ JOIN (select visit_id,
+ ${aggregrate}(created_at) target_created_at
+ from website_event
+ where website_id = {websiteId:UUID}
+ and created_at between {startDate:DateTime64} and {endDate:DateTime64}
+ and event_type = {eventType:UInt32}
+ group by visit_id) x
+ ON x.visit_id = website_event.visit_id
+ and x.target_created_at = website_event.created_at`;
+ }
+
return rawQuery(
`
select ${column} x, count(*) y
from website_event
+ ${entryExitQuery}
where website_id = {websiteId:UUID}
and created_at between {startDate:DateTime64} and {endDate:DateTime64}
and event_type = {eventType:UInt32}