@grainql/analytics-web 2.2.1 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/attribution.d.ts +47 -0
- package/dist/attribution.d.ts.map +1 -0
- package/dist/attribution.js +228 -0
- package/dist/cjs/attribution.d.ts +47 -0
- package/dist/cjs/attribution.d.ts.map +1 -0
- package/dist/cjs/attribution.js +228 -0
- package/dist/cjs/attribution.js.map +1 -0
- package/dist/cjs/countries.d.ts +13 -0
- package/dist/cjs/countries.d.ts.map +1 -0
- package/dist/cjs/countries.js +2907 -0
- package/dist/cjs/countries.js.map +1 -0
- package/dist/cjs/heartbeat.d.ts +1 -0
- package/dist/cjs/heartbeat.d.ts.map +1 -1
- package/dist/cjs/heartbeat.js +1 -1
- package/dist/cjs/heartbeat.js.map +1 -1
- package/dist/cjs/index.d.ts +26 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/page-tracking.d.ts +25 -0
- package/dist/cjs/page-tracking.d.ts.map +1 -1
- package/dist/cjs/page-tracking.js +162 -9
- package/dist/cjs/page-tracking.js.map +1 -1
- package/dist/countries.d.ts +13 -0
- package/dist/countries.d.ts.map +1 -0
- package/dist/countries.js +2907 -0
- package/dist/esm/attribution.d.ts +47 -0
- package/dist/esm/attribution.d.ts.map +1 -0
- package/dist/esm/attribution.js +218 -0
- package/dist/esm/attribution.js.map +1 -0
- package/dist/esm/countries.d.ts +13 -0
- package/dist/esm/countries.d.ts.map +1 -0
- package/dist/esm/countries.js +2902 -0
- package/dist/esm/countries.js.map +1 -0
- package/dist/esm/heartbeat.d.ts +1 -0
- package/dist/esm/heartbeat.d.ts.map +1 -1
- package/dist/esm/heartbeat.js +1 -1
- package/dist/esm/heartbeat.js.map +1 -1
- package/dist/esm/index.d.ts +26 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/page-tracking.d.ts +25 -0
- package/dist/esm/page-tracking.d.ts.map +1 -1
- package/dist/esm/page-tracking.js +162 -9
- package/dist/esm/page-tracking.js.map +1 -1
- package/dist/heartbeat.d.ts +1 -0
- package/dist/heartbeat.d.ts.map +1 -1
- package/dist/heartbeat.js +1 -1
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.global.dev.js +3361 -11
- package/dist/index.global.dev.js.map +3 -3
- package/dist/index.global.js +2 -2
- package/dist/index.global.js.map +4 -4
- package/dist/index.js +162 -1
- package/dist/index.mjs +157 -0
- package/dist/page-tracking.d.ts +25 -0
- package/dist/page-tracking.d.ts.map +1 -1
- package/dist/page-tracking.js +162 -9
- package/package.json +1 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attribution and Referral Tracking for Grain Analytics
|
|
3
|
+
* Handles referral categorization and first-touch attribution
|
|
4
|
+
*/
|
|
5
|
+
export type ReferrerCategory = 'organic' | 'paid' | 'social' | 'direct' | 'email' | 'referral';
|
|
6
|
+
export interface UTMParameters {
|
|
7
|
+
utm_source?: string;
|
|
8
|
+
utm_medium?: string;
|
|
9
|
+
utm_campaign?: string;
|
|
10
|
+
utm_term?: string;
|
|
11
|
+
utm_content?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface FirstTouchAttribution {
|
|
14
|
+
source: string;
|
|
15
|
+
medium: string;
|
|
16
|
+
campaign: string;
|
|
17
|
+
referrer: string;
|
|
18
|
+
referrer_category: ReferrerCategory;
|
|
19
|
+
timestamp: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Categorize referrer based on domain and parameters
|
|
23
|
+
*/
|
|
24
|
+
export declare function categorizeReferrer(referrer: string, currentUrl?: string): ReferrerCategory;
|
|
25
|
+
/**
|
|
26
|
+
* Parse UTM parameters from URL
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseUTMParameters(url: string): UTMParameters;
|
|
29
|
+
/**
|
|
30
|
+
* Get first-touch attribution from localStorage
|
|
31
|
+
*/
|
|
32
|
+
export declare function getFirstTouchAttribution(tenantId: string): FirstTouchAttribution | null;
|
|
33
|
+
/**
|
|
34
|
+
* Set first-touch attribution in localStorage
|
|
35
|
+
*/
|
|
36
|
+
export declare function setFirstTouchAttribution(tenantId: string, attribution: FirstTouchAttribution): void;
|
|
37
|
+
/**
|
|
38
|
+
* Get or create first-touch attribution
|
|
39
|
+
*/
|
|
40
|
+
export declare function getOrCreateFirstTouchAttribution(tenantId: string, referrer: string, currentUrl: string, utmParams: UTMParameters): FirstTouchAttribution;
|
|
41
|
+
export declare function getSessionUTMParameters(): UTMParameters | null;
|
|
42
|
+
export declare function setSessionUTMParameters(params: UTMParameters): void;
|
|
43
|
+
/**
|
|
44
|
+
* Clear session UTM parameters
|
|
45
|
+
*/
|
|
46
|
+
export declare function clearSessionUTMParameters(): void;
|
|
47
|
+
//# sourceMappingURL=attribution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attribution.d.ts","sourceRoot":"","sources":["../src/attribution.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;AAE/F,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,gBAAgB,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;CACnB;AAkFD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAE,MAAW,GAAG,gBAAgB,CAsC9F;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAqB7D;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI,CAgBvF;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,qBAAqB,GACjC,IAAI,CAWN;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,aAAa,GACvB,qBAAqB,CAwBvB;AAOD,wBAAgB,uBAAuB,IAAI,aAAa,GAAG,IAAI,CAE9D;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAEnE;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Attribution and Referral Tracking for Grain Analytics
|
|
4
|
+
* Handles referral categorization and first-touch attribution
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.categorizeReferrer = categorizeReferrer;
|
|
8
|
+
exports.parseUTMParameters = parseUTMParameters;
|
|
9
|
+
exports.getFirstTouchAttribution = getFirstTouchAttribution;
|
|
10
|
+
exports.setFirstTouchAttribution = setFirstTouchAttribution;
|
|
11
|
+
exports.getOrCreateFirstTouchAttribution = getOrCreateFirstTouchAttribution;
|
|
12
|
+
exports.getSessionUTMParameters = getSessionUTMParameters;
|
|
13
|
+
exports.setSessionUTMParameters = setSessionUTMParameters;
|
|
14
|
+
exports.clearSessionUTMParameters = clearSessionUTMParameters;
|
|
15
|
+
/**
|
|
16
|
+
* Known paid search parameters
|
|
17
|
+
*/
|
|
18
|
+
const PAID_SEARCH_PARAMS = [
|
|
19
|
+
'gclid', // Google Ads
|
|
20
|
+
'msclkid', // Microsoft Ads
|
|
21
|
+
'fbclid', // Facebook Ads
|
|
22
|
+
'ttclid', // TikTok Ads
|
|
23
|
+
'li_fat_id', // LinkedIn Ads
|
|
24
|
+
'twclid', // Twitter Ads
|
|
25
|
+
'ScCid', // Snapchat Ads
|
|
26
|
+
];
|
|
27
|
+
/**
|
|
28
|
+
* Known social media domains
|
|
29
|
+
*/
|
|
30
|
+
const SOCIAL_DOMAINS = [
|
|
31
|
+
'facebook.com',
|
|
32
|
+
'twitter.com',
|
|
33
|
+
'x.com',
|
|
34
|
+
'linkedin.com',
|
|
35
|
+
'instagram.com',
|
|
36
|
+
'pinterest.com',
|
|
37
|
+
'reddit.com',
|
|
38
|
+
'tiktok.com',
|
|
39
|
+
'youtube.com',
|
|
40
|
+
'snapchat.com',
|
|
41
|
+
't.co', // Twitter short links
|
|
42
|
+
'fb.me', // Facebook short links
|
|
43
|
+
'lnkd.in', // LinkedIn short links
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* Known organic search engines
|
|
47
|
+
*/
|
|
48
|
+
const SEARCH_ENGINES = [
|
|
49
|
+
'google.',
|
|
50
|
+
'bing.com',
|
|
51
|
+
'yahoo.com',
|
|
52
|
+
'duckduckgo.com',
|
|
53
|
+
'baidu.com',
|
|
54
|
+
'yandex.com',
|
|
55
|
+
'ecosia.org',
|
|
56
|
+
'ask.com',
|
|
57
|
+
];
|
|
58
|
+
/**
|
|
59
|
+
* Email client domains
|
|
60
|
+
*/
|
|
61
|
+
const EMAIL_DOMAINS = [
|
|
62
|
+
'mail.google.com',
|
|
63
|
+
'outlook.live.com',
|
|
64
|
+
'mail.yahoo.com',
|
|
65
|
+
'mail.aol.com',
|
|
66
|
+
];
|
|
67
|
+
/**
|
|
68
|
+
* Extract domain from URL
|
|
69
|
+
*/
|
|
70
|
+
function extractDomain(url) {
|
|
71
|
+
try {
|
|
72
|
+
const urlObj = new URL(url);
|
|
73
|
+
return urlObj.hostname.toLowerCase();
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return '';
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Check if URL contains paid search parameters
|
|
81
|
+
*/
|
|
82
|
+
function hasPaidSearchParams(url) {
|
|
83
|
+
try {
|
|
84
|
+
const urlObj = new URL(url);
|
|
85
|
+
return PAID_SEARCH_PARAMS.some(param => urlObj.searchParams.has(param));
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Categorize referrer based on domain and parameters
|
|
93
|
+
*/
|
|
94
|
+
function categorizeReferrer(referrer, currentUrl = '') {
|
|
95
|
+
// Direct traffic (no referrer)
|
|
96
|
+
if (!referrer || referrer.trim() === '') {
|
|
97
|
+
return 'direct';
|
|
98
|
+
}
|
|
99
|
+
const domain = extractDomain(referrer);
|
|
100
|
+
// Same domain = direct
|
|
101
|
+
if (currentUrl) {
|
|
102
|
+
const currentDomain = extractDomain(currentUrl);
|
|
103
|
+
if (domain === currentDomain) {
|
|
104
|
+
return 'direct';
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Check for paid search parameters
|
|
108
|
+
if (hasPaidSearchParams(referrer) || hasPaidSearchParams(currentUrl)) {
|
|
109
|
+
return 'paid';
|
|
110
|
+
}
|
|
111
|
+
// Email clients
|
|
112
|
+
if (EMAIL_DOMAINS.some(emailDomain => domain.includes(emailDomain))) {
|
|
113
|
+
return 'email';
|
|
114
|
+
}
|
|
115
|
+
// Social media
|
|
116
|
+
if (SOCIAL_DOMAINS.some(socialDomain => domain.includes(socialDomain))) {
|
|
117
|
+
return 'social';
|
|
118
|
+
}
|
|
119
|
+
// Organic search engines
|
|
120
|
+
if (SEARCH_ENGINES.some(searchEngine => domain.includes(searchEngine))) {
|
|
121
|
+
return 'organic';
|
|
122
|
+
}
|
|
123
|
+
// Everything else is referral
|
|
124
|
+
return 'referral';
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Parse UTM parameters from URL
|
|
128
|
+
*/
|
|
129
|
+
function parseUTMParameters(url) {
|
|
130
|
+
try {
|
|
131
|
+
const urlObj = new URL(url);
|
|
132
|
+
const params = {};
|
|
133
|
+
const utmSource = urlObj.searchParams.get('utm_source');
|
|
134
|
+
const utmMedium = urlObj.searchParams.get('utm_medium');
|
|
135
|
+
const utmCampaign = urlObj.searchParams.get('utm_campaign');
|
|
136
|
+
const utmTerm = urlObj.searchParams.get('utm_term');
|
|
137
|
+
const utmContent = urlObj.searchParams.get('utm_content');
|
|
138
|
+
if (utmSource)
|
|
139
|
+
params.utm_source = utmSource;
|
|
140
|
+
if (utmMedium)
|
|
141
|
+
params.utm_medium = utmMedium;
|
|
142
|
+
if (utmCampaign)
|
|
143
|
+
params.utm_campaign = utmCampaign;
|
|
144
|
+
if (utmTerm)
|
|
145
|
+
params.utm_term = utmTerm;
|
|
146
|
+
if (utmContent)
|
|
147
|
+
params.utm_content = utmContent;
|
|
148
|
+
return params;
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return {};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get first-touch attribution from localStorage
|
|
156
|
+
*/
|
|
157
|
+
function getFirstTouchAttribution(tenantId) {
|
|
158
|
+
if (typeof window === 'undefined' || typeof localStorage === 'undefined') {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
const key = `_grain_first_touch_${tenantId}`;
|
|
163
|
+
const stored = localStorage.getItem(key);
|
|
164
|
+
if (stored) {
|
|
165
|
+
return JSON.parse(stored);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
console.warn('[Grain Attribution] Failed to retrieve first-touch attribution:', error);
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Set first-touch attribution in localStorage
|
|
175
|
+
*/
|
|
176
|
+
function setFirstTouchAttribution(tenantId, attribution) {
|
|
177
|
+
if (typeof window === 'undefined' || typeof localStorage === 'undefined') {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
const key = `_grain_first_touch_${tenantId}`;
|
|
182
|
+
localStorage.setItem(key, JSON.stringify(attribution));
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
console.warn('[Grain Attribution] Failed to store first-touch attribution:', error);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Get or create first-touch attribution
|
|
190
|
+
*/
|
|
191
|
+
function getOrCreateFirstTouchAttribution(tenantId, referrer, currentUrl, utmParams) {
|
|
192
|
+
// Try to get existing first-touch
|
|
193
|
+
const existing = getFirstTouchAttribution(tenantId);
|
|
194
|
+
if (existing) {
|
|
195
|
+
return existing;
|
|
196
|
+
}
|
|
197
|
+
// Create new first-touch attribution
|
|
198
|
+
const referrerCategory = categorizeReferrer(referrer, currentUrl);
|
|
199
|
+
const referrerDomain = extractDomain(referrer);
|
|
200
|
+
const firstTouch = {
|
|
201
|
+
source: utmParams.utm_source || referrerDomain || 'direct',
|
|
202
|
+
medium: utmParams.utm_medium || referrerCategory,
|
|
203
|
+
campaign: utmParams.utm_campaign || 'none',
|
|
204
|
+
referrer: referrer || 'direct',
|
|
205
|
+
referrer_category: referrerCategory,
|
|
206
|
+
timestamp: Date.now(),
|
|
207
|
+
};
|
|
208
|
+
// Store it
|
|
209
|
+
setFirstTouchAttribution(tenantId, firstTouch);
|
|
210
|
+
return firstTouch;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Get session UTM parameters (memory-only, not persisted across page loads)
|
|
214
|
+
*/
|
|
215
|
+
let sessionUTMParams = null;
|
|
216
|
+
function getSessionUTMParameters() {
|
|
217
|
+
return sessionUTMParams;
|
|
218
|
+
}
|
|
219
|
+
function setSessionUTMParameters(params) {
|
|
220
|
+
sessionUTMParams = params;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Clear session UTM parameters
|
|
224
|
+
*/
|
|
225
|
+
function clearSessionUTMParameters() {
|
|
226
|
+
sessionUTMParams = null;
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=attribution.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attribution and Referral Tracking for Grain Analytics
|
|
3
|
+
* Handles referral categorization and first-touch attribution
|
|
4
|
+
*/
|
|
5
|
+
export type ReferrerCategory = 'organic' | 'paid' | 'social' | 'direct' | 'email' | 'referral';
|
|
6
|
+
export interface UTMParameters {
|
|
7
|
+
utm_source?: string;
|
|
8
|
+
utm_medium?: string;
|
|
9
|
+
utm_campaign?: string;
|
|
10
|
+
utm_term?: string;
|
|
11
|
+
utm_content?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface FirstTouchAttribution {
|
|
14
|
+
source: string;
|
|
15
|
+
medium: string;
|
|
16
|
+
campaign: string;
|
|
17
|
+
referrer: string;
|
|
18
|
+
referrer_category: ReferrerCategory;
|
|
19
|
+
timestamp: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Categorize referrer based on domain and parameters
|
|
23
|
+
*/
|
|
24
|
+
export declare function categorizeReferrer(referrer: string, currentUrl?: string): ReferrerCategory;
|
|
25
|
+
/**
|
|
26
|
+
* Parse UTM parameters from URL
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseUTMParameters(url: string): UTMParameters;
|
|
29
|
+
/**
|
|
30
|
+
* Get first-touch attribution from localStorage
|
|
31
|
+
*/
|
|
32
|
+
export declare function getFirstTouchAttribution(tenantId: string): FirstTouchAttribution | null;
|
|
33
|
+
/**
|
|
34
|
+
* Set first-touch attribution in localStorage
|
|
35
|
+
*/
|
|
36
|
+
export declare function setFirstTouchAttribution(tenantId: string, attribution: FirstTouchAttribution): void;
|
|
37
|
+
/**
|
|
38
|
+
* Get or create first-touch attribution
|
|
39
|
+
*/
|
|
40
|
+
export declare function getOrCreateFirstTouchAttribution(tenantId: string, referrer: string, currentUrl: string, utmParams: UTMParameters): FirstTouchAttribution;
|
|
41
|
+
export declare function getSessionUTMParameters(): UTMParameters | null;
|
|
42
|
+
export declare function setSessionUTMParameters(params: UTMParameters): void;
|
|
43
|
+
/**
|
|
44
|
+
* Clear session UTM parameters
|
|
45
|
+
*/
|
|
46
|
+
export declare function clearSessionUTMParameters(): void;
|
|
47
|
+
//# sourceMappingURL=attribution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attribution.d.ts","sourceRoot":"","sources":["../../src/attribution.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;AAE/F,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,gBAAgB,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;CACnB;AAkFD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAE,MAAW,GAAG,gBAAgB,CAsC9F;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAqB7D;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI,CAgBvF;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,qBAAqB,GACjC,IAAI,CAWN;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,aAAa,GACvB,qBAAqB,CAwBvB;AAOD,wBAAgB,uBAAuB,IAAI,aAAa,GAAG,IAAI,CAE9D;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAEnE;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Attribution and Referral Tracking for Grain Analytics
|
|
4
|
+
* Handles referral categorization and first-touch attribution
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.categorizeReferrer = categorizeReferrer;
|
|
8
|
+
exports.parseUTMParameters = parseUTMParameters;
|
|
9
|
+
exports.getFirstTouchAttribution = getFirstTouchAttribution;
|
|
10
|
+
exports.setFirstTouchAttribution = setFirstTouchAttribution;
|
|
11
|
+
exports.getOrCreateFirstTouchAttribution = getOrCreateFirstTouchAttribution;
|
|
12
|
+
exports.getSessionUTMParameters = getSessionUTMParameters;
|
|
13
|
+
exports.setSessionUTMParameters = setSessionUTMParameters;
|
|
14
|
+
exports.clearSessionUTMParameters = clearSessionUTMParameters;
|
|
15
|
+
/**
|
|
16
|
+
* Known paid search parameters
|
|
17
|
+
*/
|
|
18
|
+
const PAID_SEARCH_PARAMS = [
|
|
19
|
+
'gclid', // Google Ads
|
|
20
|
+
'msclkid', // Microsoft Ads
|
|
21
|
+
'fbclid', // Facebook Ads
|
|
22
|
+
'ttclid', // TikTok Ads
|
|
23
|
+
'li_fat_id', // LinkedIn Ads
|
|
24
|
+
'twclid', // Twitter Ads
|
|
25
|
+
'ScCid', // Snapchat Ads
|
|
26
|
+
];
|
|
27
|
+
/**
|
|
28
|
+
* Known social media domains
|
|
29
|
+
*/
|
|
30
|
+
const SOCIAL_DOMAINS = [
|
|
31
|
+
'facebook.com',
|
|
32
|
+
'twitter.com',
|
|
33
|
+
'x.com',
|
|
34
|
+
'linkedin.com',
|
|
35
|
+
'instagram.com',
|
|
36
|
+
'pinterest.com',
|
|
37
|
+
'reddit.com',
|
|
38
|
+
'tiktok.com',
|
|
39
|
+
'youtube.com',
|
|
40
|
+
'snapchat.com',
|
|
41
|
+
't.co', // Twitter short links
|
|
42
|
+
'fb.me', // Facebook short links
|
|
43
|
+
'lnkd.in', // LinkedIn short links
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* Known organic search engines
|
|
47
|
+
*/
|
|
48
|
+
const SEARCH_ENGINES = [
|
|
49
|
+
'google.',
|
|
50
|
+
'bing.com',
|
|
51
|
+
'yahoo.com',
|
|
52
|
+
'duckduckgo.com',
|
|
53
|
+
'baidu.com',
|
|
54
|
+
'yandex.com',
|
|
55
|
+
'ecosia.org',
|
|
56
|
+
'ask.com',
|
|
57
|
+
];
|
|
58
|
+
/**
|
|
59
|
+
* Email client domains
|
|
60
|
+
*/
|
|
61
|
+
const EMAIL_DOMAINS = [
|
|
62
|
+
'mail.google.com',
|
|
63
|
+
'outlook.live.com',
|
|
64
|
+
'mail.yahoo.com',
|
|
65
|
+
'mail.aol.com',
|
|
66
|
+
];
|
|
67
|
+
/**
|
|
68
|
+
* Extract domain from URL
|
|
69
|
+
*/
|
|
70
|
+
function extractDomain(url) {
|
|
71
|
+
try {
|
|
72
|
+
const urlObj = new URL(url);
|
|
73
|
+
return urlObj.hostname.toLowerCase();
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return '';
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Check if URL contains paid search parameters
|
|
81
|
+
*/
|
|
82
|
+
function hasPaidSearchParams(url) {
|
|
83
|
+
try {
|
|
84
|
+
const urlObj = new URL(url);
|
|
85
|
+
return PAID_SEARCH_PARAMS.some(param => urlObj.searchParams.has(param));
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Categorize referrer based on domain and parameters
|
|
93
|
+
*/
|
|
94
|
+
function categorizeReferrer(referrer, currentUrl = '') {
|
|
95
|
+
// Direct traffic (no referrer)
|
|
96
|
+
if (!referrer || referrer.trim() === '') {
|
|
97
|
+
return 'direct';
|
|
98
|
+
}
|
|
99
|
+
const domain = extractDomain(referrer);
|
|
100
|
+
// Same domain = direct
|
|
101
|
+
if (currentUrl) {
|
|
102
|
+
const currentDomain = extractDomain(currentUrl);
|
|
103
|
+
if (domain === currentDomain) {
|
|
104
|
+
return 'direct';
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Check for paid search parameters
|
|
108
|
+
if (hasPaidSearchParams(referrer) || hasPaidSearchParams(currentUrl)) {
|
|
109
|
+
return 'paid';
|
|
110
|
+
}
|
|
111
|
+
// Email clients
|
|
112
|
+
if (EMAIL_DOMAINS.some(emailDomain => domain.includes(emailDomain))) {
|
|
113
|
+
return 'email';
|
|
114
|
+
}
|
|
115
|
+
// Social media
|
|
116
|
+
if (SOCIAL_DOMAINS.some(socialDomain => domain.includes(socialDomain))) {
|
|
117
|
+
return 'social';
|
|
118
|
+
}
|
|
119
|
+
// Organic search engines
|
|
120
|
+
if (SEARCH_ENGINES.some(searchEngine => domain.includes(searchEngine))) {
|
|
121
|
+
return 'organic';
|
|
122
|
+
}
|
|
123
|
+
// Everything else is referral
|
|
124
|
+
return 'referral';
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Parse UTM parameters from URL
|
|
128
|
+
*/
|
|
129
|
+
function parseUTMParameters(url) {
|
|
130
|
+
try {
|
|
131
|
+
const urlObj = new URL(url);
|
|
132
|
+
const params = {};
|
|
133
|
+
const utmSource = urlObj.searchParams.get('utm_source');
|
|
134
|
+
const utmMedium = urlObj.searchParams.get('utm_medium');
|
|
135
|
+
const utmCampaign = urlObj.searchParams.get('utm_campaign');
|
|
136
|
+
const utmTerm = urlObj.searchParams.get('utm_term');
|
|
137
|
+
const utmContent = urlObj.searchParams.get('utm_content');
|
|
138
|
+
if (utmSource)
|
|
139
|
+
params.utm_source = utmSource;
|
|
140
|
+
if (utmMedium)
|
|
141
|
+
params.utm_medium = utmMedium;
|
|
142
|
+
if (utmCampaign)
|
|
143
|
+
params.utm_campaign = utmCampaign;
|
|
144
|
+
if (utmTerm)
|
|
145
|
+
params.utm_term = utmTerm;
|
|
146
|
+
if (utmContent)
|
|
147
|
+
params.utm_content = utmContent;
|
|
148
|
+
return params;
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return {};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get first-touch attribution from localStorage
|
|
156
|
+
*/
|
|
157
|
+
function getFirstTouchAttribution(tenantId) {
|
|
158
|
+
if (typeof window === 'undefined' || typeof localStorage === 'undefined') {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
const key = `_grain_first_touch_${tenantId}`;
|
|
163
|
+
const stored = localStorage.getItem(key);
|
|
164
|
+
if (stored) {
|
|
165
|
+
return JSON.parse(stored);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
console.warn('[Grain Attribution] Failed to retrieve first-touch attribution:', error);
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Set first-touch attribution in localStorage
|
|
175
|
+
*/
|
|
176
|
+
function setFirstTouchAttribution(tenantId, attribution) {
|
|
177
|
+
if (typeof window === 'undefined' || typeof localStorage === 'undefined') {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
const key = `_grain_first_touch_${tenantId}`;
|
|
182
|
+
localStorage.setItem(key, JSON.stringify(attribution));
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
console.warn('[Grain Attribution] Failed to store first-touch attribution:', error);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Get or create first-touch attribution
|
|
190
|
+
*/
|
|
191
|
+
function getOrCreateFirstTouchAttribution(tenantId, referrer, currentUrl, utmParams) {
|
|
192
|
+
// Try to get existing first-touch
|
|
193
|
+
const existing = getFirstTouchAttribution(tenantId);
|
|
194
|
+
if (existing) {
|
|
195
|
+
return existing;
|
|
196
|
+
}
|
|
197
|
+
// Create new first-touch attribution
|
|
198
|
+
const referrerCategory = categorizeReferrer(referrer, currentUrl);
|
|
199
|
+
const referrerDomain = extractDomain(referrer);
|
|
200
|
+
const firstTouch = {
|
|
201
|
+
source: utmParams.utm_source || referrerDomain || 'direct',
|
|
202
|
+
medium: utmParams.utm_medium || referrerCategory,
|
|
203
|
+
campaign: utmParams.utm_campaign || 'none',
|
|
204
|
+
referrer: referrer || 'direct',
|
|
205
|
+
referrer_category: referrerCategory,
|
|
206
|
+
timestamp: Date.now(),
|
|
207
|
+
};
|
|
208
|
+
// Store it
|
|
209
|
+
setFirstTouchAttribution(tenantId, firstTouch);
|
|
210
|
+
return firstTouch;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Get session UTM parameters (memory-only, not persisted across page loads)
|
|
214
|
+
*/
|
|
215
|
+
let sessionUTMParams = null;
|
|
216
|
+
function getSessionUTMParameters() {
|
|
217
|
+
return sessionUTMParams;
|
|
218
|
+
}
|
|
219
|
+
function setSessionUTMParameters(params) {
|
|
220
|
+
sessionUTMParams = params;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Clear session UTM parameters
|
|
224
|
+
*/
|
|
225
|
+
function clearSessionUTMParameters() {
|
|
226
|
+
sessionUTMParams = null;
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=attribution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attribution.js","sourceRoot":"","sources":["../../src/attribution.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get full country name from user's timezone
|
|
3
|
+
* @returns Full country name or null if timezone is unavailable
|
|
4
|
+
*/
|
|
5
|
+
export declare function getCountry(): string | null;
|
|
6
|
+
/**
|
|
7
|
+
* Get country code (ISO 3166-1 alpha-2) from user's timezone
|
|
8
|
+
* Privacy-friendly alternative to IP geolocation
|
|
9
|
+
* @returns ISO 3166-1 alpha-2 country code (e.g., "US", "GB") or "Unknown"
|
|
10
|
+
*/
|
|
11
|
+
export declare function getCountryCodeFromTimezone(): string;
|
|
12
|
+
export declare function getState(): string | null;
|
|
13
|
+
//# sourceMappingURL=countries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"countries.d.ts","sourceRoot":"","sources":["../../src/countries.ts"],"names":[],"mappings":"AAyyFA;;;GAGG;AACH,wBAAgB,UAAU,IAAI,MAAM,GAAG,IAAI,CAe1C;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAanD;AAED,wBAAgB,QAAQ,IAAI,MAAM,GAAG,IAAI,CAUxC"}
|