humanbehavior-js 0.1.1 → 0.1.3
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/cjs/index.js +202 -15
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +202 -15
- package/dist/esm/index.js.map +1 -1
- package/dist/index.min.js +2 -2
- package/dist/index.min.js.map +1 -1
- package/dist/types/index.d.ts +29 -0
- package/package.json +1 -1
- package/simple-demo.html +26 -0
- package/src/api.ts +51 -0
- package/src/tracker.ts +202 -19
package/dist/cjs/index.js
CHANGED
|
@@ -4368,6 +4368,57 @@ class HumanBehaviorAPI {
|
|
|
4368
4368
|
data.append('apiKey', encodeURIComponent(this.apiKey));
|
|
4369
4369
|
navigator.sendBeacon(`${this.baseUrl}/api/ingestion/events`, data);
|
|
4370
4370
|
}
|
|
4371
|
+
sendCustomEvent(sessionId, eventName, eventProperties) {
|
|
4372
|
+
return __awaiter$1(this, void 0, void 0, function* () {
|
|
4373
|
+
try {
|
|
4374
|
+
const response = yield fetch(`${this.baseUrl}/api/ingestion/customEvent`, {
|
|
4375
|
+
method: 'POST',
|
|
4376
|
+
headers: {
|
|
4377
|
+
'Content-Type': 'application/json',
|
|
4378
|
+
'Authorization': `Bearer ${this.apiKey}`
|
|
4379
|
+
},
|
|
4380
|
+
body: JSON.stringify({
|
|
4381
|
+
sessionId: sessionId,
|
|
4382
|
+
eventName: eventName,
|
|
4383
|
+
eventProperties: eventProperties || {}
|
|
4384
|
+
})
|
|
4385
|
+
});
|
|
4386
|
+
if (!response.ok) {
|
|
4387
|
+
throw new Error(`Failed to send custom event: ${response.statusText}`);
|
|
4388
|
+
}
|
|
4389
|
+
return yield response.json();
|
|
4390
|
+
}
|
|
4391
|
+
catch (error) {
|
|
4392
|
+
logError('Error sending custom event:', error);
|
|
4393
|
+
throw error;
|
|
4394
|
+
}
|
|
4395
|
+
});
|
|
4396
|
+
}
|
|
4397
|
+
sendCustomEventBatch(sessionId, events) {
|
|
4398
|
+
return __awaiter$1(this, void 0, void 0, function* () {
|
|
4399
|
+
try {
|
|
4400
|
+
const response = yield fetch(`${this.baseUrl}/api/ingestion/customEvent/batch`, {
|
|
4401
|
+
method: 'POST',
|
|
4402
|
+
headers: {
|
|
4403
|
+
'Content-Type': 'application/json',
|
|
4404
|
+
'Authorization': `Bearer ${this.apiKey}`
|
|
4405
|
+
},
|
|
4406
|
+
body: JSON.stringify({
|
|
4407
|
+
sessionId: sessionId,
|
|
4408
|
+
events: events
|
|
4409
|
+
})
|
|
4410
|
+
});
|
|
4411
|
+
if (!response.ok) {
|
|
4412
|
+
throw new Error(`Failed to send custom event batch: ${response.statusText}`);
|
|
4413
|
+
}
|
|
4414
|
+
return yield response.json();
|
|
4415
|
+
}
|
|
4416
|
+
catch (error) {
|
|
4417
|
+
logError('Error sending custom event batch:', error);
|
|
4418
|
+
throw error;
|
|
4419
|
+
}
|
|
4420
|
+
});
|
|
4421
|
+
}
|
|
4371
4422
|
}
|
|
4372
4423
|
|
|
4373
4424
|
// Redaction functionality for sensitive input fields
|
|
@@ -4806,6 +4857,10 @@ class HumanBehaviorTracker {
|
|
|
4806
4857
|
if (options === null || options === void 0 ? void 0 : options.redactFields) {
|
|
4807
4858
|
tracker.setRedactedFields(options.redactFields);
|
|
4808
4859
|
}
|
|
4860
|
+
// Setup automatic tracking if enabled
|
|
4861
|
+
if ((options === null || options === void 0 ? void 0 : options.enableAutomaticTracking) !== false) {
|
|
4862
|
+
tracker.setupAutomaticTracking(options === null || options === void 0 ? void 0 : options.automaticTrackingOptions);
|
|
4863
|
+
}
|
|
4809
4864
|
// Test connection (non-blocking)
|
|
4810
4865
|
if (isBrowser) {
|
|
4811
4866
|
const testUrl = tracker.api['baseUrl'] + '/api/health';
|
|
@@ -5054,28 +5109,159 @@ class HumanBehaviorTracker {
|
|
|
5054
5109
|
if (!this.initialized)
|
|
5055
5110
|
return;
|
|
5056
5111
|
try {
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
properties: properties || {},
|
|
5060
|
-
timestamp: new Date().toISOString(),
|
|
5061
|
-
url: window.location.href,
|
|
5062
|
-
pathname: window.location.pathname
|
|
5063
|
-
};
|
|
5064
|
-
// Add custom event to the main event stream
|
|
5065
|
-
yield this.addEvent({
|
|
5066
|
-
type: 5, // Custom event type
|
|
5067
|
-
data: {
|
|
5068
|
-
payload: Object.assign({ eventType: 'custom' }, customEventData)
|
|
5069
|
-
},
|
|
5070
|
-
timestamp: Date.now()
|
|
5071
|
-
});
|
|
5112
|
+
// Send custom event directly to the API
|
|
5113
|
+
yield this.api.sendCustomEvent(this.sessionId, eventName, properties);
|
|
5072
5114
|
logDebug(`Custom event tracked: ${eventName}`, properties);
|
|
5073
5115
|
}
|
|
5074
5116
|
catch (error) {
|
|
5075
5117
|
logError('Failed to track custom event:', error);
|
|
5118
|
+
// Fallback: add to event stream if direct API call fails
|
|
5119
|
+
try {
|
|
5120
|
+
const customEventData = {
|
|
5121
|
+
eventName: eventName,
|
|
5122
|
+
properties: properties || {},
|
|
5123
|
+
timestamp: new Date().toISOString(),
|
|
5124
|
+
url: window.location.href,
|
|
5125
|
+
pathname: window.location.pathname
|
|
5126
|
+
};
|
|
5127
|
+
yield this.addEvent({
|
|
5128
|
+
type: 5, // Custom event type
|
|
5129
|
+
data: {
|
|
5130
|
+
payload: Object.assign({ eventType: 'custom' }, customEventData)
|
|
5131
|
+
},
|
|
5132
|
+
timestamp: Date.now()
|
|
5133
|
+
});
|
|
5134
|
+
logDebug(`Custom event added to event stream as fallback: ${eventName}`);
|
|
5135
|
+
}
|
|
5136
|
+
catch (fallbackError) {
|
|
5137
|
+
logError('Failed to add custom event to event stream as fallback:', fallbackError);
|
|
5138
|
+
}
|
|
5076
5139
|
}
|
|
5077
5140
|
});
|
|
5078
5141
|
}
|
|
5142
|
+
/**
|
|
5143
|
+
* Setup automatic tracking for buttons, links, and forms
|
|
5144
|
+
*/
|
|
5145
|
+
setupAutomaticTracking(options) {
|
|
5146
|
+
if (!isBrowser)
|
|
5147
|
+
return;
|
|
5148
|
+
const config = {
|
|
5149
|
+
trackButtons: (options === null || options === void 0 ? void 0 : options.trackButtons) !== false,
|
|
5150
|
+
trackLinks: (options === null || options === void 0 ? void 0 : options.trackLinks) !== false,
|
|
5151
|
+
trackForms: (options === null || options === void 0 ? void 0 : options.trackForms) !== false,
|
|
5152
|
+
includeText: (options === null || options === void 0 ? void 0 : options.includeText) !== false,
|
|
5153
|
+
includeClasses: (options === null || options === void 0 ? void 0 : options.includeClasses) || false
|
|
5154
|
+
};
|
|
5155
|
+
logDebug('Setting up automatic tracking with config:', config);
|
|
5156
|
+
// Setup button tracking
|
|
5157
|
+
if (config.trackButtons) {
|
|
5158
|
+
this.setupAutomaticButtonTracking(config);
|
|
5159
|
+
}
|
|
5160
|
+
// Setup link tracking
|
|
5161
|
+
if (config.trackLinks) {
|
|
5162
|
+
this.setupAutomaticLinkTracking(config);
|
|
5163
|
+
}
|
|
5164
|
+
// Setup form tracking
|
|
5165
|
+
if (config.trackForms) {
|
|
5166
|
+
this.setupAutomaticFormTracking(config);
|
|
5167
|
+
}
|
|
5168
|
+
}
|
|
5169
|
+
/**
|
|
5170
|
+
* Setup automatic button tracking
|
|
5171
|
+
*/
|
|
5172
|
+
setupAutomaticButtonTracking(config) {
|
|
5173
|
+
document.addEventListener('click', (event) => __awaiter$1(this, void 0, void 0, function* () {
|
|
5174
|
+
var _a;
|
|
5175
|
+
const target = event.target;
|
|
5176
|
+
// Track button clicks
|
|
5177
|
+
if (target.tagName === 'BUTTON' || target.closest('button')) {
|
|
5178
|
+
const button = target.tagName === 'BUTTON'
|
|
5179
|
+
? target
|
|
5180
|
+
: target.closest('button');
|
|
5181
|
+
const properties = {
|
|
5182
|
+
buttonId: button.id || null,
|
|
5183
|
+
buttonType: button.type || 'button',
|
|
5184
|
+
page: window.location.pathname,
|
|
5185
|
+
timestamp: Date.now()
|
|
5186
|
+
};
|
|
5187
|
+
if (config.includeText) {
|
|
5188
|
+
properties.buttonText = ((_a = button.textContent) === null || _a === void 0 ? void 0 : _a.trim()) || null;
|
|
5189
|
+
}
|
|
5190
|
+
if (config.includeClasses) {
|
|
5191
|
+
properties.buttonClass = button.className || null;
|
|
5192
|
+
}
|
|
5193
|
+
// Remove null values
|
|
5194
|
+
Object.keys(properties).forEach(key => {
|
|
5195
|
+
if (properties[key] === null) {
|
|
5196
|
+
delete properties[key];
|
|
5197
|
+
}
|
|
5198
|
+
});
|
|
5199
|
+
yield this.customEvent('button_clicked', properties);
|
|
5200
|
+
}
|
|
5201
|
+
}));
|
|
5202
|
+
}
|
|
5203
|
+
/**
|
|
5204
|
+
* Setup automatic link tracking
|
|
5205
|
+
*/
|
|
5206
|
+
setupAutomaticLinkTracking(config) {
|
|
5207
|
+
document.addEventListener('click', (event) => __awaiter$1(this, void 0, void 0, function* () {
|
|
5208
|
+
var _a;
|
|
5209
|
+
const target = event.target;
|
|
5210
|
+
// Track link clicks
|
|
5211
|
+
if (target.tagName === 'A' || target.closest('a')) {
|
|
5212
|
+
const link = target.tagName === 'A'
|
|
5213
|
+
? target
|
|
5214
|
+
: target.closest('a');
|
|
5215
|
+
const properties = {
|
|
5216
|
+
linkUrl: link.href || null,
|
|
5217
|
+
linkId: link.id || null,
|
|
5218
|
+
linkTarget: link.target || null,
|
|
5219
|
+
page: window.location.pathname,
|
|
5220
|
+
timestamp: Date.now()
|
|
5221
|
+
};
|
|
5222
|
+
if (config.includeText) {
|
|
5223
|
+
properties.linkText = ((_a = link.textContent) === null || _a === void 0 ? void 0 : _a.trim()) || null;
|
|
5224
|
+
}
|
|
5225
|
+
if (config.includeClasses) {
|
|
5226
|
+
properties.linkClass = link.className || null;
|
|
5227
|
+
}
|
|
5228
|
+
// Remove null values
|
|
5229
|
+
Object.keys(properties).forEach(key => {
|
|
5230
|
+
if (properties[key] === null) {
|
|
5231
|
+
delete properties[key];
|
|
5232
|
+
}
|
|
5233
|
+
});
|
|
5234
|
+
yield this.customEvent('link_clicked', properties);
|
|
5235
|
+
}
|
|
5236
|
+
}));
|
|
5237
|
+
}
|
|
5238
|
+
/**
|
|
5239
|
+
* Setup automatic form tracking
|
|
5240
|
+
*/
|
|
5241
|
+
setupAutomaticFormTracking(config) {
|
|
5242
|
+
document.addEventListener('submit', (event) => __awaiter$1(this, void 0, void 0, function* () {
|
|
5243
|
+
const form = event.target;
|
|
5244
|
+
const formData = new FormData(form);
|
|
5245
|
+
const properties = {
|
|
5246
|
+
formId: form.id || null,
|
|
5247
|
+
formAction: form.action || null,
|
|
5248
|
+
formMethod: form.method || 'get',
|
|
5249
|
+
fields: Array.from(formData.keys()),
|
|
5250
|
+
page: window.location.pathname,
|
|
5251
|
+
timestamp: Date.now()
|
|
5252
|
+
};
|
|
5253
|
+
if (config.includeClasses) {
|
|
5254
|
+
properties.formClass = form.className || null;
|
|
5255
|
+
}
|
|
5256
|
+
// Remove null values
|
|
5257
|
+
Object.keys(properties).forEach(key => {
|
|
5258
|
+
if (properties[key] === null) {
|
|
5259
|
+
delete properties[key];
|
|
5260
|
+
}
|
|
5261
|
+
});
|
|
5262
|
+
yield this.customEvent('form_submitted', properties);
|
|
5263
|
+
}));
|
|
5264
|
+
}
|
|
5079
5265
|
/**
|
|
5080
5266
|
* Cleanup navigation tracking
|
|
5081
5267
|
*/
|
|
@@ -5271,6 +5457,7 @@ class HumanBehaviorTracker {
|
|
|
5271
5457
|
inlineStylesheet: true,
|
|
5272
5458
|
recordCanvas: true,
|
|
5273
5459
|
collectFonts: true,
|
|
5460
|
+
inlineImages: true,
|
|
5274
5461
|
blockClass: 'rr-block',
|
|
5275
5462
|
ignoreClass: 'rr-ignore',
|
|
5276
5463
|
maskTextClass: 'rr-ignore'
|