From b20f45a88298b79b31f510e8f76c3e78e771d01a Mon Sep 17 00:00:00 2001 From: Rafa Audibert Date: Thu, 19 Dec 2024 15:43:32 -0300 Subject: [PATCH] feat(web-analytics): Display viewport-related statistics This was requested by a customer via support and it's pretty simple to add, let's do it Outstanding question: should we track viewport or screen size? --- frontend/src/queries/schema.json | 1 + frontend/src/queries/schema.ts | 1 + .../web-analytics/tiles/WebAnalyticsTile.tsx | 14 ++++++++++++++ .../src/scenes/web-analytics/webAnalyticsLogic.tsx | 8 ++++++++ posthog/hogql_queries/web_analytics/stats_table.py | 11 +++++++++++ posthog/schema.py | 1 + 6 files changed, 36 insertions(+) diff --git a/frontend/src/queries/schema.json b/frontend/src/queries/schema.json index 005fb78c94497..d3b63fb1308c5 100644 --- a/frontend/src/queries/schema.json +++ b/frontend/src/queries/schema.json @@ -13264,6 +13264,7 @@ "InitialUTMSourceMediumCampaign", "Browser", "OS", + "Viewport", "DeviceType", "Country", "Region", diff --git a/frontend/src/queries/schema.ts b/frontend/src/queries/schema.ts index 9e4252c989b38..cbf9b6caf8871 100644 --- a/frontend/src/queries/schema.ts +++ b/frontend/src/queries/schema.ts @@ -1822,6 +1822,7 @@ export enum WebStatsBreakdown { InitialUTMSourceMediumCampaign = 'InitialUTMSourceMediumCampaign', Browser = 'Browser', OS = 'OS', + Viewport = 'Viewport', DeviceType = 'DeviceType', Country = 'Country', Region = 'Region', diff --git a/frontend/src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx b/frontend/src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx index 38ce8be4ef977..b5b04d6b419b5 100644 --- a/frontend/src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx +++ b/frontend/src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx @@ -145,6 +145,8 @@ const BreakdownValueTitle: QueryContextColumnTitleComponent = (props) => { return <>Browser case WebStatsBreakdown.OS: return <>OS + case WebStatsBreakdown.Viewport: + return <>Viewport case WebStatsBreakdown.DeviceType: return <>Device Type case WebStatsBreakdown.Country: @@ -173,6 +175,16 @@ const BreakdownValueCell: QueryContextColumnComponent = (props) => { const { breakdownBy } = source switch (breakdownBy) { + case WebStatsBreakdown.Viewport: + if (Array.isArray(value)) { + const [width, height] = value + return ( + <> + {width}x{height} + + ) + } + break case WebStatsBreakdown.Country: if (typeof value === 'string') { const countryCode = value @@ -264,6 +276,8 @@ export const webStatsBreakdownToPropertyName = ( return { key: '$browser', type: PropertyFilterType.Event } case WebStatsBreakdown.OS: return { key: '$os', type: PropertyFilterType.Event } + case WebStatsBreakdown.Viewport: + return { key: '$viewport', type: PropertyFilterType.Event } case WebStatsBreakdown.DeviceType: return { key: '$device_type', type: PropertyFilterType.Event } case WebStatsBreakdown.Country: diff --git a/frontend/src/scenes/web-analytics/webAnalyticsLogic.tsx b/frontend/src/scenes/web-analytics/webAnalyticsLogic.tsx index bd3f9afb4e78e..65b372d40a4b9 100644 --- a/frontend/src/scenes/web-analytics/webAnalyticsLogic.tsx +++ b/frontend/src/scenes/web-analytics/webAnalyticsLogic.tsx @@ -174,6 +174,7 @@ export enum DeviceTab { BROWSER = 'BROWSER', OS = 'OS', DEVICE_TYPE = 'DEVICE_TYPE', + VIEWPORT = 'VIEWPORT', } export enum PathTab { @@ -1120,6 +1121,13 @@ export const webAnalyticsLogic = kea([ WebStatsBreakdown.Browser ), createTableTab(TileId.DEVICES, DeviceTab.OS, 'OS', 'OS', WebStatsBreakdown.OS), + createTableTab( + TileId.DEVICES, + DeviceTab.VIEWPORT, + 'Viewports', + 'Viewport', + WebStatsBreakdown.Viewport + ), ], }, shouldShowGeographyTile diff --git a/posthog/hogql_queries/web_analytics/stats_table.py b/posthog/hogql_queries/web_analytics/stats_table.py index 7135934bc6625..862d2830c9fba 100644 --- a/posthog/hogql_queries/web_analytics/stats_table.py +++ b/posthog/hogql_queries/web_analytics/stats_table.py @@ -512,6 +512,13 @@ def _counts_breakdown_value(self): return ast.Field(chain=["properties", "$browser"]) case WebStatsBreakdown.OS: return ast.Field(chain=["properties", "$os"]) + case WebStatsBreakdown.VIEWPORT: + return ast.Tuple( + exprs=[ + ast.Field(chain=["properties", "$viewport_width"]), + ast.Field(chain=["properties", "$viewport_height"]), + ] + ) case WebStatsBreakdown.DEVICE_TYPE: return ast.Field(chain=["properties", "$device_type"]) case WebStatsBreakdown.COUNTRY: @@ -555,6 +562,10 @@ def where_breakdown(self): match self.query.breakdownBy: case WebStatsBreakdown.REGION | WebStatsBreakdown.CITY: return parse_expr("tupleElement(breakdown_value, 2) IS NOT NULL") + case WebStatsBreakdown.VIEWPORT: + return parse_expr( + "tupleElement(breakdown_value, 1) IS NOT NULL AND tupleElement(breakdown_value, 2) IS NOT NULL" + ) case ( WebStatsBreakdown.INITIAL_UTM_SOURCE | WebStatsBreakdown.INITIAL_UTM_CAMPAIGN diff --git a/posthog/schema.py b/posthog/schema.py index a46596350f23f..88fa9d3664ec1 100644 --- a/posthog/schema.py +++ b/posthog/schema.py @@ -1673,6 +1673,7 @@ class WebStatsBreakdown(StrEnum): INITIAL_UTM_SOURCE_MEDIUM_CAMPAIGN = "InitialUTMSourceMediumCampaign" BROWSER = "Browser" OS = "OS" + VIEWPORT = "Viewport" DEVICE_TYPE = "DeviceType" COUNTRY = "Country" REGION = "Region"