diff --git a/packages/clarity-js/src/data/consent.ts b/packages/clarity-js/src/data/consent.ts new file mode 100644 index 00000000..52cfa24c --- /dev/null +++ b/packages/clarity-js/src/data/consent.ts @@ -0,0 +1,14 @@ +import { Event, ConsentData } from "@clarity-types/data"; +import * as core from "@src/core"; +import encode from "@src/data/encode"; + +export let data: ConsentData = null; + +export function consent(value: boolean): void { + if (core.active) { + data = { source: 2, value: value.toString() }; + + encode(Event.Consent); + } +} + diff --git a/packages/clarity-js/src/data/encode.ts b/packages/clarity-js/src/data/encode.ts index 17085e96..28c9f9ad 100644 --- a/packages/clarity-js/src/data/encode.ts +++ b/packages/clarity-js/src/data/encode.ts @@ -10,6 +10,7 @@ import * as summary from "@src/data/summary"; import * as upgrade from "@src/data/upgrade"; import * as variable from "@src/data/variable"; import * as extract from "@src/data/extract"; +import * as consent from "@src/data/consent"; import { queue, track } from "./upload"; export default function(event: Event): void { @@ -123,5 +124,10 @@ export default function(event: Event): void { extract.reset(); queue(tokens, false); + case Event.Consent: + tokens.push(consent.data.source); + tokens.push(consent.data.value); + queue(tokens); + break; } } diff --git a/packages/clarity-js/src/data/metadata.ts b/packages/clarity-js/src/data/metadata.ts index 85a43348..27f6fa1f 100644 --- a/packages/clarity-js/src/data/metadata.ts +++ b/packages/clarity-js/src/data/metadata.ts @@ -1,5 +1,5 @@ import { Time } from "@clarity-types/core"; -import { BooleanFlag, Constant, Dimension, Metadata, MetadataCallback, MetadataCallbackOptions, Metric, Session, User, Setting } from "@clarity-types/data"; +import { BooleanFlag, Constant, Dimension, Metadata, MetadataCallback, MetadataCallbackOptions, Metric, Session, User, Setting, Event } from "@clarity-types/data"; import * as clarity from "@src/clarity"; import * as core from "@src/core"; import config from "@src/core/config"; @@ -8,6 +8,7 @@ import * as scrub from "@src/core/scrub"; import * as dimension from "@src/data/dimension"; import * as metric from "@src/data/metric"; import { set } from "@src/data/variable"; +import * as trackConsent from "@src/data/consent"; export let data: Metadata = null; export let callbacks: MetadataCallbackOptions[] = []; @@ -62,13 +63,7 @@ export function start(): void { metric.max(Metric.ColorDepth, Math.round(screen.colorDepth)); } - // Read cookies specified in configuration - for (let key of config.cookies) { - let value = getCookie(key); - if (value) { set(key, value); } - } - - // Track ids using a cookie if configuration allows it + read(); track(u); } @@ -120,6 +115,8 @@ export function consent(status: boolean = true): void { if (core.active()) { config.track = true; track(user(), BooleanFlag.True); + save(); + trackConsent.consent(status); } } @@ -128,6 +125,14 @@ export function clear(): void { setCookie(Constant.SessionKey, Constant.Empty, 0); } +function read(): void { + // Read cookies specified in configuration + for (let key of config.cookies) { + let value = getCookie(key); + if (value) { set(key, value); } + } +} + function tab(): string { let id = shortid(); if (config.track && supported(window, Constant.SessionStorage)) { @@ -142,10 +147,14 @@ export function save(): void { let ts = Math.round(Date.now()); let upload = config.upload && typeof config.upload === Constant.String ? (config.upload as string).replace(Constant.HTTPS, Constant.Empty) : Constant.Empty; let upgrade = config.lean ? BooleanFlag.False : BooleanFlag.True; - processCallback(upgrade); setCookie(Constant.SessionKey, [data.sessionId, ts, data.pageNum, upgrade, upload].join(Constant.Pipe), Setting.SessionExpire); } +export function callback(): void { + let upgrade = config.lean ? BooleanFlag.False : BooleanFlag.True; + processCallback(upgrade); +} + function processCallback(upgrade: BooleanFlag) { if (callbacks.length > 0) { callbacks.forEach(x => { @@ -251,11 +260,11 @@ function getCookie(key: string): string { // * Cookie was previously not encoded by Clarity and browser encoded it once or more // * Cookie was previously encoded by Clarity and browser did not encode it let [isEncoded, decodedValue] = decodeCookieValue(pair[1]); - + while (isEncoded) { [isEncoded, decodedValue] = decodeCookieValue(decodedValue); } - + return decodedValue; } } diff --git a/packages/clarity-js/src/data/upgrade.ts b/packages/clarity-js/src/data/upgrade.ts index 0dd8b74c..4ff8d4d2 100644 --- a/packages/clarity-js/src/data/upgrade.ts +++ b/packages/clarity-js/src/data/upgrade.ts @@ -22,6 +22,7 @@ export function upgrade(key: string): void { data = { key }; // Update metadata to track we have upgraded this session + metadata.callback(); metadata.save(); // Callback upgrade handler, if configured diff --git a/packages/clarity-js/src/data/upload.ts b/packages/clarity-js/src/data/upload.ts index 8357d4a3..24b2222b 100644 --- a/packages/clarity-js/src/data/upload.ts +++ b/packages/clarity-js/src/data/upload.ts @@ -51,7 +51,7 @@ export function queue(tokens: Token[], transmit: boolean = true): void { case Event.Discover: discoverBytes += event.length; case Event.Box: - case Event.Mutation: + case Event.Mutation: case Event.Snapshot: case Event.StyleSheetAdoption: case Event.StyleSheetUpdate: @@ -125,7 +125,7 @@ async function upload(final: boolean = false): Promise { let a = `[${analysis.join()}]`; let p = sendPlaybackBytes ? `[${playback.join()}]` : Constant.Empty; - let encoded: EncodedPayload = {e, a, p}; + let encoded: EncodedPayload = { e, a, p }; // Get the payload ready for sending over the wire // We also attempt to compress the payload if it is not the last payload and the browser supports it @@ -241,7 +241,10 @@ function check(xhr: XMLHttpRequest, sequence: number): void { function done(sequence: number): void { // If we everything went successfully, and it is the first sequence, save this session for future reference - if (sequence === 1) { metadata.save(); } + if (sequence === 1) { + metadata.callback(); + metadata.save(); + } } function delay(): number { @@ -253,8 +256,7 @@ function delay(): number { function response(payload: string): void { let lines = payload && payload.length > 0 ? payload.split("\n") : []; - for (var line of lines) - { + for (var line of lines) { let parts = line && line.length > 0 ? line.split(/ (.*)/) : [Constant.Empty]; switch (parts[0]) { case Constant.End: diff --git a/packages/clarity-js/types/data.d.ts b/packages/clarity-js/types/data.d.ts index 0b573aec..1a6d4b3d 100644 --- a/packages/clarity-js/types/data.d.ts +++ b/packages/clarity-js/types/data.d.ts @@ -68,7 +68,8 @@ export const enum Event { Snapshot = 43, Animation = 44, StyleSheetAdoption = 45, - StyleSheetUpdate = 46 + StyleSheetUpdate = 46, + Consent = 47 } export const enum Metric { @@ -450,6 +451,11 @@ export interface UploadData { status: number; } +export interface ConsentData { + source: number; + value: string; +} + export interface ClaritySignal { type: string value?: number