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