Skip to content

Commit 9ba6cf2

Browse files
Add client_session context entity if anonymous tracking with session tracking is enabled (close #1124)
PR #1135
1 parent 68221b5 commit 9ba6cf2

File tree

5 files changed

+110
-13
lines changed

5 files changed

+110
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@snowplow/browser-tracker-core",
5+
"comment": "Add client_session context entity if anonymous tracking with session tracking is enabled (#1124)",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@snowplow/browser-tracker-core"
10+
}

libraries/browser-tracker-core/src/tracker/id_cookie.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -300,14 +300,20 @@ export function serializeIdCookie(idCookie: ParsedIdCookie) {
300300
* @param configStateStorageStrategy Cookie storage strategy
301301
* @returns Client session context entity
302302
*/
303-
export function clientSessionFromIdCookie(idCookie: ParsedIdCookie, configStateStorageStrategy: string) {
303+
export function clientSessionFromIdCookie(
304+
idCookie: ParsedIdCookie,
305+
configStateStorageStrategy: string,
306+
configAnonymousTracking: boolean
307+
) {
304308
const firstEventTsInMs = idCookie[firstEventTsInMsIndex];
305309
const clientSession: ClientSession = {
306-
userId: idCookie[domainUserIdIndex],
310+
userId: configAnonymousTracking
311+
? '00000000-0000-0000-0000-000000000000' // TODO: use uuid.NIL when we upgrade to uuid v8.3
312+
: idCookie[domainUserIdIndex],
307313
sessionId: idCookie[sessionIdIndex],
308314
eventIndex: idCookie[eventIndexIndex],
309315
sessionIndex: idCookie[visitCountIndex],
310-
previousSessionId: idCookie[previousSessionIdIndex] || null,
316+
previousSessionId: configAnonymousTracking ? null : idCookie[previousSessionIdIndex] || null,
311317
storageMechanism: configStateStorageStrategy == 'localStorage' ? 'LOCAL_STORAGE' : 'COOKIE_1',
312318
firstEventId: idCookie[firstEventIdIndex] || null,
313319
firstEventTimestamp: firstEventTsInMs ? new Date(firstEventTsInMs).toISOString() : null,

libraries/browser-tracker-core/src/tracker/index.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -787,8 +787,11 @@ export function Tracker(
787787
// Add the page URL last as it may take us over the IE limit (and we don't always need it)
788788
payloadBuilder.add('url', purify(configCustomUrl || locationHrefAlias));
789789

790-
if (configSessionContext && !configAnonymousSessionTracking && !configAnonymousTracking) {
791-
addSessionContextToPayload(payloadBuilder, clientSessionFromIdCookie(idCookie, configStateStorageStrategy));
790+
if (configSessionContext && (!configAnonymousTracking || configAnonymousSessionTracking)) {
791+
addSessionContextToPayload(
792+
payloadBuilder,
793+
clientSessionFromIdCookie(idCookie, configStateStorageStrategy, configAnonymousTracking)
794+
);
792795
}
793796

794797
// Update cookies

libraries/browser-tracker-core/test/id_cookie.test.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ describe('serializeIdCookie', () => {
262262
describe('clientSessionFromIdCookie', () => {
263263
it('Correctly fills out the properties', () => {
264264
let idCookie = parseIdCookie('def.1653632272.10.1653632282.1653632262.ses.previous.fid.1653638673483.9', '', '', 0);
265-
let clientSession = clientSessionFromIdCookie(idCookie, 'cookieAndLocalStorage');
265+
let clientSession = clientSessionFromIdCookie(idCookie, 'cookieAndLocalStorage', false);
266266

267267
expect(clientSession.userId).toBe('def');
268268
expect(clientSession.sessionId).toBe('ses');
@@ -273,4 +273,18 @@ describe('clientSessionFromIdCookie', () => {
273273
expect(clientSession.firstEventId).toBe('fid');
274274
expect(clientSession.firstEventTimestamp).toBe('2022-05-27T08:04:33.483Z');
275275
});
276+
277+
it('Anonymises userId and previousSessionId when anonymous tracking', () => {
278+
let idCookie = parseIdCookie('def.1653632272.10.1653632282.1653632262.ses.previous.fid.1653638673483.9', '', '', 0);
279+
let clientSession = clientSessionFromIdCookie(idCookie, 'cookieAndLocalStorage', true);
280+
281+
expect(clientSession.userId).toBe('00000000-0000-0000-0000-000000000000');
282+
expect(clientSession.sessionId).toBe('ses');
283+
expect(clientSession.previousSessionId).toBeNull;
284+
expect(clientSession.eventIndex).toBe(9);
285+
expect(clientSession.sessionIndex).toBe(10);
286+
expect(clientSession.storageMechanism).toBe('COOKIE_1');
287+
expect(clientSession.firstEventId).toBe('fid');
288+
expect(clientSession.firstEventTimestamp).toBe('2022-05-27T08:04:33.483Z');
289+
});
276290
});

libraries/browser-tracker-core/test/tracker/session_data.test.ts

+71-7
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2929
*/
3030

31+
import { TrackerConfiguration } from '../../dist/index.module';
3132
import { addTracker, SharedState } from '../../src';
3233
import { createTestIdCookie, createTestSessionIdCookie } from '../helpers';
3334

@@ -54,45 +55,45 @@ describe('Tracker API: ', () => {
5455
});
5556

5657
it('Sets initial domain session index on first session', () => {
57-
const tracker = addTracker('sp1', 'sp1', '', '', new SharedState());
58+
const tracker = createTracker();
5859

5960
expect(tracker?.getDomainSessionIndex()).toEqual(1);
6061
});
6162

6263
it('Sets correct domain session index on new session', () => {
6364
const initialSessionIndex = 1;
6465
document.cookie = createTestIdCookie({ visitCount: initialSessionIndex });
65-
const tracker = addTracker('sp2', 'sp2', '', '', new SharedState());
66+
const tracker = createTracker();
6667

6768
expect(tracker?.getDomainSessionIndex()).toEqual(initialSessionIndex + 1);
6869
});
6970

7071
it('Sets correct domain session index on existing session', () => {
7172
const initialSessionIndex = 2;
7273
document.cookie = createTestIdCookie({ visitCount: initialSessionIndex }) + ' ' + createTestSessionIdCookie();
73-
const tracker = addTracker('sp3', 'sp3', '', '', new SharedState());
74+
const tracker = createTracker();
7475

7576
expect(tracker?.getDomainSessionIndex()).toEqual(initialSessionIndex);
7677
});
7778

7879
it('Sets correct domain session index (1) after clearUserData() on existing session', () => {
7980
const initialSessionIndex = 2;
8081
document.cookie = createTestIdCookie({ visitCount: initialSessionIndex }) + ' ' + createTestSessionIdCookie();
81-
const tracker = addTracker('sp4', 'sp4', '', '', new SharedState());
82+
const tracker = createTracker();
8283
expect(tracker?.getDomainSessionIndex()).toEqual(initialSessionIndex);
8384

8485
tracker?.clearUserData();
8586
expect(tracker?.getDomainSessionIndex()).toEqual(1);
8687
});
8788

8889
it('Sets correct domain session index anonymous track', () => {
89-
const tracker = addTracker('sp5', 'sp5', '', '', new SharedState(), { anonymousTracking: true });
90+
const tracker = createTracker({ anonymousTracking: true });
9091
expect(tracker?.getDomainSessionIndex()).toEqual(1);
9192
});
9293

9394
it('Retains correct domain session index on opt-out cookie present', () => {
9495
const optOutCookieName = 'optOut';
95-
const tracker = addTracker('sp6', 'sp6', '', '', new SharedState());
96+
const tracker = createTracker();
9697
tracker?.setOptOutCookie(optOutCookieName);
9798
document.cookie = `${optOutCookieName}=1;`;
9899

@@ -102,10 +103,73 @@ describe('Tracker API: ', () => {
102103

103104
it('Sets correct domain session index after session expiration', () => {
104105
// Session timeout is in seconds
105-
const tracker = addTracker('sp7', 'sp7', '', '', new SharedState(), { sessionCookieTimeout: 1 });
106+
const tracker = createTracker({ sessionCookieTimeout: 1 });
106107
// Advance timer by more than one second
107108
jest.advanceTimersByTime(1001);
108109
tracker?.trackPageView({ title: 'my page' });
109110
expect(tracker?.getDomainSessionIndex()).toEqual(2);
110111
});
112+
113+
it('Adds the client session context entity when enabled', (done) => {
114+
const tracker = createTracker({
115+
contexts: { session: true },
116+
encodeBase64: false,
117+
plugins: [
118+
{
119+
afterTrack: (payload) => {
120+
let context = payload.co as string;
121+
expect(context).toContain('client_session');
122+
done();
123+
},
124+
},
125+
],
126+
});
127+
128+
tracker?.trackPageView();
129+
});
130+
131+
it('Adds the client session context entity when anonymous session tracking', (done) => {
132+
const tracker = createTracker({
133+
contexts: { session: true },
134+
encodeBase64: false,
135+
anonymousTracking: { withSessionTracking: true },
136+
plugins: [
137+
{
138+
afterTrack: (payload) => {
139+
let context = payload.co as string;
140+
expect(context).toContain('client_session');
141+
expect(context).toContain('"userId":"00000000-0000-0000-0000-000000000000"');
142+
expect(context).toContain('"previousSessionId":null');
143+
done();
144+
},
145+
},
146+
],
147+
});
148+
149+
tracker?.trackPageView();
150+
});
151+
152+
it("Doesn't add the client session context entity when anonymous tracking without session tracking", (done) => {
153+
const tracker = createTracker({
154+
contexts: { session: true },
155+
encodeBase64: false,
156+
anonymousTracking: true,
157+
plugins: [
158+
{
159+
afterTrack: (payload) => {
160+
let context = payload.co as string;
161+
expect(context).not.toContain('client_session');
162+
done();
163+
},
164+
},
165+
],
166+
});
167+
168+
tracker?.trackPageView();
169+
});
111170
});
171+
172+
function createTracker(configuration?: TrackerConfiguration) {
173+
let id = 'sp-' + Math.random();
174+
return addTracker(id, id, '', '', new SharedState(), configuration);
175+
}

0 commit comments

Comments
 (0)