diff --git a/.changeset/clever-seals-pull.md b/.changeset/clever-seals-pull.md new file mode 100644 index 00000000..d3854b62 --- /dev/null +++ b/.changeset/clever-seals-pull.md @@ -0,0 +1,9 @@ +--- +"@ima/plugin-analytic-google": major +--- + +Update data sent in a GA4 page view hit + +**What:** Add the prefix `page_` to the existing params (these are the correct default names for GA4) and add new parameters. Save `referrer` to correspond to the actual referrer in SPA browsing. Add missing consent settings. +**Why:** We were hitting page view incorrectly. +**How:** Nothing. diff --git a/.eslintrc.js b/.eslintrc.js index da63fab8..13e51993 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -24,7 +24,9 @@ module.exports = { 'jsdoc/require-returns-check': 'off', 'jsdoc/require-jsdoc': 'off', 'jsdoc/tag-lines': 'off', - + 'jsdoc/require-param': 'off', + 'jsdoc/require-returns': 'off', + 'jsdoc/require-param-type': 'off', 'no-console': [ 'error', { diff --git a/package-lock.json b/package-lock.json index 0a188507..88e3e91a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@babel/preset-react": "^7.22.3", "@cfaester/enzyme-adapter-react-18": "^0.7.0", "@changesets/cli": "^2.26.1", - "@ima/plugin-cli": "^19.1.1", + "@ima/plugin-cli": "^19.1.2", "@swc/jest": "^0.2.26", "@types/jest": "^29.5.1", "@types/node": "^20.2.5", @@ -2587,9 +2587,9 @@ "link": true }, "node_modules/@ima/plugin-cli": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/@ima/plugin-cli/-/plugin-cli-19.1.1.tgz", - "integrity": "sha512-VYjkF9+Hm+RXEkPiaRdBbu5kY4xDSyuzr4hnAC4hY7O5pVoJNBZIU0Fcm20lO8pbthlYZ4b/Rl7vDwLqplSVVA==", + "version": "19.1.2", + "resolved": "https://registry.npmjs.org/@ima/plugin-cli/-/plugin-cli-19.1.2.tgz", + "integrity": "sha512-uU97ZipyhTVCx1JgQhNUCUyd+MdwBOFlDI/MP837c/XmIFOZGDFRV9mEqoWnXcxAw79RmhNHlW9xquUdbFZX7g==", "dev": true, "dependencies": { "@ima/dev-utils": "^19.0.0", diff --git a/package.json b/package.json index 232f2206..df382b9c 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@babel/preset-react": "^7.22.3", "@cfaester/enzyme-adapter-react-18": "^0.7.0", "@changesets/cli": "^2.26.1", - "@ima/plugin-cli": "^19.1.1", + "@ima/plugin-cli": "^19.1.2", "@swc/jest": "^0.2.26", "@types/jest": "^29.5.1", "@types/node": "^20.2.5", diff --git a/packages/plugin-analytic-google/src/GoogleAnalytics4.ts b/packages/plugin-analytic-google/src/GoogleAnalytics4.ts index ff6e26b1..d880a737 100644 --- a/packages/plugin-analytic-google/src/GoogleAnalytics4.ts +++ b/packages/plugin-analytic-google/src/GoogleAnalytics4.ts @@ -20,6 +20,7 @@ export type AnalyticGoogleSettings = { */ export class GoogleAnalytics4 extends AbstractAnalytic { #config: AnalyticGoogleSettings; + #referrer: string; _consentSettings?: ConsentSettings; static get $dependencies(): Dependencies { @@ -55,6 +56,7 @@ export class GoogleAnalytics4 extends AbstractAnalytic { super(...rest); this.#config = config; + this.#referrer = ''; this._analyticScriptName = 'google_analytics_4'; @@ -64,9 +66,6 @@ export class GoogleAnalytics4 extends AbstractAnalytic { } /** * Hits custom event of given with given data - * - * @param eventName custom event name - * @param eventData custom event data */ hit(eventName: string, eventData: Record) { if (!this.isEnabled()) { @@ -78,14 +77,15 @@ export class GoogleAnalytics4 extends AbstractAnalytic { /** * Hit page view event to analytic with defined data. - * @param pageData */ hitPageView(pageData: Record) { if (!this.isEnabled()) { return; } - this._ga4Script('event', 'page_view', this._getPageViewData(pageData)); + const pageViewData = this._getPageViewData(pageData); + this._ga4Script('event', 'page_view', pageViewData); + this.#referrer = pageViewData.page_location; } /** @@ -150,10 +150,17 @@ export class GoogleAnalytics4 extends AbstractAnalytic { * Returns page view data derived from pageData param. */ _getPageViewData(pageData: Record) { + const page_location = this._window?.getUrl(); + const clientDocument = this._window?.getDocument(); + const page_referrer = this.#referrer || clientDocument?.referrer; + return { - page: pageData.path, - location: this._window.getUrl(), - title: document.title || '', + page_path: pageData.path, + page_location, + page_referrer, + page_route: pageData?.route?.getName() || '', + page_status: pageData?.response?.status, + page_title: clientDocument?.title || '', }; } diff --git a/packages/plugin-analytic-google/src/__tests__/GoogleAnalytics4Spec.js b/packages/plugin-analytic-google/src/__tests__/GoogleAnalytics4Spec.js index 7848effe..310a866c 100644 --- a/packages/plugin-analytic-google/src/__tests__/GoogleAnalytics4Spec.js +++ b/packages/plugin-analytic-google/src/__tests__/GoogleAnalytics4Spec.js @@ -10,24 +10,37 @@ describe('GoogleAnalytics4', () => { consentSettings: {}, }; - const mockGtag = { + let mockDocument; + + function setMockDocument(document = {}) { + mockDocument = { ...document }; + global.document = mockDocument; + } + + const mockWindow = { gtag: jest.fn(), }; const mockUrl = 'mockUrl'; const scriptLoader = toMockedInstance(ScriptLoaderPlugin); const dispatcher = toMockedInstance(Dispatcher); - const window = toMockedInstance(Window, { - getWindow() { - return mockGtag; - }, - getUrl() { - return mockUrl; - }, - }); + let googleAnalytics4 = null; beforeEach(() => { + setMockDocument(); + const window = toMockedInstance(Window, { + getDocument() { + return mockDocument; + }, + getWindow() { + return mockWindow; + }, + getUrl() { + return mockUrl; + }, + }); + googleAnalytics4 = new GoogleAnalytics4( settings, scriptLoader, @@ -47,17 +60,26 @@ describe('GoogleAnalytics4', () => { const pageTitle = 'Page title'; const mockPath = 'somePath'; + const mockReferrer = 'https://google.com'; - global.document = { + setMockDocument({ title: pageTitle, - }; + referrer: mockReferrer, + }); - googleAnalytics4.hitPageView({ path: mockPath }); + googleAnalytics4.hitPageView({ + path: mockPath, + response: { status: 200 }, + route: { getName: () => 'someRoute' }, + }); - expect(mockGtag.gtag).toHaveBeenCalledWith('event', 'page_view', { - location: mockUrl, - page: mockPath, - title: pageTitle, + expect(mockWindow.gtag).toHaveBeenCalledWith('event', 'page_view', { + page_location: mockUrl, + page_path: mockPath, + page_title: pageTitle, + page_referrer: mockReferrer, + page_route: 'someRoute', + page_status: 200, }); }); }); @@ -74,7 +96,7 @@ describe('GoogleAnalytics4', () => { googleAnalytics4.hit(customEventName, customEventData); - expect(mockGtag.gtag).toHaveBeenCalledWith( + expect(mockWindow.gtag).toHaveBeenCalledWith( 'event', customEventName, customEventData @@ -116,7 +138,7 @@ describe('GoogleAnalytics4', () => { googleAnalytics4.updateConsent(purposeConsents); - expect(mockGtag.gtag).toHaveBeenCalledWith( + expect(mockWindow.gtag).toHaveBeenCalledWith( 'consent', 'update', expect.any(Object) diff --git a/packages/plugin-analytic-google/src/main.ts b/packages/plugin-analytic-google/src/main.ts index 795f3efc..9e2d73f7 100644 --- a/packages/plugin-analytic-google/src/main.ts +++ b/packages/plugin-analytic-google/src/main.ts @@ -14,7 +14,10 @@ pluginLoader.register('@ima/plugin-analytic-google', () => ({ consentSettings: { ad_storage: 'denied', analytics_storage: 'denied', + functionality_storage: 'denied', personalization_storage: 'denied', + security_storage: 'denied', + ad_user_data: 'denied', }, service: 'G-XXXXXXXXXX', waitForUpdateTimeout: 5000,