Skip to content

Commit 3eff3eb

Browse files
Revise to use integration attributes
1 parent bbc1a63 commit 3eff3eb

File tree

4 files changed

+148
-14
lines changed

4 files changed

+148
-14
lines changed

src/integrationCapture.ts

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { SDKEventCustomFlags } from './sdkRuntimeModels';
2+
import { IntegrationAttributes } from './store';
23
import {
34
Dictionary,
45
queryStringParser,
@@ -53,16 +54,19 @@ export const facebookClickIdProcessor: IntegrationCaptureProcessorFunction = (
5354
// Integration outputs are used to determine how click ids are used within the SDK
5455
// CUSTOM_FLAGS are sent out when an Event is created via ServerModel.createEventObject
5556
// PARTNER_IDENTITIES are sent out in a Batch when a group of events are converted to a Batch
57+
// INTEGRATION_ATTRIBUTES are stored on the event level but are also passed up to the Batch
5658

5759
const IntegrationOutputs = {
5860
CUSTOM_FLAGS: 'custom_flags',
5961
PARTNER_IDENTITIES: 'partner_identities',
62+
INTEGRATION_ATTRIBUTES: 'integration_attributes',
6063
} as const;
6164

6265
interface IntegrationMappingItem {
6366
mappedKey: string;
6467
output: valueof<typeof IntegrationOutputs>;
6568
processor?: IntegrationCaptureProcessorFunction;
69+
moduleId?: number;
6670
}
6771

6872
interface IntegrationIdMapping {
@@ -101,8 +105,9 @@ const integrationMapping: IntegrationIdMapping = {
101105

102106
// Rokt
103107
rtid: {
104-
mappedKey: 'Rokt.ClickId',
105-
output: IntegrationOutputs.CUSTOM_FLAGS,
108+
mappedKey: 'rokt_id',
109+
output: IntegrationOutputs.INTEGRATION_ATTRIBUTES,
110+
moduleId: 1277,
106111
},
107112

108113
// TIKTOK
@@ -121,13 +126,15 @@ export default class IntegrationCapture {
121126
public readonly initialTimestamp: number;
122127
public readonly filteredPartnerIdentityMappings: IntegrationIdMapping;
123128
public readonly filteredCustomFlagMappings: IntegrationIdMapping;
129+
public readonly filteredIntegrationAttributeMappings: IntegrationIdMapping;
124130

125131
constructor() {
126132
this.initialTimestamp = Date.now();
127133

128134
// Cache filtered mappings for faster access
129135
this.filteredPartnerIdentityMappings = this.filterMappings(IntegrationOutputs.PARTNER_IDENTITIES);
130136
this.filteredCustomFlagMappings = this.filterMappings(IntegrationOutputs.CUSTOM_FLAGS);
137+
this.filteredIntegrationAttributeMappings = this.filterMappings(IntegrationOutputs.INTEGRATION_ATTRIBUTES);
131138
}
132139

133140
/**
@@ -186,6 +193,37 @@ export default class IntegrationCapture {
186193
return this.getClickIds(this.clickIds, this.filteredPartnerIdentityMappings);
187194
}
188195

196+
/**
197+
* Returns only the `integration_attributes` mapped integration output.
198+
* @returns {Dictionary<string>} The integration attributes.
199+
*/
200+
public getClickIdsAsIntegrationAttributes(): IntegrationAttributes {
201+
// Integration IDs are stored in the following format:
202+
// {
203+
// "integration_attributes": {
204+
// "<moduleId>": {
205+
// "mappedKey": "clickIdValue"
206+
// }
207+
// }
208+
// }
209+
const mappedClickIds: IntegrationAttributes = {};
210+
211+
for (const key in this.clickIds) {
212+
if (this.clickIds.hasOwnProperty(key)) {
213+
const value = this.clickIds[key];
214+
const mappingKey = this.filteredIntegrationAttributeMappings[key]?.mappedKey;
215+
if (!isEmpty(mappingKey)) {
216+
const moduleId = this.filteredIntegrationAttributeMappings[key]?.moduleId;
217+
if (moduleId && !mappedClickIds[moduleId]) {
218+
mappedClickIds[moduleId] = { [mappingKey]: value };
219+
}
220+
}
221+
}
222+
}
223+
return mappedClickIds;
224+
}
225+
226+
189227
private getClickIds(
190228
clickIds: Dictionary<string>,
191229
mappingList: IntegrationIdMapping

src/serverModel.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
Dictionary,
1818
isValidCustomFlagProperty,
1919
} from './utils';
20-
import { ServerSettings } from './store';
20+
import { IntegrationAttributes, ServerSettings } from './store';
2121
import { MPID } from '@mparticle/web-sdk';
2222
import {
2323
IConsentStateV2DTO,
@@ -319,6 +319,7 @@ export default function ServerModel(
319319
mpInstance._Store.webviewBridgeEnabled
320320
) {
321321
let customFlags: SDKEventCustomFlags = {...event.customFlags};
322+
let integrationAttributes: IntegrationAttributes = mpInstance._Store.integrationAttributes;
322323

323324
// https://go.mparticle.com/work/SQDSDKS-5053
324325
if (mpInstance._Helpers.getFeatureFlag && mpInstance._Helpers.getFeatureFlag(Constants.FeatureFlags.CaptureIntegrationSpecificIds)) {
@@ -328,6 +329,9 @@ export default function ServerModel(
328329
mpInstance._IntegrationCapture.capture();
329330
const transformedClickIDs = mpInstance._IntegrationCapture.getClickIdsAsCustomFlags();
330331
customFlags = {...transformedClickIDs, ...customFlags};
332+
333+
const transformedIntegrationAttributes = mpInstance._IntegrationCapture.getClickIdsAsIntegrationAttributes();
334+
integrationAttributes = {...transformedIntegrationAttributes, ...integrationAttributes};
331335
}
332336

333337
if (event.hasOwnProperty('toEventAPIObject')) {
@@ -378,7 +382,7 @@ export default function ServerModel(
378382
Package: mpInstance._Store.SDKConfig.package,
379383
ClientGeneratedId: mpInstance._Store.clientId,
380384
DeviceId: mpInstance._Store.deviceId,
381-
IntegrationAttributes: mpInstance._Store.integrationAttributes,
385+
IntegrationAttributes: integrationAttributes,
382386
CurrencyCode: mpInstance._Store.currencyCode,
383387
DataPlan: mpInstance._Store.SDKConfig.dataPlan
384388
? mpInstance._Store.SDKConfig.dataPlan

test/jest/integration-capture.spec.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,15 @@ describe.only('Integration Capture', () => {
2626
'gclid',
2727
'gbraid',
2828
'wbraid',
29-
'rtid',
3029
'ttclid',
3130
]);
3231
});
32+
33+
it('should initialize with a filtered list of integration attribute mappings', () => {
34+
const integrationCapture = new IntegrationCapture();
35+
const mappings = integrationCapture.filteredIntegrationAttributeMappings;
36+
expect(Object.keys(mappings)).toEqual(['rtid']);
37+
});
3338
});
3439

3540
describe('#capture', () => {
@@ -381,6 +386,30 @@ describe.only('Integration Capture', () => {
381386
});
382387
});
383388

389+
describe('#getClickIdsAsIntegrationAttributes', () => {
390+
it('should return empty object if clickIds is empty or undefined', () => {
391+
const integrationCapture = new IntegrationCapture();
392+
const integrationAttributes = integrationCapture.getClickIdsAsIntegrationAttributes();
393+
394+
expect(integrationAttributes).toEqual({});
395+
});
396+
397+
it('should only return mapped clickIds as integration attributes', () => {
398+
const integrationCapture = new IntegrationCapture();
399+
integrationCapture.clickIds = {
400+
rtid: '12345',
401+
};
402+
403+
const integrationAttributes = integrationCapture.getClickIdsAsIntegrationAttributes();
404+
405+
expect(integrationAttributes).toEqual({
406+
'1277': {
407+
'rokt_id': '12345',
408+
}
409+
});
410+
});
411+
});
412+
384413
describe('#facebookClickIdProcessor', () => {
385414
it('returns a formatted clickId if it is passed in as a partial click id', () => {
386415
const partialClickId = 'AbCdEfGhIjKlMnOpQrStUvWxYz1234567890';

test/src/tests-integration-capture.ts

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ describe('Integration Capture', () => {
7777
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234');
7878
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574');
7979
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111');
80-
expect(testEvent.data.custom_flags['Rokt.ClickId'], 'Rokt Click Id').to.equal('45670808');
8180
});
8281

8382
it('should add captured integrations to event custom flags, prioritizing passed in custom flags', async () => {
@@ -100,7 +99,6 @@ describe('Integration Capture', () => {
10099
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234');
101100
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574');
102101
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111');
103-
expect(testEvent.data.custom_flags['Rokt.ClickId'], 'Rokt Click Id').to.equal('45670808');
104102
});
105103

106104
it('should add captured integrations to page view custom flags', async () => {
@@ -124,7 +122,6 @@ describe('Integration Capture', () => {
124122
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234');
125123
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574');
126124
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111');
127-
expect(testEvent.data.custom_flags['Rokt.ClickId'], 'Rokt Click Id').to.equal('45670808');
128125
});
129126

130127
it('should add captured integrations to page view custom flags, prioritizing passed in custom flags', async () => {
@@ -146,7 +143,6 @@ describe('Integration Capture', () => {
146143
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234');
147144
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574');
148145
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111');
149-
expect(testEvent.data.custom_flags['Rokt.ClickId'], 'Rokt Click Id').to.equal('45670808');
150146
});
151147

152148
it('should add captured integrations to commerce event custom flags', async () => {
@@ -184,7 +180,6 @@ describe('Integration Capture', () => {
184180
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234');
185181
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574');
186182
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111');
187-
expect(testEvent.data.custom_flags['Rokt.ClickId'], 'Rokt Click Id').to.equal('45670808');
188183
});
189184

190185
it('should add captured integrations to commerce event custom flags, prioritizing passed in flags', async () => {
@@ -222,7 +217,6 @@ describe('Integration Capture', () => {
222217
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234');
223218
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574');
224219
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111');
225-
expect(testEvent.data.custom_flags['Rokt.ClickId'], 'Rokt Click Id').to.equal('45670808');
226220
});
227221

228222
it('should add captured integrations to commerce event custom flags', async () => {
@@ -260,7 +254,6 @@ describe('Integration Capture', () => {
260254
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234');
261255
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574');
262256
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111');
263-
expect(testEvent.data.custom_flags['Rokt.ClickId'], 'Rokt Click Id').to.equal('45670808');
264257
});
265258

266259
it('should add captured integrations to commerce event custom flags, prioritizing passed in flags', async () => {
@@ -298,10 +291,9 @@ describe('Integration Capture', () => {
298291
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gclid'], 'Google Enhanced Conversions Gclid').to.equal('234');
299292
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Gbraid'], 'Google Enhanced Conversions Gbraid').to.equal('6574');
300293
expect(testEvent.data.custom_flags['GoogleEnhancedConversions.Wbraid'], 'Google Enhanced Conversions Wbraid').to.equal('1234111');
301-
expect(testEvent.data.custom_flags['Rokt.ClickId'], 'Rokt Click Id').to.equal('45670808');
302294
});
303295

304-
it('should add captured integrations to batch partner identities', async () => {
296+
it('should add captured integrations to batch as partner identities', async () => {
305297
await waitForCondition(hasIdentityCallInflightReturned);
306298

307299
window.mParticle.logEvent('Test Event 1');
@@ -321,4 +313,75 @@ describe('Integration Capture', () => {
321313
});
322314

323315
});
316+
317+
it('should add captured integrations to batch as integration attributes', async () => {
318+
await waitForCondition(hasIdentityCallInflightReturned);
319+
320+
window.mParticle.logEvent('Test Event 1');
321+
window.mParticle.logEvent('Test Event 2');
322+
window.mParticle.logEvent('Test Event 3');
323+
324+
window.mParticle.upload();
325+
326+
expect(fetchMock.calls().length).to.greaterThan(1);
327+
328+
const lastCall = fetchMock.lastCall();
329+
const batch = JSON.parse(lastCall[1].body as string);
330+
331+
expect(batch).to.have.property('integration_attributes');
332+
expect(batch.integration_attributes['1277']).to.deep.equal({
333+
'rokt_id': '45670808',
334+
});
335+
});
336+
337+
it('should add captured integrations to batch as integration attributes without colliding with set integration attributes', async () => {
338+
await waitForCondition(hasIdentityCallInflightReturned);
339+
340+
window.mParticle.setIntegrationAttribute(160, { 'client_id': '12354'});
341+
342+
window.mParticle.logEvent('Test Event 1');
343+
window.mParticle.logEvent('Test Event 2');
344+
window.mParticle.logEvent('Test Event 3');
345+
346+
window.mParticle.upload();
347+
348+
expect(fetchMock.calls().length).to.greaterThan(1);
349+
350+
const lastCall = fetchMock.lastCall();
351+
const batch = JSON.parse(lastCall[1].body as string);
352+
353+
expect(batch).to.have.property('integration_attributes');
354+
expect(batch.integration_attributes).to.have.property('1277');
355+
expect(batch.integration_attributes).to.have.property('160');
356+
expect(batch.integration_attributes['1277']).to.deep.equal({
357+
'rokt_id': '45670808',
358+
});
359+
expect(batch.integration_attributes['160']).to.deep.equal({
360+
'client_id': '12354',
361+
});
362+
363+
});
364+
365+
it('should add captured integrations to batch as integration attributes, prioritizing passed in integration attributes', async () => {
366+
await waitForCondition(hasIdentityCallInflightReturned);
367+
368+
window.mParticle.setIntegrationAttribute(1277, { 'rokt_id': 'passed-in'});
369+
window.mParticle.setIntegrationAttribute(160, { 'client_id': '12354'});
370+
371+
window.mParticle.logEvent('Test Event 1');
372+
window.mParticle.logEvent('Test Event 2');
373+
window.mParticle.logEvent('Test Event 3');
374+
375+
window.mParticle.upload();
376+
377+
expect(fetchMock.calls().length).to.greaterThan(1);
378+
379+
const lastCall = fetchMock.lastCall();
380+
const batch = JSON.parse(lastCall[1].body as string);
381+
382+
expect(batch).to.have.property('integration_attributes');
383+
expect(batch.integration_attributes['1277']).to.deep.equal({
384+
'rokt_id': 'passed-in',
385+
});
386+
});
324387
});

0 commit comments

Comments
 (0)