@loamly/tracker 2.0.1 → 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 +132 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.mjs +132 -60
- package/dist/index.mjs.map +1 -1
- package/dist/loamly.iife.global.js +132 -60
- 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 +11 -9
- package/src/config.ts +1 -1
- package/src/core.ts +177 -74
- package/src/types.ts +25 -0
- package/LICENSE +0 -23
|
@@ -26,7 +26,7 @@ var Loamly = (() => {
|
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
// src/config.ts
|
|
29
|
-
var VERSION = "2.0
|
|
29
|
+
var VERSION = "2.1.0";
|
|
30
30
|
var DEFAULT_CONFIG = {
|
|
31
31
|
apiHost: "https://app.loamly.ai",
|
|
32
32
|
endpoints: {
|
|
@@ -1774,16 +1774,32 @@ var Loamly = (() => {
|
|
|
1774
1774
|
apiHost: userConfig.apiHost || DEFAULT_CONFIG.apiHost
|
|
1775
1775
|
};
|
|
1776
1776
|
debugMode = userConfig.debug ?? false;
|
|
1777
|
+
const features = {
|
|
1778
|
+
scroll: true,
|
|
1779
|
+
time: true,
|
|
1780
|
+
forms: true,
|
|
1781
|
+
spa: true,
|
|
1782
|
+
behavioralML: true,
|
|
1783
|
+
focusBlur: true,
|
|
1784
|
+
agentic: true,
|
|
1785
|
+
eventQueue: true,
|
|
1786
|
+
ping: false,
|
|
1787
|
+
// Opt-in only
|
|
1788
|
+
...userConfig.features
|
|
1789
|
+
};
|
|
1777
1790
|
log("Initializing Loamly Tracker v" + VERSION);
|
|
1791
|
+
log("Features:", features);
|
|
1778
1792
|
visitorId = getVisitorId();
|
|
1779
1793
|
log("Visitor ID:", visitorId);
|
|
1780
1794
|
const session = getSessionId();
|
|
1781
1795
|
sessionId = session.sessionId;
|
|
1782
1796
|
log("Session ID:", sessionId, session.isNew ? "(new)" : "(existing)");
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1797
|
+
if (features.eventQueue) {
|
|
1798
|
+
eventQueue = new EventQueue(endpoint(DEFAULT_CONFIG.endpoints.behavioral), {
|
|
1799
|
+
batchSize: DEFAULT_CONFIG.batchSize,
|
|
1800
|
+
batchTimeout: DEFAULT_CONFIG.batchTimeout
|
|
1801
|
+
});
|
|
1802
|
+
}
|
|
1787
1803
|
navigationTiming = detectNavigationType();
|
|
1788
1804
|
log("Navigation timing:", navigationTiming);
|
|
1789
1805
|
aiDetection = detectAIFromReferrer(document.referrer) || detectAIFromUTM(window.location.href);
|
|
@@ -1795,21 +1811,27 @@ var Loamly = (() => {
|
|
|
1795
1811
|
pageview();
|
|
1796
1812
|
}
|
|
1797
1813
|
if (!userConfig.disableBehavioral) {
|
|
1798
|
-
setupAdvancedBehavioralTracking();
|
|
1814
|
+
setupAdvancedBehavioralTracking(features);
|
|
1815
|
+
}
|
|
1816
|
+
if (features.behavioralML) {
|
|
1817
|
+
behavioralClassifier = new BehavioralClassifier(1e4);
|
|
1818
|
+
behavioralClassifier.setOnClassify(handleBehavioralClassification);
|
|
1819
|
+
setupBehavioralMLTracking();
|
|
1820
|
+
}
|
|
1821
|
+
if (features.focusBlur) {
|
|
1822
|
+
focusBlurAnalyzer = new FocusBlurAnalyzer();
|
|
1823
|
+
focusBlurAnalyzer.initTracking();
|
|
1824
|
+
setTimeout(() => {
|
|
1825
|
+
if (focusBlurAnalyzer) {
|
|
1826
|
+
handleFocusBlurAnalysis(focusBlurAnalyzer.analyze());
|
|
1827
|
+
}
|
|
1828
|
+
}, 5e3);
|
|
1799
1829
|
}
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
setTimeout(() => {
|
|
1806
|
-
if (focusBlurAnalyzer) {
|
|
1807
|
-
handleFocusBlurAnalysis(focusBlurAnalyzer.analyze());
|
|
1808
|
-
}
|
|
1809
|
-
}, 5e3);
|
|
1810
|
-
agenticAnalyzer = new AgenticBrowserAnalyzer();
|
|
1811
|
-
agenticAnalyzer.init();
|
|
1812
|
-
if (visitorId && sessionId) {
|
|
1830
|
+
if (features.agentic) {
|
|
1831
|
+
agenticAnalyzer = new AgenticBrowserAnalyzer();
|
|
1832
|
+
agenticAnalyzer.init();
|
|
1833
|
+
}
|
|
1834
|
+
if (features.ping && visitorId && sessionId) {
|
|
1813
1835
|
pingService = new PingService(sessionId, visitorId, VERSION, {
|
|
1814
1836
|
interval: DEFAULT_CONFIG.pingInterval,
|
|
1815
1837
|
endpoint: endpoint(DEFAULT_CONFIG.endpoints.ping)
|
|
@@ -1821,50 +1843,66 @@ var Loamly = (() => {
|
|
|
1821
1843
|
});
|
|
1822
1844
|
spaRouter.start();
|
|
1823
1845
|
setupUnloadHandlers();
|
|
1846
|
+
reportHealth("initialized");
|
|
1824
1847
|
log("Initialization complete");
|
|
1825
1848
|
}
|
|
1826
|
-
function setupAdvancedBehavioralTracking() {
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
}
|
|
1837
|
-
});
|
|
1838
|
-
scrollTracker.start();
|
|
1839
|
-
timeTracker = new TimeTracker({
|
|
1840
|
-
updateIntervalMs: 1e4,
|
|
1841
|
-
// Report every 10 seconds
|
|
1842
|
-
onUpdate: (event) => {
|
|
1843
|
-
if (event.active_time_ms >= DEFAULT_CONFIG.timeSpentThresholdMs) {
|
|
1844
|
-
queueEvent("time_spent", {
|
|
1845
|
-
active_time_ms: event.active_time_ms,
|
|
1846
|
-
total_time_ms: event.total_time_ms,
|
|
1847
|
-
idle_time_ms: event.idle_time_ms,
|
|
1848
|
-
is_engaged: event.is_engaged
|
|
1849
|
+
function setupAdvancedBehavioralTracking(features) {
|
|
1850
|
+
if (features.scroll) {
|
|
1851
|
+
scrollTracker = new ScrollTracker({
|
|
1852
|
+
chunks: [30, 60, 90, 100],
|
|
1853
|
+
onChunkReached: (event) => {
|
|
1854
|
+
log("Scroll chunk:", event.chunk);
|
|
1855
|
+
queueEvent("scroll_depth", {
|
|
1856
|
+
depth: event.depth,
|
|
1857
|
+
chunk: event.chunk,
|
|
1858
|
+
time_to_reach_ms: event.time_to_reach_ms
|
|
1849
1859
|
});
|
|
1850
1860
|
}
|
|
1851
|
-
}
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1861
|
+
});
|
|
1862
|
+
scrollTracker.start();
|
|
1863
|
+
}
|
|
1864
|
+
if (features.time) {
|
|
1865
|
+
timeTracker = new TimeTracker({
|
|
1866
|
+
updateIntervalMs: 1e4,
|
|
1867
|
+
// Report every 10 seconds
|
|
1868
|
+
onUpdate: (event) => {
|
|
1869
|
+
if (event.active_time_ms >= DEFAULT_CONFIG.timeSpentThresholdMs) {
|
|
1870
|
+
queueEvent("time_spent", {
|
|
1871
|
+
active_time_ms: event.active_time_ms,
|
|
1872
|
+
total_time_ms: event.total_time_ms,
|
|
1873
|
+
idle_time_ms: event.idle_time_ms,
|
|
1874
|
+
is_engaged: event.is_engaged
|
|
1875
|
+
});
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
});
|
|
1879
|
+
timeTracker.start();
|
|
1880
|
+
}
|
|
1881
|
+
if (features.forms) {
|
|
1882
|
+
formTracker = new FormTracker({
|
|
1883
|
+
onFormEvent: (event) => {
|
|
1884
|
+
log("Form event:", event.event_type, event.form_id);
|
|
1885
|
+
queueEvent(event.event_type, {
|
|
1886
|
+
form_id: event.form_id,
|
|
1887
|
+
form_type: event.form_type,
|
|
1888
|
+
field_name: event.field_name,
|
|
1889
|
+
field_type: event.field_type,
|
|
1890
|
+
time_to_submit_ms: event.time_to_submit_ms,
|
|
1891
|
+
is_conversion: event.is_conversion
|
|
1892
|
+
});
|
|
1893
|
+
}
|
|
1894
|
+
});
|
|
1895
|
+
formTracker.start();
|
|
1896
|
+
}
|
|
1897
|
+
if (features.spa) {
|
|
1898
|
+
spaRouter = new SPARouter({
|
|
1899
|
+
onNavigate: (event) => {
|
|
1900
|
+
log("SPA navigation:", event.navigation_type);
|
|
1901
|
+
pageview(event.to_url);
|
|
1902
|
+
}
|
|
1903
|
+
});
|
|
1904
|
+
spaRouter.start();
|
|
1905
|
+
}
|
|
1868
1906
|
document.addEventListener("click", (e) => {
|
|
1869
1907
|
const target = e.target;
|
|
1870
1908
|
const link = target.closest("a");
|
|
@@ -2166,6 +2204,39 @@ var Loamly = (() => {
|
|
|
2166
2204
|
function isTrackerInitialized() {
|
|
2167
2205
|
return initialized;
|
|
2168
2206
|
}
|
|
2207
|
+
function reportHealth(status, errorMessage) {
|
|
2208
|
+
if (!config.apiKey) return;
|
|
2209
|
+
try {
|
|
2210
|
+
const healthData = {
|
|
2211
|
+
workspace_id: config.apiKey,
|
|
2212
|
+
status,
|
|
2213
|
+
error_message: errorMessage || null,
|
|
2214
|
+
version: VERSION,
|
|
2215
|
+
url: typeof window !== "undefined" ? window.location.href : null,
|
|
2216
|
+
user_agent: typeof navigator !== "undefined" ? navigator.userAgent : null,
|
|
2217
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2218
|
+
features: {
|
|
2219
|
+
scroll_tracker: !!scrollTracker,
|
|
2220
|
+
time_tracker: !!timeTracker,
|
|
2221
|
+
form_tracker: !!formTracker,
|
|
2222
|
+
spa_router: !!spaRouter,
|
|
2223
|
+
behavioral_ml: !!behavioralClassifier,
|
|
2224
|
+
focus_blur: !!focusBlurAnalyzer,
|
|
2225
|
+
agentic: !!agenticAnalyzer,
|
|
2226
|
+
ping_service: !!pingService,
|
|
2227
|
+
event_queue: !!eventQueue
|
|
2228
|
+
}
|
|
2229
|
+
};
|
|
2230
|
+
safeFetch(endpoint(DEFAULT_CONFIG.endpoints.health), {
|
|
2231
|
+
method: "POST",
|
|
2232
|
+
headers: { "Content-Type": "application/json" },
|
|
2233
|
+
body: JSON.stringify(healthData)
|
|
2234
|
+
}).catch(() => {
|
|
2235
|
+
});
|
|
2236
|
+
log("Health reported:", status);
|
|
2237
|
+
} catch {
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2169
2240
|
function reset() {
|
|
2170
2241
|
log("Resetting tracker");
|
|
2171
2242
|
pingService?.stop();
|
|
@@ -2215,7 +2286,8 @@ var Loamly = (() => {
|
|
|
2215
2286
|
getAgentic: getAgenticResult,
|
|
2216
2287
|
isInitialized: isTrackerInitialized,
|
|
2217
2288
|
reset,
|
|
2218
|
-
debug: setDebug
|
|
2289
|
+
debug: setDebug,
|
|
2290
|
+
reportHealth
|
|
2219
2291
|
};
|
|
2220
2292
|
|
|
2221
2293
|
// src/browser.ts
|