From 309dac3873e3404d4e52ba9b6958ab3e194b07b1 Mon Sep 17 00:00:00 2001 From: Kelson Warner Date: Fri, 18 Sep 2020 17:53:01 -0700 Subject: [PATCH] feat: add logAttributionCapturedEvent option (#295) * GROWTH-1094 add logAttributionCapturedEvent option to log Amplitude Events when attribution data is captured * Add spread property * Revert changes to test html * Rename ATTRIBUTION_EVENT to * GROWTH-1094 add missing semicolon * Rename ATTRIBUTION_CAPTURED * Add tests for feature --- src/amplitude-client.js | 22 +++++++-- src/constants.js | 4 +- src/options.js | 1 + test/amplitude-client.js | 103 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 126 insertions(+), 4 deletions(-) diff --git a/src/amplitude-client.js b/src/amplitude-client.js index 78722ddd..dab89062 100644 --- a/src/amplitude-client.js +++ b/src/amplitude-client.js @@ -354,14 +354,27 @@ AmplitudeClient.prototype._migrateUnsentEvents = function _migrateUnsentEvents(c * @private */ AmplitudeClient.prototype._trackParamsAndReferrer = function _trackParamsAndReferrer() { + let utmProperties; + let referrerProperties; + let gclidProperties; if (this.options.includeUtm) { - this._initUtmData(); + utmProperties = this._initUtmData(); } if (this.options.includeReferrer) { - this._saveReferrer(this._getReferrer()); + referrerProperties = this._saveReferrer(this._getReferrer()); } if (this.options.includeGclid) { - this._saveGclid(this._getUrlParams()); + gclidProperties = this._saveGclid(this._getUrlParams()); + } + if (this.options.logAttributionCapturedEvent) { + const attributionProperties = { + ...utmProperties, + ...referrerProperties, + ...gclidProperties, + }; + if (Object.keys(attributionProperties).length > 0) { + this.logEvent(Constants.ATTRIBUTION_EVENT, attributionProperties); + } } }; @@ -675,6 +688,7 @@ AmplitudeClient.prototype._initUtmData = function _initUtmData(queryParams, cook cookieParams = cookieParams || this.cookieStorage.get('__utmz'); var utmProperties = getUtmData(cookieParams, queryParams); _sendParamsReferrerUserProperties(this, utmProperties); + return utmProperties; }; /** @@ -739,6 +753,7 @@ AmplitudeClient.prototype._saveGclid = function _saveGclid(urlParams) { } var gclidProperties = {'gclid': gclid}; _sendParamsReferrerUserProperties(this, gclidProperties); + return gclidProperties; }; /** @@ -778,6 +793,7 @@ AmplitudeClient.prototype._saveReferrer = function _saveReferrer(referrer) { 'referring_domain': this._getReferringDomain(referrer) }; _sendParamsReferrerUserProperties(this, referrerInfo); + return referrerInfo; }; /** diff --git a/src/constants.js b/src/constants.js index 45bf6984..96fc6f10 100644 --- a/src/constants.js +++ b/src/constants.js @@ -37,5 +37,7 @@ export default { UTM_MEDIUM: 'utm_medium', UTM_CAMPAIGN: 'utm_campaign', UTM_TERM: 'utm_term', - UTM_CONTENT: 'utm_content' + UTM_CONTENT: 'utm_content', + + ATTRIBUTION_EVENT: '[Amplitude] Attribution Captured' }; diff --git a/src/options.js b/src/options.js index 0b16980d..8e4ae039 100644 --- a/src/options.js +++ b/src/options.js @@ -30,6 +30,7 @@ export default { includeUtm: false, language: language.getLanguage(), logLevel: 'WARN', + logAttributionCapturedEvent: false, optOut: false, onError: () => {}, platform, diff --git a/test/amplitude-client.js b/test/amplitude-client.js index e79b42c9..d370e95c 100644 --- a/test/amplitude-client.js +++ b/test/amplitude-client.js @@ -2952,6 +2952,32 @@ describe('setVersionName', function() { }); }); + it('should log attribution event when referrer is updated if configured', function() { + clock.tick(30 * 60 * 1000 + 1); // force new session + amplitude.init(apiKey, undefined, {includeReferrer: true, logAttributionCapturedEvent: true, batchEvents: true, eventUploadThreshold: 2}); + assert.lengthOf(server.requests, 1); + var events = JSON.parse(queryString.parse(server.requests[0].requestBody).e); + assert.lengthOf(events, 2); + // first event should be identify with initial_referrer and referrer + assert.equal(events[0].event_type, '$identify'); + assert.deepEqual(events[0].user_properties, { + '$set': { + 'referrer': 'https://amplitude.com/contact', + 'referring_domain': 'amplitude.com' + }, + '$setOnce': { + 'initial_referrer': 'https://amplitude.com/contact', + 'initial_referring_domain': 'amplitude.com' + } + }); + // second event should be the attribution captured event with referrer information + assert.equal(events[1].event_type, constants.ATTRIBUTION_EVENT); + assert.deepEqual(events[1].event_properties, { + 'referrer': 'https://amplitude.com/contact', + 'referring_domain': 'amplitude.com' + }); + }); + it('should not delete unsent events saved to localStorage', function() { var existingEvent = '[{"device_id":"test_device_id","user_id":"test_user_id","timestamp":1453769146589,' + '"event_id":49,"session_id":1453763315544,"event_type":"clicked","version_name":"Web","platform":"Web"' + @@ -2993,6 +3019,62 @@ describe('setVersionName', function() { } }); }); + + it('should log attribution event when UTMs are captured if configured', function() { + reset(); + cookie.set('__utmz', '133232535.1424926227.1.1.utmcct=top&utmccn=new'); + clock.tick(30 * 60 * 1000 + 1); + amplitude.init(apiKey, undefined, {includeUtm: true, logAttributionCapturedEvent: true, batchEvents: true, eventUploadThreshold: 2}); + assert.lengthOf(server.requests, 1); + var events = JSON.parse(queryString.parse(server.requests[0].requestBody).e); + // first event should be identify with UTM state + assert.equal(events[0].event_type, '$identify'); + assert.deepEqual(events[0].user_properties, { + '$setOnce': { + initial_utm_campaign: 'new', + initial_utm_content: 'top' + }, + '$set': { + utm_campaign: 'new', + utm_content: 'top' + } + }); + // second event should be the attribution captured event with UTMs populated + assert.equal(events[1].event_type, constants.ATTRIBUTION_EVENT); + assert.deepEqual(events[1].event_properties, { + utm_campaign: 'new', + utm_content: 'top' + }); + }); + + it('should log attribution event more than once per session if configured and UTMs changes', function() { + reset(); + cookie.set('__utmz', '133232535.1424926227.1.1.utmcct=top&utmccn=new'); + amplitude.init(apiKey, undefined, { + includeUtm: true, logAttributionCapturedEvent: true, saveParamsReferrerOncePerSession: false, batchEvents: true, eventUploadThreshold: 2 + }); + // even though same session, utm params are sent again + assert.lengthOf(server.requests, 1); + var events = JSON.parse(queryString.parse(server.requests[0].requestBody).e); + // first event should be identify with UTM state + assert.equal(events[0].event_type, '$identify'); + assert.deepEqual(events[0].user_properties, { + '$setOnce': { + initial_utm_campaign: 'new', + initial_utm_content: 'top' + }, + '$set': { + utm_campaign: 'new', + utm_content: 'top' + } + }); + // second event should be the attribution captured event with UTMs populated + assert.equal(events[1].event_type, constants.ATTRIBUTION_EVENT); + assert.deepEqual(events[1].event_properties, { + utm_campaign: 'new', + utm_content: 'top' + }); + }); }); describe('gatherGclid', function() { @@ -3050,6 +3132,27 @@ describe('setVersionName', function() { '$setOnce': {'initial_gclid': '12345'} }); }); + + it('should log attribution event when gclid is captured if configured', () => { + clock.tick(30 * 60 * 1000 + 1); + amplitude.init(apiKey, undefined, {includeGclid: true, logAttributionCapturedEvent: true, batchEvents: true, eventUploadThreshold: 2}); + + assert.lengthOf(server.requests, 1); + var events = JSON.parse(queryString.parse(server.requests[0].requestBody).e); + assert.lengthOf(events, 2); + + // first event should be identify with gclid + assert.equal(events[0].event_type, '$identify'); + assert.deepEqual(events[0].user_properties, { + '$set': {'gclid': '12345'}, + '$setOnce': {'initial_gclid': '12345'} + }); + // second event should be the attribution captured event with gclid populated + assert.equal(events[1].event_type, constants.ATTRIBUTION_EVENT); + assert.deepEqual(events[1].event_properties, { + 'gclid': '12345' + }) + }); }); describe('logRevenue', function() {