From ea3e88e43f6de738940fefb75f885ec21b16c182 Mon Sep 17 00:00:00 2001 From: Sophia Mersmann Date: Fri, 1 Nov 2024 16:21:32 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20log=20explorer=20views=20to=20googl?= =?UTF-8?q?e=20analytics=20(#4098)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves #4094 ## Summary A view event is logged to Google Analytics when an Explorer is rendered and when the view is changed. ## Details - A view event is logged if Explorer is scrolled into view so that we only log an event when an Explorer has actually been looked at - We also log an event when the user updates the view Logged events are of the following shape: ``` { "event": "owid.explorer_view", "explorerPath": "/explorers/democracy", "explorerView": JSON.stringify({ Dataset: "Polity", Metric: "Democracy", "Sub-metric": "Main index" }) } ``` ## Testing I tested this code by console logging when an event is fired, but I haven't checked to see if these events actually end up in GA. - Explorer page: http://staging-site-log-explorer-views/explorers/democracy - [x] Should log one view event on page load - [x] Should log an event when the view is changed - Topic page: http://staging-site-log-explorer-views/democracy - [x] Should log an event when the explorer is scrolled into view - [x] Should log an event when the view is changed - [x] Should not log another event when the explorer is scrolled out of view and then again into view - [x] Should not log an event for the embedded explorer --- explorer/Explorer.tsx | 27 +++++++++++++++++++ .../grapher/src/core/GrapherAnalytics.ts | 11 ++++++++ 2 files changed, 38 insertions(+) diff --git a/explorer/Explorer.tsx b/explorer/Explorer.tsx index a9f48821bf..e3bdeda19f 100644 --- a/explorer/Explorer.tsx +++ b/explorer/Explorer.tsx @@ -27,6 +27,7 @@ import { SlideShowController, SlideShowManager, DEFAULT_GRAPHER_ENTITY_TYPE, + GrapherAnalytics, } from "@ourworldindata/grapher" import { Bounds, @@ -189,6 +190,8 @@ export class Explorer EntityPickerManager, GrapherManager { + analytics = new GrapherAnalytics() + // caution: do a ctrl+f to find untyped usages static renderSingleExplorerOnExplorerPage( program: ExplorerProps, @@ -272,6 +275,24 @@ export class Explorer return new Map(arr.map((config) => [config.id!, config])) } + private setUpIntersectionObserver(): void { + if (typeof window !== "undefined" && "IntersectionObserver" in window) { + const observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + this.analytics.logExplorerView( + this.explorerProgram.slug, + this.explorerProgram.decisionMatrix.currentParams + ) + observer.disconnect() + } + }) + }) + observer.observe(this.grapherContainerRef.current!) + this.disposers.push(() => observer.disconnect()) + } + } + disposers: (() => void)[] = [] componentDidMount() { this.setGrapher(this.grapherRef!.current!) @@ -291,6 +312,7 @@ export class Explorer this.grapher?.populateFromQueryParams(url.queryParams) exposeInstanceOnWindow(this, "explorer") + this.setUpIntersectionObserver() this.attachEventListeners() this.updateEntityPickerTable() // call for the first time to initialize EntityPicker } @@ -415,6 +437,11 @@ export class Explorer : tabsWithoutTable[0] ?? GrapherTabOption.table this.grapher.populateFromQueryParams(newGrapherParams) + + this.analytics.logExplorerView( + this.explorerProgram.slug, + this.explorerProgram.decisionMatrix.currentParams + ) } @action.bound private setGrapherTable(table: OwidTable) { diff --git a/packages/@ourworldindata/grapher/src/core/GrapherAnalytics.ts b/packages/@ourworldindata/grapher/src/core/GrapherAnalytics.ts index bbaf5234f4..2f81bb6ead 100644 --- a/packages/@ourworldindata/grapher/src/core/GrapherAnalytics.ts +++ b/packages/@ourworldindata/grapher/src/core/GrapherAnalytics.ts @@ -15,6 +15,7 @@ export enum EventCategory { GrapherView = "owid.grapher_view", GrapherClick = "owid.grapher_click", GrapherError = "owid.grapher_error", + ExplorerView = "owid.explorer_view", ExplorerCountrySelector = "owid.explorer_country_selector", Hover = "owid.hover", KeyboardShortcut = "owid.keyboard_shortcut", @@ -50,6 +51,8 @@ interface GAEvent { eventTarget?: string grapherPath?: string grapherView?: string // specifies a view in a multi-dim data page + explorerPath?: string + explorerView?: string } // taken from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/de66435d18fbdb2684947d16b5cd3a77f876324c/types/gtag.js/index.d.ts#L151-L156 @@ -97,6 +100,14 @@ export class GrapherAnalytics { }) } + logExplorerView(slug: string, view: Record): void { + this.logToGA({ + event: EventCategory.ExplorerView, + explorerPath: `/explorers/${slug}`, + explorerView: JSON.stringify(view), + }) + } + logGlobalEntitySelector(action: entityControlEvent, note?: string): void { this.logToGA({ event: EventCategory.GlobalEntitySelectorUsage,