From 5a37c918ee3ab1992180b3243ea51040cfd01e3e Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Fri, 7 Mar 2025 07:25:26 -0800 Subject: [PATCH 01/12] Load the agent from the AL script instead of CDN --- packages/manager/src/hooks/usePendo.ts | 38 +++++++++++++------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/manager/src/hooks/usePendo.ts b/packages/manager/src/hooks/usePendo.ts index 6c8619d431a..91563166fd8 100644 --- a/packages/manager/src/hooks/usePendo.ts +++ b/packages/manager/src/hooks/usePendo.ts @@ -2,12 +2,12 @@ import { useAccount, useProfile } from '@linode/queries'; import { loadScript } from '@linode/utilities'; // `loadScript` from `useScript` hook import React from 'react'; -import { APP_ROOT, PENDO_API_KEY } from 'src/constants'; -import { - checkOptanonConsent, - getCookie, - ONE_TRUST_COOKIE_CATEGORIES, -} from 'src/utilities/analytics/utils'; +import { ADOBE_ANALYTICS_URL, APP_ROOT, PENDO_API_KEY } from 'src/constants'; +// import { +// ONE_TRUST_COOKIE_CATEGORIES, +// checkOptanonConsent, +// getCookie, +// } from 'src/utilities/analytics/utils'; declare global { interface Window { @@ -70,21 +70,21 @@ export const usePendo = () => { const accountId = getUniquePendoId(account?.euuid); const visitorId = getUniquePendoId(profile?.uid.toString()); - const optanonCookie = getCookie('OptanonConsent'); - // Since OptanonConsent cookie always has a .linode.com domain, only check for consent in dev/staging/prod envs. - // When running the app locally, do not try to check for OneTrust cookie consent, just enable Pendo. - const hasConsentEnabled = - APP_ROOT.includes('localhost') || - checkOptanonConsent( - optanonCookie, - ONE_TRUST_COOKIE_CATEGORIES['Performance Cookies'] - ); + // const optanonCookie = getCookie('OptanonConsent'); + // // Since OptanonConsent cookie always has a .linode.com domain, only check for consent in dev/staging/prod envs. + // // When running the app locally, do not try to check for OneTrust cookie consent, just enable Pendo. + // const hasConsentEnabled = + // APP_ROOT.includes('localhost') || + // checkOptanonConsent( + // optanonCookie, + // ONE_TRUST_COOKIE_CATEGORIES['Performance Cookies'] + // ); // This URL uses a Pendo-configured CNAME (M3-8742). - const PENDO_URL = `https://content.psp.cloud.linode.com/agent/static/${PENDO_API_KEY}/pendo.js`; + // const PENDO_URL = `https://content.psp.cloud.linode.com/agent/static/${PENDO_API_KEY}/pendo.js`; React.useEffect(() => { - if (PENDO_API_KEY && hasConsentEnabled) { + if (ADOBE_ANALYTICS_URL && PENDO_API_KEY) { // Adapted Pendo install script for readability // Refer to: https://support.pendo.io/hc/en-us/articles/21362607464987-Components-of-the-install-script#01H6S2EXET8C9FGSHP08XZAE4F @@ -116,7 +116,7 @@ export const usePendo = () => { }); // Load Pendo script into the head HTML tag, then initialize Pendo with metadata - loadScript(PENDO_URL, { + loadScript(ADOBE_ANALYTICS_URL, { location: 'head', }).then(() => { window.pendo.initialize({ @@ -164,5 +164,5 @@ export const usePendo = () => { }); }); } - }, [PENDO_URL, accountId, hasConsentEnabled, visitorId]); + }, [ADOBE_ANALYTICS_URL, accountId, visitorId]); }; From a3bda2e3e0a22baf1f1ea294c74f5a4b7a4fd6e0 Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Mon, 5 May 2025 13:27:05 -0700 Subject: [PATCH 02/12] Remove the Optanon consent check for launch script to handle --- packages/manager/src/hooks/usePendo.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/manager/src/hooks/usePendo.ts b/packages/manager/src/hooks/usePendo.ts index 91563166fd8..9e572261b3a 100644 --- a/packages/manager/src/hooks/usePendo.ts +++ b/packages/manager/src/hooks/usePendo.ts @@ -80,8 +80,15 @@ export const usePendo = () => { // ONE_TRUST_COOKIE_CATEGORIES['Performance Cookies'] // ); - // This URL uses a Pendo-configured CNAME (M3-8742). - // const PENDO_URL = `https://content.psp.cloud.linode.com/agent/static/${PENDO_API_KEY}/pendo.js`; + // const optanonCookie = getCookie('OptanonConsent'); + // Since OptanonConsent cookie always has a .linode.com domain, only check for consent in dev/staging/prod envs. + // When running the app locally, do not try to check for OneTrust cookie consent, just enable Pendo. + // const hasConsentEnabled = + // APP_ROOT.includes('localhost') || + // checkOptanonConsent( + // optanonCookie, + // ONE_TRUST_COOKIE_CATEGORIES['Performance Cookies'] + // ); React.useEffect(() => { if (ADOBE_ANALYTICS_URL && PENDO_API_KEY) { @@ -164,5 +171,5 @@ export const usePendo = () => { }); }); } - }, [ADOBE_ANALYTICS_URL, accountId, visitorId]); + }, [accountId, visitorId]); }; From 1872663022107965cef3624283035e15b909ff62 Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Wed, 7 May 2025 07:38:26 -0700 Subject: [PATCH 03/12] Try to add page view tracking on first page load --- packages/manager/src/hooks/useAdobeAnalytics.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/manager/src/hooks/useAdobeAnalytics.ts b/packages/manager/src/hooks/useAdobeAnalytics.ts index d85391276da..1037b6d5dc4 100644 --- a/packages/manager/src/hooks/useAdobeAnalytics.ts +++ b/packages/manager/src/hooks/useAdobeAnalytics.ts @@ -29,6 +29,13 @@ export const useAdobeAnalytics = () => { 'Adobe Analytics error: Not all Adobe Launch scripts and extensions were loaded correctly; analytics cannot be sent.' ); } + + // Fire the first page view for the landing page + // eslint-disable-next-line no-console + console.log(window._satellite, window.location.pathname); + window._satellite.track('page view', { + url: window.location.pathname, + }); }) .catch(() => { // Do nothing; a user may have analytics script requests blocked. From 717de141f0c372ddcd80b3a1871e9f235e88cf5b Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Mon, 12 May 2025 16:19:53 -0700 Subject: [PATCH 04/12] Clean up cookie stuff --- packages/manager/src/hooks/usePendo.ts | 25 ------- .../src/utilities/analytics/utils.test.ts | 74 ------------------- .../manager/src/utilities/analytics/utils.ts | 54 -------------- 3 files changed, 153 deletions(-) diff --git a/packages/manager/src/hooks/usePendo.ts b/packages/manager/src/hooks/usePendo.ts index 9e572261b3a..61428cb229f 100644 --- a/packages/manager/src/hooks/usePendo.ts +++ b/packages/manager/src/hooks/usePendo.ts @@ -3,11 +3,6 @@ import { loadScript } from '@linode/utilities'; // `loadScript` from `useScript` import React from 'react'; import { ADOBE_ANALYTICS_URL, APP_ROOT, PENDO_API_KEY } from 'src/constants'; -// import { -// ONE_TRUST_COOKIE_CATEGORIES, -// checkOptanonConsent, -// getCookie, -// } from 'src/utilities/analytics/utils'; declare global { interface Window { @@ -70,26 +65,6 @@ export const usePendo = () => { const accountId = getUniquePendoId(account?.euuid); const visitorId = getUniquePendoId(profile?.uid.toString()); - // const optanonCookie = getCookie('OptanonConsent'); - // // Since OptanonConsent cookie always has a .linode.com domain, only check for consent in dev/staging/prod envs. - // // When running the app locally, do not try to check for OneTrust cookie consent, just enable Pendo. - // const hasConsentEnabled = - // APP_ROOT.includes('localhost') || - // checkOptanonConsent( - // optanonCookie, - // ONE_TRUST_COOKIE_CATEGORIES['Performance Cookies'] - // ); - - // const optanonCookie = getCookie('OptanonConsent'); - // Since OptanonConsent cookie always has a .linode.com domain, only check for consent in dev/staging/prod envs. - // When running the app locally, do not try to check for OneTrust cookie consent, just enable Pendo. - // const hasConsentEnabled = - // APP_ROOT.includes('localhost') || - // checkOptanonConsent( - // optanonCookie, - // ONE_TRUST_COOKIE_CATEGORIES['Performance Cookies'] - // ); - React.useEffect(() => { if (ADOBE_ANALYTICS_URL && PENDO_API_KEY) { // Adapted Pendo install script for readability diff --git a/packages/manager/src/utilities/analytics/utils.test.ts b/packages/manager/src/utilities/analytics/utils.test.ts index d2ec1e9b138..b606c03d238 100644 --- a/packages/manager/src/utilities/analytics/utils.test.ts +++ b/packages/manager/src/utilities/analytics/utils.test.ts @@ -1,85 +1,11 @@ import { generateTimeOfDay } from './customEventAnalytics'; import { - checkOptanonConsent, - getCookie, getFormattedStringFromFormEventOptions, - ONE_TRUST_COOKIE_CATEGORIES, waitForAdobeAnalyticsToBeLoaded, } from './utils'; import type { FormEventOptions } from './types'; -describe('getCookie', () => { - beforeAll(() => { - const mockCookies = - 'mycookie=my-cookie-value; OptanonConsent=cookie-consent-here; mythirdcookie=my-third-cookie;'; - vi.spyOn(document, 'cookie', 'get').mockReturnValue(mockCookies); - }); - - it('should return the value of a cookie from document.cookie given its name, given cookie in middle position', () => { - expect(getCookie('OptanonConsent')).toEqual('cookie-consent-here'); - }); - - it('should return the value of a cookie from document.cookie given its name, given cookie in first position', () => { - expect(getCookie('mycookie')).toEqual('my-cookie-value'); - }); - - it('should return the value of a cookie from document.cookie given its name, given cookie in last position', () => { - expect(getCookie('mythirdcookie')).toEqual('my-third-cookie'); - }); - - it('should return undefined if the cookie does not exist in document.cookie', () => { - expect(getCookie('mysecondcookie')).toEqual(undefined); - }); -}); - -describe('checkOptanonConsent', () => { - it('should return true if consent is enabled for the given Optanon cookie category', () => { - const mockPerformanceCookieConsentEnabled = - 'somestuffhere&groups=C0001%3A1%2CC0002%3A1%2CC0003%3A1%2CC0004%3A1%2CC0005%3A1&intType=6'; - - expect( - checkOptanonConsent( - mockPerformanceCookieConsentEnabled, - ONE_TRUST_COOKIE_CATEGORIES['Performance Cookies'] - ) - ).toEqual(true); - }); - - it('should return false if consent is disabled for the given Optanon cookie category', () => { - const mockPerformanceCookieConsentDisabled = - 'somestuffhere&groups=C0001%3A1%2CC0002%3A0%2CC0003%3A1%2CC0004%3A1%2CC0005%3A1&intType=6'; - - expect( - checkOptanonConsent( - mockPerformanceCookieConsentDisabled, - ONE_TRUST_COOKIE_CATEGORIES['Performance Cookies'] - ) - ).toEqual(false); - }); - - it('should return false if the consent category does not exist in the cookie', () => { - const mockNoPerformanceCookieCategory = - 'somestuffhere&groups=C0001%3A1%2CC0003%3A1%2CC0004%3A1%2CC0005%3A1&intType=6'; - - expect( - checkOptanonConsent( - mockNoPerformanceCookieCategory, - ONE_TRUST_COOKIE_CATEGORIES['Performance Cookies'] - ) - ).toEqual(false); - }); - - it('should return false if the cookie is undefined', () => { - expect( - checkOptanonConsent( - undefined, - ONE_TRUST_COOKIE_CATEGORIES['Performance Cookies'] - ) - ).toEqual(false); - }); -}); - describe('generateTimeOfDay', () => { it('should generate human-readable time of day', () => { expect(generateTimeOfDay(0)).toBe('Early Morning'); diff --git a/packages/manager/src/utilities/analytics/utils.ts b/packages/manager/src/utilities/analytics/utils.ts index 14a9ee8dd41..2f6b66f92a3 100644 --- a/packages/manager/src/utilities/analytics/utils.ts +++ b/packages/manager/src/utilities/analytics/utils.ts @@ -11,60 +11,6 @@ import type { FormStepEvent, } from './types'; -/** - * Based on Login's OneTrust cookie list - */ -export const ONE_TRUST_COOKIE_CATEGORIES = { - 'Functional Cookies': 'C0003', - 'Performance Cookies': 'C0002', // Analytics cookies fall into this category - 'Social Media Cookies': 'C0004', - 'Strictly Necessary Cookies': 'C0001', - 'Targeting Cookies': 'C0005', -} as const; - -/** - * Given the name of a cookie, parses the document.cookie string and returns the cookie's value. - * @param name cookie's name - * @returns value of cookie if it exists in the document; else, undefined - */ -export const getCookie = (name: string) => { - const cookies = document.cookie.split(';'); - - const selectedCookie = cookies.find( - (cookie) => cookie.trim().startsWith(name + '=') // Trim whitespace so position in cookie string doesn't matter - ); - - return selectedCookie?.trim().substring(name.length + 1); -}; - -/** - * This function parses the categories in the OptanonConsent cookie to check if consent is provided. - * @param optanonCookie the OptanonConsent cookie from OneTrust - * @param selectedCategory the category code based on cookie type - * @returns true if the user has consented to cookie enablement for the category; else, false - */ -export const checkOptanonConsent = ( - optanonCookie: string | undefined, - selectedCategory: (typeof ONE_TRUST_COOKIE_CATEGORIES)[keyof typeof ONE_TRUST_COOKIE_CATEGORIES] -): boolean => { - const optanonGroups = optanonCookie?.match(/groups=([^&]*)/); - - if (!optanonCookie || !optanonGroups) { - return false; - } - - // Optanon consent groups will be of the form: "C000[N]:[0/1]". - const unencodedOptanonGroups = decodeURIComponent(optanonGroups[1]).split( - ',' - ); - return unencodedOptanonGroups.some((consentGroup) => { - if (consentGroup.includes(selectedCategory)) { - return Number(consentGroup.split(':')[1]) === 1; // Cookie enabled - } - return false; - }); -}; - /** * Sends a direct call rule events to Adobe for a Component Click (and optionally, with `data`, Component Details). * This should be used for all custom events other than form events, which should use sendFormEvent. From c67870a44eb67247eab5f0f58898ca01454c97cc Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Mon, 12 May 2025 16:32:49 -0700 Subject: [PATCH 05/12] Update docs --- docs/tooling/analytics.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/tooling/analytics.md b/docs/tooling/analytics.md index 3cd5f883d7b..36de84443ec 100644 --- a/docs/tooling/analytics.md +++ b/docs/tooling/analytics.md @@ -12,15 +12,16 @@ Pendo is configured in [`usePendo.js`](https://github.com/linode/manager/blob/de Important notes: -- Pendo is only loaded if the user has enabled Performance Cookies via OneTrust *and* if a valid `PENDO_API_KEY` is configured as an environment variable. In our development, staging, and production environments, `PENDO_API_KEY` is available at build time. See **Locally Testing Page Views & Custom Events and/or Troubleshooting Pendo** for set up with local environments. -- We load the Pendo agent from the CDN, rather than [self-hosting](https://support.pendo.io/hc/en-us/articles/360038969692-Self-hosting-the-Pendo-agent), and we have configured a [CNAME](https://support.pendo.io/hc/en-us/articles/360043539891-CNAME-for-Pendo). +- Pendo is only loaded if a valid `PENDO_API_KEY` is configured as an environment variable. In our preview, development, staging, and production environments, `PENDO_API_KEY` is available at build time. See **Locally Testing Page Views & Custom Events and/or Troubleshooting Pendo** for set up with local environments. +- We [self-host](https://support.pendo.io/hc/en-us/articles/360038969692-Self-hosting-the-Pendo-agent) and load the Pendo agent from Adobe Launch, rather than from the CDN, and we have configured a [CNAME](https://support.pendo.io/hc/en-us/articles/360043539891-CNAME-for-Pendo). +- As configured by Adobe Launch, Pendo will respect OneTrust cookie preferences in development, staging, and production environments and does not check cookie preferences in the pre-preview environment. Pendo will not run on localhost:3000 because it needs a Optanon cookie with the linode.com domain for consent. - At initialization, we do string transformation on select URL patterns to **remove sensitive data**. When new URL patterns are added to Cloud Manager, verify that existing transforms remove sensitive data; if not, update the transforms. -- Pendo will respect OneTrust cookie preferences in development, staging, and production environments and does not check cookie preferences in the local environment. - Pendo makes use of the existing `data-testid` properties, used in our automated testing, for tagging elements. They are more persistent and reliable than CSS properties, which are liable to change. ### Locally Testing Page Views & Custom Events and/or Troubleshooting Pendo 1. Set the `REACT_APP_PENDO_API_KEY` environment variable in `.env`. +2. Confirm the Adobe Launch script has loaded. (View it in the browser console Sources tab under the assets.adobedtm.com directory.) 2. Use the browser tools Network tab, filter requests by "psp.cloud", and check that successful network requests have been made to load Pendo scripts (also visible in the browser tools Sources tab). 3. In the browser console, type `pendo.validateEnvironment()`. 4. You should see command output in the console, and it should include an `accountId` and a `visitorId` that correspond with your APIv4 account `euuid` and profile `uid`, respectively. Each page view change or custom event that fires should be visible as a request in the Network tab. From c152e988320f1c1aa6ceac385f184ad1041f6f78 Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Mon, 12 May 2025 16:41:36 -0700 Subject: [PATCH 06/12] Correct typo and stray console.log --- docs/tooling/analytics.md | 2 +- packages/manager/src/hooks/useAdobeAnalytics.ts | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/tooling/analytics.md b/docs/tooling/analytics.md index 36de84443ec..a38dcba5c98 100644 --- a/docs/tooling/analytics.md +++ b/docs/tooling/analytics.md @@ -14,7 +14,7 @@ Important notes: - Pendo is only loaded if a valid `PENDO_API_KEY` is configured as an environment variable. In our preview, development, staging, and production environments, `PENDO_API_KEY` is available at build time. See **Locally Testing Page Views & Custom Events and/or Troubleshooting Pendo** for set up with local environments. - We [self-host](https://support.pendo.io/hc/en-us/articles/360038969692-Self-hosting-the-Pendo-agent) and load the Pendo agent from Adobe Launch, rather than from the CDN, and we have configured a [CNAME](https://support.pendo.io/hc/en-us/articles/360043539891-CNAME-for-Pendo). -- As configured by Adobe Launch, Pendo will respect OneTrust cookie preferences in development, staging, and production environments and does not check cookie preferences in the pre-preview environment. Pendo will not run on localhost:3000 because it needs a Optanon cookie with the linode.com domain for consent. +- As configured by Adobe Launch, Pendo will respect OneTrust cookie preferences in development, staging, and production environments and does not check cookie preferences in preview environments. Pendo will not run on localhost:3000 because it needs a Optanon cookie with the linode.com domain for consent. - At initialization, we do string transformation on select URL patterns to **remove sensitive data**. When new URL patterns are added to Cloud Manager, verify that existing transforms remove sensitive data; if not, update the transforms. - Pendo makes use of the existing `data-testid` properties, used in our automated testing, for tagging elements. They are more persistent and reliable than CSS properties, which are liable to change. diff --git a/packages/manager/src/hooks/useAdobeAnalytics.ts b/packages/manager/src/hooks/useAdobeAnalytics.ts index 1037b6d5dc4..666e1483b72 100644 --- a/packages/manager/src/hooks/useAdobeAnalytics.ts +++ b/packages/manager/src/hooks/useAdobeAnalytics.ts @@ -31,8 +31,6 @@ export const useAdobeAnalytics = () => { } // Fire the first page view for the landing page - // eslint-disable-next-line no-console - console.log(window._satellite, window.location.pathname); window._satellite.track('page view', { url: window.location.pathname, }); From ac824345af3d722e4d3eaef2b609a30e02874e6e Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Mon, 12 May 2025 16:46:46 -0700 Subject: [PATCH 07/12] Add a try-catch --- packages/manager/src/hooks/usePendo.ts | 96 ++++++++++++++------------ 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/packages/manager/src/hooks/usePendo.ts b/packages/manager/src/hooks/usePendo.ts index 61428cb229f..08dde8ca39c 100644 --- a/packages/manager/src/hooks/usePendo.ts +++ b/packages/manager/src/hooks/usePendo.ts @@ -3,6 +3,7 @@ import { loadScript } from '@linode/utilities'; // `loadScript` from `useScript` import React from 'react'; import { ADOBE_ANALYTICS_URL, APP_ROOT, PENDO_API_KEY } from 'src/constants'; +import { reportException } from 'src/exceptionReporting'; declare global { interface Window { @@ -66,7 +67,7 @@ export const usePendo = () => { const visitorId = getUniquePendoId(profile?.uid.toString()); React.useEffect(() => { - if (ADOBE_ANALYTICS_URL && PENDO_API_KEY) { + if (PENDO_API_KEY && ADOBE_ANALYTICS_URL) { // Adapted Pendo install script for readability // Refer to: https://support.pendo.io/hc/en-us/articles/21362607464987-Components-of-the-install-script#01H6S2EXET8C9FGSHP08XZAE4F @@ -97,53 +98,60 @@ export const usePendo = () => { })(methodNames[index]); }); - // Load Pendo script into the head HTML tag, then initialize Pendo with metadata + // Ensure the Adobe Launch script is loaded, then initialize Pendo with metadata loadScript(ADOBE_ANALYTICS_URL, { location: 'head', }).then(() => { - window.pendo.initialize({ - account: { - id: accountId, // Highly recommended, required if using Pendo Feedback - // name: // Optional - // is_paying: // Recommended if using Pendo Feedback - // monthly_value:// Recommended if using Pendo Feedback - // planLevel: // Optional - // planPrice: // Optional - // creationDate: // Optional - - // You can add any additional account level key-values here, - // as long as it's not one of the above reserved names. - }, - // Controls what URLs we send to Pendo. Refer to: https://agent.pendo.io/advanced/location/. - location: { - transforms: [ - { - action: 'Clear', - attr: 'hash', - }, - { - action: 'Clear', - attr: 'search', - }, - { - action: 'Replace', - attr: 'pathname', - data(url: string) { - return transformUrl(url); + try { + window.pendo.initialize({ + account: { + id: accountId, // Highly recommended, required if using Pendo Feedback + // name: // Optional + // is_paying: // Recommended if using Pendo Feedback + // monthly_value:// Recommended if using Pendo Feedback + // planLevel: // Optional + // planPrice: // Optional + // creationDate: // Optional + + // You can add any additional account level key-values here, + // as long as it's not one of the above reserved names. + }, + // Controls what URLs we send to Pendo. Refer to: https://agent.pendo.io/advanced/location/. + location: { + transforms: [ + { + action: 'Clear', + attr: 'hash', }, - }, - ], - }, - visitor: { - id: visitorId, // Required if user is logged in - // email: // Recommended if using Pendo Feedback, or NPS Email - // full_name: // Recommended if using Pendo Feedback - // role: // Optional - - // You can add any additional visitor level key-values here, - // as long as it's not one of the above reserved names. - }, - }); + { + action: 'Clear', + attr: 'search', + }, + { + action: 'Replace', + attr: 'pathname', + data(url: string) { + return transformUrl(url); + }, + }, + ], + }, + visitor: { + id: visitorId, // Required if user is logged in + // email: // Recommended if using Pendo Feedback, or NPS Email + // full_name: // Recommended if using Pendo Feedback + // role: // Optional + + // You can add any additional visitor level key-values here, + // as long as it's not one of the above reserved names. + }, + }); + } catch (error) { + reportException( + 'An error occurred when trying to initialize Pendo.', + { error } + ); + } }); } }, [accountId, visitorId]); From 51ae0053177c03ebc4337d4084fe180f9f77e48b Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Mon, 12 May 2025 16:47:31 -0700 Subject: [PATCH 08/12] Add console log for env vars to debug --- packages/manager/src/hooks/usePendo.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/manager/src/hooks/usePendo.ts b/packages/manager/src/hooks/usePendo.ts index 08dde8ca39c..6bbda2945b9 100644 --- a/packages/manager/src/hooks/usePendo.ts +++ b/packages/manager/src/hooks/usePendo.ts @@ -67,6 +67,8 @@ export const usePendo = () => { const visitorId = getUniquePendoId(profile?.uid.toString()); React.useEffect(() => { + // eslint-disable-next-line no-console + console.log({ PENDO_API_KEY }, { ADOBE_ANALYTICS_URL }); if (PENDO_API_KEY && ADOBE_ANALYTICS_URL) { // Adapted Pendo install script for readability // Refer to: https://support.pendo.io/hc/en-us/articles/21362607464987-Components-of-the-install-script#01H6S2EXET8C9FGSHP08XZAE4F From 3ecafebbc5ee6c44cbe5cbab77e5b66b75763e40 Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Mon, 12 May 2025 16:48:42 -0700 Subject: [PATCH 09/12] Fix numbering in docs --- docs/tooling/analytics.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/tooling/analytics.md b/docs/tooling/analytics.md index a38dcba5c98..ea48182cfe4 100644 --- a/docs/tooling/analytics.md +++ b/docs/tooling/analytics.md @@ -22,10 +22,10 @@ Important notes: 1. Set the `REACT_APP_PENDO_API_KEY` environment variable in `.env`. 2. Confirm the Adobe Launch script has loaded. (View it in the browser console Sources tab under the assets.adobedtm.com directory.) -2. Use the browser tools Network tab, filter requests by "psp.cloud", and check that successful network requests have been made to load Pendo scripts (also visible in the browser tools Sources tab). -3. In the browser console, type `pendo.validateEnvironment()`. -4. You should see command output in the console, and it should include an `accountId` and a `visitorId` that correspond with your APIv4 account `euuid` and profile `uid`, respectively. Each page view change or custom event that fires should be visible as a request in the Network tab. -5. If the console does not output the expected ids and instead outputs something like `Cookies are disabled in Pendo config. Is this expected?` in response to the above command, clear app storage with the browser tools. Once redirected back to Login, update the OneTrust cookie settings to enable cookies via "Manage Preferences" in the banner at the bottom of the screen. Log back into Cloud Manager and Pendo should load. +3. Use the browser tools Network tab, filter requests by "psp.cloud", and check that successful network requests have been made to load Pendo scripts (also visible in the browser tools Sources tab). +4. In the browser console, type `pendo.validateEnvironment()`. +5. You should see command output in the console, and it should include an `accountId` and a `visitorId` that correspond with your APIv4 account `euuid` and profile `uid`, respectively. Each page view change or custom event that fires should be visible as a request in the Network tab. +6. If the console does not output the expected ids and instead outputs something like `Cookies are disabled in Pendo config. Is this expected?` in response to the above command, clear app storage with the browser tools. Once redirected back to Login, update the OneTrust cookie settings to enable cookies via "Manage Preferences" in the banner at the bottom of the screen. Log back into Cloud Manager and Pendo should load. ## Adobe Analytics From 6b29c12b9be91428874e5e7efd10c25067534ee6 Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Thu, 10 Apr 2025 14:16:52 -0700 Subject: [PATCH 10/12] Fix bug - resolve the promise in useScript if the script was already loaded --- packages/utilities/src/hooks/useScript.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/utilities/src/hooks/useScript.ts b/packages/utilities/src/hooks/useScript.ts index 839c577854e..35069417dd0 100644 --- a/packages/utilities/src/hooks/useScript.ts +++ b/packages/utilities/src/hooks/useScript.ts @@ -60,7 +60,9 @@ export const loadScript = ( } } else { // Grab existing script status from attribute and set to state. - options?.setStatus?.(script.getAttribute('data-status') as ScriptStatus); + const existingStatus = script.getAttribute('data-status') as ScriptStatus; + options?.setStatus?.(existingStatus); + resolve({ status: existingStatus }); } // Script event handler to update status in state // Note: Even if the script already exists we still need to add From 59055093f81ba758e0f40512cebe79563e37acf8 Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Mon, 12 May 2025 17:09:34 -0700 Subject: [PATCH 11/12] Add changesets --- .../manager/.changeset/pr-12203-changed-1747094831129.md | 5 +++++ packages/manager/.changeset/pr-12203-fixed-1747094899948.md | 5 +++++ packages/manager/.changeset/pr-12203-fixed-1747094966781.md | 5 +++++ packages/manager/src/hooks/usePendo.ts | 2 -- 4 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 packages/manager/.changeset/pr-12203-changed-1747094831129.md create mode 100644 packages/manager/.changeset/pr-12203-fixed-1747094899948.md create mode 100644 packages/manager/.changeset/pr-12203-fixed-1747094966781.md diff --git a/packages/manager/.changeset/pr-12203-changed-1747094831129.md b/packages/manager/.changeset/pr-12203-changed-1747094831129.md new file mode 100644 index 00000000000..22782cff002 --- /dev/null +++ b/packages/manager/.changeset/pr-12203-changed-1747094831129.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Changed +--- + +Switch to self-hosting the Pendo agent with Adobe Launch ([#12203](https://github.com/linode/manager/pull/12203)) diff --git a/packages/manager/.changeset/pr-12203-fixed-1747094899948.md b/packages/manager/.changeset/pr-12203-fixed-1747094899948.md new file mode 100644 index 00000000000..75f893b6cad --- /dev/null +++ b/packages/manager/.changeset/pr-12203-fixed-1747094899948.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Fixed +--- + +Bug in loadScript function not resolving promise if script already existed ([#12203](https://github.com/linode/manager/pull/12203)) diff --git a/packages/manager/.changeset/pr-12203-fixed-1747094966781.md b/packages/manager/.changeset/pr-12203-fixed-1747094966781.md new file mode 100644 index 00000000000..f8707444078 --- /dev/null +++ b/packages/manager/.changeset/pr-12203-fixed-1747094966781.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Fixed +--- + +Bug where first pageview of landing page was not fired in Adobe Analytics ([#12203](https://github.com/linode/manager/pull/12203)) diff --git a/packages/manager/src/hooks/usePendo.ts b/packages/manager/src/hooks/usePendo.ts index 6bbda2945b9..08dde8ca39c 100644 --- a/packages/manager/src/hooks/usePendo.ts +++ b/packages/manager/src/hooks/usePendo.ts @@ -67,8 +67,6 @@ export const usePendo = () => { const visitorId = getUniquePendoId(profile?.uid.toString()); React.useEffect(() => { - // eslint-disable-next-line no-console - console.log({ PENDO_API_KEY }, { ADOBE_ANALYTICS_URL }); if (PENDO_API_KEY && ADOBE_ANALYTICS_URL) { // Adapted Pendo install script for readability // Refer to: https://support.pendo.io/hc/en-us/articles/21362607464987-Components-of-the-install-script#01H6S2EXET8C9FGSHP08XZAE4F From 240384cb9fb79d90ed1c854ef2345ac6266bb70f Mon Sep 17 00:00:00 2001 From: mjac0bs Date: Tue, 13 May 2025 09:25:52 -0700 Subject: [PATCH 12/12] Update test spec to include new Launch script urls --- packages/manager/cypress/e2e/core/general/analytics.spec.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/manager/cypress/e2e/core/general/analytics.spec.ts b/packages/manager/cypress/e2e/core/general/analytics.spec.ts index c20555a720b..3ac17080cc3 100644 --- a/packages/manager/cypress/e2e/core/general/analytics.spec.ts +++ b/packages/manager/cypress/e2e/core/general/analytics.spec.ts @@ -2,9 +2,8 @@ import { ui } from 'support/ui'; const ADOBE_LAUNCH_URLS = [ 'https://assets.adobedtm.com/fcfd3580c848/15e23aa7fce2/launch-92311d9d9637-development.min.js', // New dev Launch script - 'https://assets.adobedtm.com/fcfd3580c848/795fdfec4a0e/launch-09b7ca9d43ad-development.min.js', // Existing dev Launch script - 'https://assets.adobedtm.com/fcfd3580c848/795fdfec4a0e/launch-a50be9afbe1d-staging.min.js', // Existing staging Launch script - 'https://assets.adobedtm.com/fcfd3580c848/795fdfec4a0e/launch-de0ca78667e7.min.js', // Existing prod Launch script + 'https://assets.adobedtm.com/fcfd3580c848/15e23aa7fce2/launch-5bda4b7a1db9-staging.min.js', // New staging Launch script + 'https://assets.adobedtm.com/fcfd3580c848/15e23aa7fce2/launch-9ea21650035a.min.js', // New prod Launch script ]; describe('Script loading and user interaction test', () => {