humanbehavior-js 0.0.8 → 0.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/dist/cjs/index.js +558 -184
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/react/index.js +197 -86
- package/dist/cjs/react/index.js.map +1 -1
- package/dist/esm/index.js +554 -185
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/react/index.js +195 -87
- package/dist/esm/react/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 +115 -10
- package/dist/types/react/index.d.ts +8 -9
- package/package.json +3 -2
- package/readme.md +127 -105
- package/simple-spa.html +544 -0
- package/src/api.ts +9 -137
- package/src/index.ts +3 -0
- package/src/react/index.tsx +137 -81
- package/src/redact.ts +19 -17
- package/src/tracker.ts +498 -62
- package/src/utils/logger.ts +144 -0
package/dist/types/index.d.ts
CHANGED
|
@@ -83,6 +83,7 @@ declare const redactionManager: RedactionManager;
|
|
|
83
83
|
declare global {
|
|
84
84
|
interface Window {
|
|
85
85
|
HumanBehaviorTracker: typeof HumanBehaviorTracker;
|
|
86
|
+
__humanBehaviorGlobalTracker?: HumanBehaviorTracker;
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
declare class HumanBehaviorTracker {
|
|
@@ -101,10 +102,66 @@ declare class HumanBehaviorTracker {
|
|
|
101
102
|
private initialized;
|
|
102
103
|
initializationPromise: Promise<void> | null;
|
|
103
104
|
private redactionManager;
|
|
105
|
+
private originalConsole;
|
|
106
|
+
private consoleTrackingEnabled;
|
|
107
|
+
navigationTrackingEnabled: boolean;
|
|
108
|
+
private currentUrl;
|
|
109
|
+
private previousUrl;
|
|
110
|
+
private originalPushState;
|
|
111
|
+
private originalReplaceState;
|
|
112
|
+
private navigationListeners;
|
|
113
|
+
private _connectionBlocked;
|
|
114
|
+
/**
|
|
115
|
+
* Initialize the HumanBehavior tracker
|
|
116
|
+
* This is the main entry point - call this once per page
|
|
117
|
+
*/
|
|
118
|
+
static init(apiKey: string, options?: {
|
|
119
|
+
ingestionUrl?: string;
|
|
120
|
+
logLevel?: 'none' | 'error' | 'warn' | 'info' | 'debug';
|
|
121
|
+
redactFields?: string[];
|
|
122
|
+
}): HumanBehaviorTracker;
|
|
104
123
|
constructor(apiKey: string | undefined, ingestionUrl?: string);
|
|
105
124
|
private init;
|
|
106
125
|
private ensureInitialized;
|
|
126
|
+
/**
|
|
127
|
+
* Setup navigation event tracking for SPA navigation
|
|
128
|
+
*/
|
|
129
|
+
private setupNavigationTracking;
|
|
130
|
+
/**
|
|
131
|
+
* Track navigation events and send custom events
|
|
132
|
+
*/
|
|
133
|
+
trackNavigationEvent(type: string, fromUrl: string, toUrl: string): Promise<void>;
|
|
134
|
+
/**
|
|
135
|
+
* Track a page view event (PostHog-style)
|
|
136
|
+
*/
|
|
137
|
+
trackPageView(url?: string): Promise<void>;
|
|
138
|
+
/**
|
|
139
|
+
* Track a custom event (PostHog-style)
|
|
140
|
+
*/
|
|
141
|
+
customEvent(eventName: string, properties?: Record<string, any>): Promise<void>;
|
|
142
|
+
/**
|
|
143
|
+
* Cleanup navigation tracking
|
|
144
|
+
*/
|
|
145
|
+
private cleanupNavigationTracking;
|
|
107
146
|
static logToStorage(message: string): void;
|
|
147
|
+
/**
|
|
148
|
+
* Configure logging behavior for the SDK
|
|
149
|
+
* @param config Logger configuration options
|
|
150
|
+
*/
|
|
151
|
+
static configureLogging(config: {
|
|
152
|
+
level?: 'none' | 'error' | 'warn' | 'info' | 'debug';
|
|
153
|
+
enableConsole?: boolean;
|
|
154
|
+
enableStorage?: boolean;
|
|
155
|
+
}): void;
|
|
156
|
+
/**
|
|
157
|
+
* Enable console event tracking
|
|
158
|
+
*/
|
|
159
|
+
enableConsoleTracking(): void;
|
|
160
|
+
/**
|
|
161
|
+
* Disable console event tracking
|
|
162
|
+
*/
|
|
163
|
+
disableConsoleTracking(): void;
|
|
164
|
+
private trackConsoleEvent;
|
|
108
165
|
private setupPageUnloadHandler;
|
|
109
166
|
viewLogs(): void;
|
|
110
167
|
addUserInfo(userProperties: Record<string, any>): Promise<void>;
|
|
@@ -113,7 +170,6 @@ declare class HumanBehaviorTracker {
|
|
|
113
170
|
* @param authFields Array of field names to check for existing users (e.g., ['email', 'phoneNumber'])
|
|
114
171
|
*/
|
|
115
172
|
auth(authFields: string[]): Promise<void>;
|
|
116
|
-
customEvent(eventName: string, eventProperties?: Record<string, any>): Promise<void>;
|
|
117
173
|
start(): Promise<void>;
|
|
118
174
|
stop(): Promise<void>;
|
|
119
175
|
addEvent(event: any): Promise<void>;
|
|
@@ -139,6 +195,28 @@ declare class HumanBehaviorTracker {
|
|
|
139
195
|
* Get the currently selected fields for redaction
|
|
140
196
|
*/
|
|
141
197
|
getRedactedFields(): string[];
|
|
198
|
+
/**
|
|
199
|
+
* Get the current session ID
|
|
200
|
+
*/
|
|
201
|
+
getSessionId(): string;
|
|
202
|
+
/**
|
|
203
|
+
* Get the current URL being tracked
|
|
204
|
+
*/
|
|
205
|
+
getCurrentUrl(): string;
|
|
206
|
+
/**
|
|
207
|
+
* Test if the tracker can reach the ingestion server
|
|
208
|
+
*/
|
|
209
|
+
testConnection(): Promise<{
|
|
210
|
+
success: boolean;
|
|
211
|
+
error?: string;
|
|
212
|
+
}>;
|
|
213
|
+
/**
|
|
214
|
+
* Get connection status and recommendations
|
|
215
|
+
*/
|
|
216
|
+
getConnectionStatus(): {
|
|
217
|
+
blocked: boolean;
|
|
218
|
+
recommendations: string[];
|
|
219
|
+
};
|
|
142
220
|
}
|
|
143
221
|
|
|
144
222
|
declare const MAX_CHUNK_SIZE_BYTES: number;
|
|
@@ -159,14 +237,41 @@ declare class HumanBehaviorAPI {
|
|
|
159
237
|
sendEventsChunked(events: any[], sessionId: string): Promise<any[]>;
|
|
160
238
|
sendUserData(userId: string, userData: Record<string, any>, sessionId: string): Promise<any>;
|
|
161
239
|
sendUserAuth(userId: string, userData: Record<string, any>, sessionId: string, authFields: string[]): Promise<any>;
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
240
|
+
sendBeaconEvents(events: any[], sessionId: string): void;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
declare enum LogLevel {
|
|
244
|
+
NONE = 0,
|
|
245
|
+
ERROR = 1,
|
|
246
|
+
WARN = 2,
|
|
247
|
+
INFO = 3,
|
|
248
|
+
DEBUG = 4
|
|
249
|
+
}
|
|
250
|
+
interface LoggerConfig {
|
|
251
|
+
level: LogLevel;
|
|
252
|
+
enableConsole: boolean;
|
|
253
|
+
enableStorage: boolean;
|
|
254
|
+
}
|
|
255
|
+
declare class Logger {
|
|
256
|
+
private config;
|
|
257
|
+
private isBrowser;
|
|
258
|
+
constructor(config?: Partial<LoggerConfig>);
|
|
259
|
+
setConfig(config: Partial<LoggerConfig>): void;
|
|
260
|
+
private shouldLog;
|
|
261
|
+
private formatMessage;
|
|
262
|
+
error(message: string, ...args: any[]): void;
|
|
263
|
+
warn(message: string, ...args: any[]): void;
|
|
264
|
+
info(message: string, ...args: any[]): void;
|
|
265
|
+
debug(message: string, ...args: any[]): void;
|
|
266
|
+
private logToStorage;
|
|
267
|
+
getLogs(): any[];
|
|
268
|
+
clearLogs(): void;
|
|
169
269
|
}
|
|
270
|
+
declare const logger: Logger;
|
|
271
|
+
declare const logError: (message: string, ...args: any[]) => void;
|
|
272
|
+
declare const logWarn: (message: string, ...args: any[]) => void;
|
|
273
|
+
declare const logInfo: (message: string, ...args: any[]) => void;
|
|
274
|
+
declare const logDebug: (message: string, ...args: any[]) => void;
|
|
170
275
|
|
|
171
|
-
export { HumanBehaviorAPI, HumanBehaviorTracker, MAX_CHUNK_SIZE_BYTES, RedactionManager, HumanBehaviorTracker as default, isChunkSizeExceeded, redactionManager, validateSingleEventSize };
|
|
172
|
-
export type { RedactionOptions };
|
|
276
|
+
export { HumanBehaviorAPI, HumanBehaviorTracker, LogLevel, MAX_CHUNK_SIZE_BYTES, RedactionManager, HumanBehaviorTracker as default, isChunkSizeExceeded, logDebug, logError, logInfo, logWarn, logger, redactionManager, validateSingleEventSize };
|
|
277
|
+
export type { LoggerConfig, RedactionOptions };
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import React, { ReactNode } from 'react';
|
|
2
2
|
import { HumanBehaviorTracker } from '..';
|
|
3
|
+
export { HumanBehaviorTracker } from '..';
|
|
3
4
|
|
|
4
|
-
interface HumanBehaviorInterface {
|
|
5
|
-
addEvent: (event: any) => void;
|
|
6
|
-
addUserInfo: (userProperties: Record<string, any>) => Promise<void>;
|
|
7
|
-
start: () => void;
|
|
8
|
-
stop: () => void;
|
|
9
|
-
viewLogs: () => void;
|
|
10
|
-
}
|
|
11
5
|
interface HumanBehaviorProviderProps {
|
|
12
6
|
apiKey?: string;
|
|
13
7
|
client?: HumanBehaviorTracker;
|
|
14
8
|
children: ReactNode;
|
|
9
|
+
options?: {
|
|
10
|
+
ingestionUrl?: string;
|
|
11
|
+
logLevel?: 'none' | 'error' | 'warn' | 'info' | 'debug';
|
|
12
|
+
redactFields?: string[];
|
|
13
|
+
};
|
|
15
14
|
}
|
|
16
|
-
declare const HumanBehaviorProvider: ({ apiKey, client, children }: HumanBehaviorProviderProps) => React.JSX.Element;
|
|
17
|
-
declare const useHumanBehavior: () =>
|
|
15
|
+
declare const HumanBehaviorProvider: ({ apiKey, client, children, options }: HumanBehaviorProviderProps) => React.JSX.Element;
|
|
16
|
+
declare const useHumanBehavior: () => HumanBehaviorTracker;
|
|
18
17
|
|
|
19
18
|
export { HumanBehaviorProvider, useHumanBehavior };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "humanbehavior-js",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "SDK for HumanBehavior session and event recording",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"license": "ISC",
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@types/react": "^19.0.12",
|
|
32
|
+
"humanbehavior-js": "^0.0.9",
|
|
32
33
|
"react": "^19.0.0",
|
|
33
34
|
"rrweb": "^2.0.0-alpha.4",
|
|
34
35
|
"uuid": "^11.1.0"
|
|
@@ -49,7 +50,7 @@
|
|
|
49
50
|
},
|
|
50
51
|
"repository": {
|
|
51
52
|
"type": "git",
|
|
52
|
-
"url": "https://github.com/humanbehavior-gh/HumanBehavior.git"
|
|
53
|
+
"url": "git+https://github.com/humanbehavior-gh/HumanBehavior.git"
|
|
53
54
|
},
|
|
54
55
|
"keywords": [
|
|
55
56
|
"session-recording",
|
package/readme.md
CHANGED
|
@@ -1,145 +1,167 @@
|
|
|
1
1
|
# HumanBehavior SDK
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A simplified session recording and analytics SDK that maintains session continuity across page navigations.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Quick Start
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
### Single Page Application (Recommended)
|
|
8
|
+
|
|
9
|
+
For the best session continuity experience, use the SPA approach:
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<!DOCTYPE html>
|
|
13
|
+
<html>
|
|
14
|
+
<head>
|
|
15
|
+
<script src="dist/index.min.js"></script>
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
<script>
|
|
19
|
+
// Initialize once - session persists across all navigation
|
|
20
|
+
const tracker = HumanBehaviorTracker.init('your-api-key', {
|
|
21
|
+
logLevel: 'debug',
|
|
22
|
+
redactFields: ['password', 'credit_card']
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Your SPA navigation logic here
|
|
26
|
+
function navigateToPage(page) {
|
|
27
|
+
// Update content without page reload
|
|
28
|
+
loadPageContent(page);
|
|
29
|
+
|
|
30
|
+
// Track navigation
|
|
31
|
+
tracker.trackNavigationEvent('spa_navigation', currentPage, page);
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
</body>
|
|
35
|
+
</html>
|
|
9
36
|
```
|
|
10
37
|
|
|
11
|
-
|
|
38
|
+
### Traditional Multi-Page Setup
|
|
12
39
|
|
|
13
|
-
|
|
40
|
+
For traditional HTML pages, the tracker will automatically restore sessions:
|
|
14
41
|
|
|
15
42
|
```html
|
|
16
|
-
|
|
43
|
+
<!-- index.html -->
|
|
44
|
+
<script src="dist/index.min.js"></script>
|
|
17
45
|
<script>
|
|
18
|
-
const tracker =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
46
|
+
const tracker = HumanBehaviorTracker.init('your-api-key');
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<!-- about.html -->
|
|
50
|
+
<script src="dist/index.min.js"></script>
|
|
51
|
+
<script>
|
|
52
|
+
const tracker = HumanBehaviorTracker.init('your-api-key'); // Reuses existing session
|
|
23
53
|
</script>
|
|
24
54
|
```
|
|
25
55
|
|
|
26
|
-
|
|
56
|
+
## API Reference
|
|
57
|
+
|
|
58
|
+
### Initialization
|
|
27
59
|
|
|
28
|
-
|
|
60
|
+
```javascript
|
|
61
|
+
// Main initialization method
|
|
62
|
+
const tracker = HumanBehaviorTracker.init(apiKey, options);
|
|
63
|
+
```
|
|
29
64
|
|
|
30
|
-
|
|
31
|
-
|
|
65
|
+
**Options:**
|
|
66
|
+
- `ingestionUrl`: Custom ingestion server URL
|
|
67
|
+
- `logLevel`: 'none' | 'error' | 'warn' | 'info' | 'debug'
|
|
68
|
+
- `redactFields`: Array of CSS selectors to redact
|
|
32
69
|
|
|
33
|
-
|
|
34
|
-
import { HumanBehaviorProvider } from "humanbehavior-js/react";
|
|
35
|
-
import { useEffect, useState } from "react";
|
|
70
|
+
### Session Management
|
|
36
71
|
|
|
37
|
-
|
|
38
|
-
|
|
72
|
+
```javascript
|
|
73
|
+
// Get current session ID
|
|
74
|
+
const sessionId = tracker.getSessionId();
|
|
39
75
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
}, []);
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<HumanBehaviorProvider client={tracker}>
|
|
50
|
-
{children}
|
|
51
|
-
</HumanBehaviorProvider>
|
|
52
|
-
)
|
|
53
|
-
}
|
|
76
|
+
// Get current URL
|
|
77
|
+
const currentUrl = tracker.getCurrentUrl();
|
|
78
|
+
|
|
79
|
+
// Test connection to ingestion server
|
|
80
|
+
const result = await tracker.testConnection();
|
|
54
81
|
```
|
|
55
82
|
|
|
56
|
-
|
|
83
|
+
### Event Tracking
|
|
57
84
|
|
|
58
|
-
```
|
|
59
|
-
|
|
85
|
+
```javascript
|
|
86
|
+
// Track custom events
|
|
87
|
+
await tracker.customEvent('button_click', { button: 'submit' });
|
|
60
88
|
|
|
61
|
-
|
|
89
|
+
// Track page views
|
|
90
|
+
await tracker.trackPageView();
|
|
62
91
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
<HumanBehaviorProvider apiKey={process.env.NEXT_PUBLIC_HUMANBEHAVIOR_API_KEY}>
|
|
66
|
-
{children}
|
|
67
|
-
</HumanBehaviorProvider>
|
|
68
|
-
)
|
|
69
|
-
}
|
|
92
|
+
// Track navigation (for SPAs)
|
|
93
|
+
await tracker.trackNavigationEvent('pushState', '/home', '/about');
|
|
70
94
|
```
|
|
71
95
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
```tsx
|
|
75
|
-
export default async function RootLayout({
|
|
76
|
-
children
|
|
77
|
-
}: {
|
|
78
|
-
children: React.ReactNode;
|
|
79
|
-
}) {
|
|
80
|
-
return (
|
|
81
|
-
<html lang='en' suppressHydrationWarning>
|
|
82
|
-
<body>
|
|
83
|
-
<HumanBehaviorProviderWrapper>
|
|
84
|
-
{children}
|
|
85
|
-
</HumanBehaviorProviderWrapper>
|
|
86
|
-
</body>
|
|
87
|
-
</html>
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
```
|
|
96
|
+
### Data Redaction
|
|
91
97
|
|
|
92
|
-
|
|
98
|
+
```javascript
|
|
99
|
+
// Redact sensitive fields
|
|
100
|
+
tracker.setRedactedFields(['input[type="password"]', '#email']);
|
|
93
101
|
|
|
94
|
-
|
|
102
|
+
// Check if redaction is active
|
|
103
|
+
const isActive = tracker.isRedactedFields();
|
|
104
|
+
```
|
|
95
105
|
|
|
96
|
-
|
|
97
|
-
import { useHumanBehavior } from "humanbehavior-js/react";
|
|
106
|
+
### Debugging
|
|
98
107
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
email: "user@example.com",
|
|
106
|
-
name: "John Doe"
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
// Track custom events
|
|
110
|
-
humanBehavior.addEvent({
|
|
111
|
-
type: "custom",
|
|
112
|
-
name: "button_clicked",
|
|
113
|
-
data: { buttonId: "submit" }
|
|
114
|
-
});
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
return <button onClick={handleUserAction}>Click me</button>;
|
|
118
|
-
}
|
|
108
|
+
```javascript
|
|
109
|
+
// View logs
|
|
110
|
+
tracker.viewLogs();
|
|
111
|
+
|
|
112
|
+
// Get connection status
|
|
113
|
+
const status = tracker.getConnectionStatus();
|
|
119
114
|
```
|
|
120
115
|
|
|
121
|
-
##
|
|
116
|
+
## Session Continuity
|
|
122
117
|
|
|
123
|
-
|
|
118
|
+
The SDK automatically handles session continuity:
|
|
124
119
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
120
|
+
1. **Session Restoration**: Automatically restores sessions within 30 minutes
|
|
121
|
+
2. **Activity Tracking**: Updates activity timestamp on user interactions
|
|
122
|
+
3. **Cross-Page Persistence**: Session persists across page navigations
|
|
123
|
+
|
|
124
|
+
## Demo
|
|
125
|
+
|
|
126
|
+
Check out `simple-spa.html` for a complete single-page application demo that shows:
|
|
127
|
+
|
|
128
|
+
- True session continuity across navigation
|
|
129
|
+
- Interactive event tracking
|
|
130
|
+
- Real-time status updates
|
|
131
|
+
- Modern UI with smooth transitions
|
|
130
132
|
|
|
131
|
-
##
|
|
133
|
+
## Troubleshooting
|
|
132
134
|
|
|
133
|
-
|
|
134
|
-
- **Data Redaction**: Protect sensitive information in recordings
|
|
135
|
-
- **User Identification**: Track users across sessions
|
|
136
|
-
- **Custom Events**: Send custom analytics events
|
|
137
|
-
- **React Integration**: Hooks and providers for React applications
|
|
135
|
+
### Ad Blocker Issues
|
|
138
136
|
|
|
139
|
-
|
|
137
|
+
If you see `net::ERR_BLOCKED_BY_CLIENT` errors:
|
|
140
138
|
|
|
141
|
-
|
|
139
|
+
1. Check if ad blockers are active
|
|
140
|
+
2. Use `tracker.getConnectionStatus()` to diagnose
|
|
141
|
+
3. Consider whitelisting your domain
|
|
142
|
+
|
|
143
|
+
### Session Issues
|
|
144
|
+
|
|
145
|
+
- Sessions automatically expire after 30 minutes of inactivity
|
|
146
|
+
- Each page load calls `/init` but reuses existing sessions when possible
|
|
147
|
+
- Check browser console for session restoration logs
|
|
148
|
+
|
|
149
|
+
## Development
|
|
142
150
|
|
|
143
151
|
```bash
|
|
152
|
+
# Build the SDK
|
|
144
153
|
npm run build
|
|
145
|
-
|
|
154
|
+
|
|
155
|
+
# Watch for changes
|
|
156
|
+
npm run dev
|
|
157
|
+
|
|
158
|
+
# Run tests
|
|
159
|
+
npm test
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Architecture
|
|
163
|
+
|
|
164
|
+
- **Frontend**: TypeScript SDK with session restoration
|
|
165
|
+
- **Backend**: Node.js ingestion server with Redis storage
|
|
166
|
+
- **Archiver**: Processes completed sessions to S3 and Prisma
|
|
167
|
+
- **Session Continuity**: localStorage + cookie-based session management
|