@loamly/tracker 2.0.2 → 2.1.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/README.md +23 -0
- package/dist/index.cjs +96 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +25 -1
- package/dist/index.d.ts +25 -1
- package/dist/index.mjs +96 -59
- package/dist/index.mjs.map +1 -1
- package/dist/loamly.iife.global.js +96 -59
- package/dist/loamly.iife.global.js.map +1 -1
- package/dist/loamly.iife.min.global.js +1 -1
- package/dist/loamly.iife.min.global.js.map +1 -1
- package/package.json +1 -1
- package/src/config.ts +1 -1
- package/src/core.ts +125 -73
- package/src/types.ts +25 -0
package/dist/index.d.mts
CHANGED
|
@@ -77,6 +77,30 @@ interface LoamlyConfig {
|
|
|
77
77
|
disableBehavioral?: boolean;
|
|
78
78
|
/** Custom session timeout in milliseconds (default: 30 minutes) */
|
|
79
79
|
sessionTimeout?: number;
|
|
80
|
+
/**
|
|
81
|
+
* Feature flags for lightweight mode
|
|
82
|
+
* Set to false to reduce initialization overhead
|
|
83
|
+
*/
|
|
84
|
+
features?: {
|
|
85
|
+
/** Scroll depth tracking (default: true) */
|
|
86
|
+
scroll?: boolean;
|
|
87
|
+
/** Time on page tracking (default: true) */
|
|
88
|
+
time?: boolean;
|
|
89
|
+
/** Form interaction tracking (default: true) */
|
|
90
|
+
forms?: boolean;
|
|
91
|
+
/** SPA navigation support (default: true) */
|
|
92
|
+
spa?: boolean;
|
|
93
|
+
/** Behavioral ML classification (default: true) */
|
|
94
|
+
behavioralML?: boolean;
|
|
95
|
+
/** Focus/blur paste detection (default: true) */
|
|
96
|
+
focusBlur?: boolean;
|
|
97
|
+
/** Agentic browser detection (default: true) */
|
|
98
|
+
agentic?: boolean;
|
|
99
|
+
/** Event queue with retry (default: true) */
|
|
100
|
+
eventQueue?: boolean;
|
|
101
|
+
/** Heartbeat ping service (default: false - opt-in) */
|
|
102
|
+
ping?: boolean;
|
|
103
|
+
};
|
|
80
104
|
}
|
|
81
105
|
interface TrackEventOptions {
|
|
82
106
|
/** Custom properties to attach to the event */
|
|
@@ -246,7 +270,7 @@ declare function detectAIFromUTM(url: string): AIDetectionResult | null;
|
|
|
246
270
|
* @license MIT
|
|
247
271
|
* @see https://github.com/loamly/loamly
|
|
248
272
|
*/
|
|
249
|
-
declare const VERSION = "2.0
|
|
273
|
+
declare const VERSION = "2.1.0";
|
|
250
274
|
/**
|
|
251
275
|
* Known AI platforms for referrer detection
|
|
252
276
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -77,6 +77,30 @@ interface LoamlyConfig {
|
|
|
77
77
|
disableBehavioral?: boolean;
|
|
78
78
|
/** Custom session timeout in milliseconds (default: 30 minutes) */
|
|
79
79
|
sessionTimeout?: number;
|
|
80
|
+
/**
|
|
81
|
+
* Feature flags for lightweight mode
|
|
82
|
+
* Set to false to reduce initialization overhead
|
|
83
|
+
*/
|
|
84
|
+
features?: {
|
|
85
|
+
/** Scroll depth tracking (default: true) */
|
|
86
|
+
scroll?: boolean;
|
|
87
|
+
/** Time on page tracking (default: true) */
|
|
88
|
+
time?: boolean;
|
|
89
|
+
/** Form interaction tracking (default: true) */
|
|
90
|
+
forms?: boolean;
|
|
91
|
+
/** SPA navigation support (default: true) */
|
|
92
|
+
spa?: boolean;
|
|
93
|
+
/** Behavioral ML classification (default: true) */
|
|
94
|
+
behavioralML?: boolean;
|
|
95
|
+
/** Focus/blur paste detection (default: true) */
|
|
96
|
+
focusBlur?: boolean;
|
|
97
|
+
/** Agentic browser detection (default: true) */
|
|
98
|
+
agentic?: boolean;
|
|
99
|
+
/** Event queue with retry (default: true) */
|
|
100
|
+
eventQueue?: boolean;
|
|
101
|
+
/** Heartbeat ping service (default: false - opt-in) */
|
|
102
|
+
ping?: boolean;
|
|
103
|
+
};
|
|
80
104
|
}
|
|
81
105
|
interface TrackEventOptions {
|
|
82
106
|
/** Custom properties to attach to the event */
|
|
@@ -246,7 +270,7 @@ declare function detectAIFromUTM(url: string): AIDetectionResult | null;
|
|
|
246
270
|
* @license MIT
|
|
247
271
|
* @see https://github.com/loamly/loamly
|
|
248
272
|
*/
|
|
249
|
-
declare const VERSION = "2.0
|
|
273
|
+
declare const VERSION = "2.1.0";
|
|
250
274
|
/**
|
|
251
275
|
* Known AI platforms for referrer detection
|
|
252
276
|
*/
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/config.ts
|
|
2
|
-
var VERSION = "2.0
|
|
2
|
+
var VERSION = "2.1.0";
|
|
3
3
|
var DEFAULT_CONFIG = {
|
|
4
4
|
apiHost: "https://app.loamly.ai",
|
|
5
5
|
endpoints: {
|
|
@@ -1770,16 +1770,32 @@ function init(userConfig = {}) {
|
|
|
1770
1770
|
apiHost: userConfig.apiHost || DEFAULT_CONFIG.apiHost
|
|
1771
1771
|
};
|
|
1772
1772
|
debugMode = userConfig.debug ?? false;
|
|
1773
|
+
const features = {
|
|
1774
|
+
scroll: true,
|
|
1775
|
+
time: true,
|
|
1776
|
+
forms: true,
|
|
1777
|
+
spa: true,
|
|
1778
|
+
behavioralML: true,
|
|
1779
|
+
focusBlur: true,
|
|
1780
|
+
agentic: true,
|
|
1781
|
+
eventQueue: true,
|
|
1782
|
+
ping: false,
|
|
1783
|
+
// Opt-in only
|
|
1784
|
+
...userConfig.features
|
|
1785
|
+
};
|
|
1773
1786
|
log("Initializing Loamly Tracker v" + VERSION);
|
|
1787
|
+
log("Features:", features);
|
|
1774
1788
|
visitorId = getVisitorId();
|
|
1775
1789
|
log("Visitor ID:", visitorId);
|
|
1776
1790
|
const session = getSessionId();
|
|
1777
1791
|
sessionId = session.sessionId;
|
|
1778
1792
|
log("Session ID:", sessionId, session.isNew ? "(new)" : "(existing)");
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1793
|
+
if (features.eventQueue) {
|
|
1794
|
+
eventQueue = new EventQueue(endpoint(DEFAULT_CONFIG.endpoints.behavioral), {
|
|
1795
|
+
batchSize: DEFAULT_CONFIG.batchSize,
|
|
1796
|
+
batchTimeout: DEFAULT_CONFIG.batchTimeout
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1783
1799
|
navigationTiming = detectNavigationType();
|
|
1784
1800
|
log("Navigation timing:", navigationTiming);
|
|
1785
1801
|
aiDetection = detectAIFromReferrer(document.referrer) || detectAIFromUTM(window.location.href);
|
|
@@ -1791,21 +1807,27 @@ function init(userConfig = {}) {
|
|
|
1791
1807
|
pageview();
|
|
1792
1808
|
}
|
|
1793
1809
|
if (!userConfig.disableBehavioral) {
|
|
1794
|
-
setupAdvancedBehavioralTracking();
|
|
1810
|
+
setupAdvancedBehavioralTracking(features);
|
|
1811
|
+
}
|
|
1812
|
+
if (features.behavioralML) {
|
|
1813
|
+
behavioralClassifier = new BehavioralClassifier(1e4);
|
|
1814
|
+
behavioralClassifier.setOnClassify(handleBehavioralClassification);
|
|
1815
|
+
setupBehavioralMLTracking();
|
|
1816
|
+
}
|
|
1817
|
+
if (features.focusBlur) {
|
|
1818
|
+
focusBlurAnalyzer = new FocusBlurAnalyzer();
|
|
1819
|
+
focusBlurAnalyzer.initTracking();
|
|
1820
|
+
setTimeout(() => {
|
|
1821
|
+
if (focusBlurAnalyzer) {
|
|
1822
|
+
handleFocusBlurAnalysis(focusBlurAnalyzer.analyze());
|
|
1823
|
+
}
|
|
1824
|
+
}, 5e3);
|
|
1795
1825
|
}
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
setTimeout(() => {
|
|
1802
|
-
if (focusBlurAnalyzer) {
|
|
1803
|
-
handleFocusBlurAnalysis(focusBlurAnalyzer.analyze());
|
|
1804
|
-
}
|
|
1805
|
-
}, 5e3);
|
|
1806
|
-
agenticAnalyzer = new AgenticBrowserAnalyzer();
|
|
1807
|
-
agenticAnalyzer.init();
|
|
1808
|
-
if (visitorId && sessionId) {
|
|
1826
|
+
if (features.agentic) {
|
|
1827
|
+
agenticAnalyzer = new AgenticBrowserAnalyzer();
|
|
1828
|
+
agenticAnalyzer.init();
|
|
1829
|
+
}
|
|
1830
|
+
if (features.ping && visitorId && sessionId) {
|
|
1809
1831
|
pingService = new PingService(sessionId, visitorId, VERSION, {
|
|
1810
1832
|
interval: DEFAULT_CONFIG.pingInterval,
|
|
1811
1833
|
endpoint: endpoint(DEFAULT_CONFIG.endpoints.ping)
|
|
@@ -1820,48 +1842,63 @@ function init(userConfig = {}) {
|
|
|
1820
1842
|
reportHealth("initialized");
|
|
1821
1843
|
log("Initialization complete");
|
|
1822
1844
|
}
|
|
1823
|
-
function setupAdvancedBehavioralTracking() {
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
}
|
|
1834
|
-
});
|
|
1835
|
-
scrollTracker.start();
|
|
1836
|
-
timeTracker = new TimeTracker({
|
|
1837
|
-
updateIntervalMs: 1e4,
|
|
1838
|
-
// Report every 10 seconds
|
|
1839
|
-
onUpdate: (event) => {
|
|
1840
|
-
if (event.active_time_ms >= DEFAULT_CONFIG.timeSpentThresholdMs) {
|
|
1841
|
-
queueEvent("time_spent", {
|
|
1842
|
-
active_time_ms: event.active_time_ms,
|
|
1843
|
-
total_time_ms: event.total_time_ms,
|
|
1844
|
-
idle_time_ms: event.idle_time_ms,
|
|
1845
|
-
is_engaged: event.is_engaged
|
|
1845
|
+
function setupAdvancedBehavioralTracking(features) {
|
|
1846
|
+
if (features.scroll) {
|
|
1847
|
+
scrollTracker = new ScrollTracker({
|
|
1848
|
+
chunks: [30, 60, 90, 100],
|
|
1849
|
+
onChunkReached: (event) => {
|
|
1850
|
+
log("Scroll chunk:", event.chunk);
|
|
1851
|
+
queueEvent("scroll_depth", {
|
|
1852
|
+
depth: event.depth,
|
|
1853
|
+
chunk: event.chunk,
|
|
1854
|
+
time_to_reach_ms: event.time_to_reach_ms
|
|
1846
1855
|
});
|
|
1847
1856
|
}
|
|
1848
|
-
}
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1857
|
+
});
|
|
1858
|
+
scrollTracker.start();
|
|
1859
|
+
}
|
|
1860
|
+
if (features.time) {
|
|
1861
|
+
timeTracker = new TimeTracker({
|
|
1862
|
+
updateIntervalMs: 1e4,
|
|
1863
|
+
// Report every 10 seconds
|
|
1864
|
+
onUpdate: (event) => {
|
|
1865
|
+
if (event.active_time_ms >= DEFAULT_CONFIG.timeSpentThresholdMs) {
|
|
1866
|
+
queueEvent("time_spent", {
|
|
1867
|
+
active_time_ms: event.active_time_ms,
|
|
1868
|
+
total_time_ms: event.total_time_ms,
|
|
1869
|
+
idle_time_ms: event.idle_time_ms,
|
|
1870
|
+
is_engaged: event.is_engaged
|
|
1871
|
+
});
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
});
|
|
1875
|
+
timeTracker.start();
|
|
1876
|
+
}
|
|
1877
|
+
if (features.forms) {
|
|
1878
|
+
formTracker = new FormTracker({
|
|
1879
|
+
onFormEvent: (event) => {
|
|
1880
|
+
log("Form event:", event.event_type, event.form_id);
|
|
1881
|
+
queueEvent(event.event_type, {
|
|
1882
|
+
form_id: event.form_id,
|
|
1883
|
+
form_type: event.form_type,
|
|
1884
|
+
field_name: event.field_name,
|
|
1885
|
+
field_type: event.field_type,
|
|
1886
|
+
time_to_submit_ms: event.time_to_submit_ms,
|
|
1887
|
+
is_conversion: event.is_conversion
|
|
1888
|
+
});
|
|
1889
|
+
}
|
|
1890
|
+
});
|
|
1891
|
+
formTracker.start();
|
|
1892
|
+
}
|
|
1893
|
+
if (features.spa) {
|
|
1894
|
+
spaRouter = new SPARouter({
|
|
1895
|
+
onNavigate: (event) => {
|
|
1896
|
+
log("SPA navigation:", event.navigation_type);
|
|
1897
|
+
pageview(event.to_url);
|
|
1898
|
+
}
|
|
1899
|
+
});
|
|
1900
|
+
spaRouter.start();
|
|
1901
|
+
}
|
|
1865
1902
|
document.addEventListener("click", (e) => {
|
|
1866
1903
|
const target = e.target;
|
|
1867
1904
|
const link = target.closest("a");
|