From 2712c3dbdb8cd8a04e30a5c02c9658869ead149a Mon Sep 17 00:00:00 2001 From: Leo McArdle Date: Fri, 1 Sep 2023 16:28:13 +0000 Subject: [PATCH 1/2] chore(glean): add page's UTM parameters to pings https://mozilla-hub.atlassian.net/browse/MP-545 --- client/src/telemetry/generated/page.ts | 25 ++++++++++++++++++++++- client/src/telemetry/glean-context.tsx | 24 ++++++++++++++++++++++ client/src/telemetry/metrics.yaml | 28 ++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/client/src/telemetry/generated/page.ts b/client/src/telemetry/generated/page.ts index cc69eab5f1b7..6dfcd685eb36 100644 --- a/client/src/telemetry/generated/page.ts +++ b/client/src/telemetry/generated/page.ts @@ -4,8 +4,9 @@ // AUTOGENERATED BY glean_parser v8.1.1. DO NOT EDIT. DO NOT COMMIT. -import UrlMetricType from "@mozilla/glean/private/metrics/url"; +import LabeledMetricType from "@mozilla/glean/private/metrics/labeled"; import StringMetricType from "@mozilla/glean/private/metrics/string"; +import UrlMetricType from "@mozilla/glean/private/metrics/url"; /** * The HTTP status code of the page. @@ -61,3 +62,25 @@ export const referrer = new UrlMetricType({ lifetime: "application", disabled: false, }); + +/** + * The UTM parameters of the page, used to attribute the source of traffic: + * "source": which site sent the traffic + * "medium": what type of link was used + * "campaign": what specific campaign or experiment does this relate to + * "term": here for completeness, the search term that was purchased/bid on + * "content": what specifically was clicked to bring the user to the site + * + * Generated from `page.utm`. + */ +export const utm = new LabeledMetricType( + { + category: "page", + name: "utm", + sendInPings: ["action", "page"], + lifetime: "application", + disabled: false, + }, + StringMetricType, + ["campaign", "content", "medium", "source", "term"] +); diff --git a/client/src/telemetry/glean-context.tsx b/client/src/telemetry/glean-context.tsx index 0ca5190554fc..e67be0d77f10 100644 --- a/client/src/telemetry/glean-context.tsx +++ b/client/src/telemetry/glean-context.tsx @@ -15,6 +15,17 @@ import { Doc } from "../../../libs/types/document"; export type ViewportBreakpoint = "xs" | "sm" | "md" | "lg" | "xl" | "xxl"; export type HTTPStatus = "200" | "404"; +const UTMParameterNames = [ + "source", + "medium", + "campaign", + "term", + "content", +] as const; +type UTMParameters = Partial< + Record<(typeof UTMParameterNames)[number], string> +>; + export type PageProps = { referrer: string | undefined; path: string | undefined; @@ -26,6 +37,7 @@ export type PageProps = { viewportRatio: number; viewportHorizontalCoverage: number; isBaseline?: string; + utm: UTMParameters; }; export type PageEventProps = { @@ -98,6 +110,9 @@ function glean(): GleanAnalytics { if (page.isBaseline) { pageMetric.isBaseline.set(page.isBaseline); } + for (const param in page.utm) { + pageMetric.utm[param].set(page.utm[param]); + } pageMetric.httpStatus.set(page.httpStatus); if (page.geo) { navigatorMetric.geo.set(page.geo); @@ -203,6 +218,7 @@ export function useGleanPage(pageNotFound: boolean, doc?: Doc) { : doc.baseline.is_baseline ? "baseline" : "not_baseline", + utm: getUTMParameters(), }); if (typeof userData !== "undefined" && path.current !== loc.pathname) { path.current = loc.pathname; @@ -223,3 +239,11 @@ export function useGleanClick() { [glean, userData?.subscriptionType] ); } + +function getUTMParameters(): UTMParameters { + const searchParams = new URLSearchParams(document.location.search); + return UTMParameterNames.reduce((acc, name): UTMParameters => { + const param = searchParams.get(`utm_${name}`); + return param ? { ...acc, [name]: param } : acc; + }, {}); +} diff --git a/client/src/telemetry/metrics.yaml b/client/src/telemetry/metrics.yaml index 4d40d767c2fb..15e115c6e9b7 100644 --- a/client/src/telemetry/metrics.yaml +++ b/client/src/telemetry/metrics.yaml @@ -37,6 +37,34 @@ page: notification_emails: - mdn-team@mozilla.com expires: 2023-09-05 + utm: + type: labeled_string + lifetime: application + send_in_pings: + - page + - action + description: | + The UTM parameters of the page, used to attribute the source of traffic: + "source": which site sent the traffic + "medium": what type of link was used + "campaign": what specific campaign or experiment does this relate to + "term": here for completeness, the search term that was purchased/bid on + "content": what specifically was clicked to bring the user to the site + data_sensitivity: + - web_activity + bugs: + - "https://mozilla-hub.atlassian.net/browse/MP-545" + data_reviews: + - "https://bugzilla.mozilla.org/show_bug.cgi?id=1851150" + notification_emails: + - mdn-team@mozilla.com + expires: 2024-09-05 + labels: + - source + - medium + - campaign + - term + - content http_status: type: string description: | From 42ba5600ef78111f8b96700b94eabc05668f9aca Mon Sep 17 00:00:00 2001 From: Leo McArdle Date: Mon, 16 Oct 2023 11:20:37 +0000 Subject: [PATCH 2/2] review feedback --- client/src/telemetry/glean-context.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/telemetry/glean-context.tsx b/client/src/telemetry/glean-context.tsx index e67be0d77f10..8f1d76c457aa 100644 --- a/client/src/telemetry/glean-context.tsx +++ b/client/src/telemetry/glean-context.tsx @@ -15,7 +15,7 @@ import { Doc } from "../../../libs/types/document"; export type ViewportBreakpoint = "xs" | "sm" | "md" | "lg" | "xl" | "xxl"; export type HTTPStatus = "200" | "404"; -const UTMParameterNames = [ +const UTM_PARAMETER_NAMES = [ "source", "medium", "campaign", @@ -23,7 +23,7 @@ const UTMParameterNames = [ "content", ] as const; type UTMParameters = Partial< - Record<(typeof UTMParameterNames)[number], string> + Record<(typeof UTM_PARAMETER_NAMES)[number], string> >; export type PageProps = { @@ -242,7 +242,7 @@ export function useGleanClick() { function getUTMParameters(): UTMParameters { const searchParams = new URLSearchParams(document.location.search); - return UTMParameterNames.reduce((acc, name): UTMParameters => { + return UTM_PARAMETER_NAMES.reduce((acc, name): UTMParameters => { const param = searchParams.get(`utm_${name}`); return param ? { ...acc, [name]: param } : acc; }, {});