@multiplayer-app/session-recorder-browser 0.0.1

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.
Files changed (59) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +560 -0
  3. package/dist/browser/index.js +50249 -0
  4. package/dist/browser/index.js.map +1 -0
  5. package/dist/common/SessionRecorderHttpInstrumentationHooksNode.d.ts.map +1 -0
  6. package/dist/common/SessionRecorderHttpTraceExporterBrowser.d.ts.map +1 -0
  7. package/dist/common/SessionRecorderIdGenerator.d.ts.map +1 -0
  8. package/dist/common/SessionRecorderJsonTraceSerializer.d.ts.map +1 -0
  9. package/dist/common/SessionRecorderTraceIdRatioBasedSampler.d.ts.map +1 -0
  10. package/dist/common/constants.base.d.ts.map +1 -0
  11. package/dist/common/constants.browser.d.ts.map +1 -0
  12. package/dist/common/constants.node.d.ts.map +1 -0
  13. package/dist/common/index-browser.d.ts.map +1 -0
  14. package/dist/common/index-node.d.ts.map +1 -0
  15. package/dist/common/index.d.ts.map +1 -0
  16. package/dist/common/sdk/capture-exception.d.ts.map +1 -0
  17. package/dist/common/sdk/id-generator.d.ts.map +1 -0
  18. package/dist/common/sdk/index.d.ts.map +1 -0
  19. package/dist/common/sdk/is-gzip.d.ts.map +1 -0
  20. package/dist/common/sdk/mask.d.ts.map +1 -0
  21. package/dist/common/sdk/save-continuous-deb-session.d.ts.map +1 -0
  22. package/dist/common/sdk/schemify.d.ts.map +1 -0
  23. package/dist/common/sdk/set-attribute.d.ts.map +1 -0
  24. package/dist/common/type/index.d.ts.map +1 -0
  25. package/dist/common/type/session-type.enum.d.ts.map +1 -0
  26. package/dist/config/defaults.d.ts.map +1 -0
  27. package/dist/config/index.d.ts.map +1 -0
  28. package/dist/config/masking.d.ts.map +1 -0
  29. package/dist/config/session-recorder.d.ts.map +1 -0
  30. package/dist/exporters/index.js +3 -0
  31. package/dist/exporters/index.js.LICENSE.txt +725 -0
  32. package/dist/exporters/index.js.map +1 -0
  33. package/dist/exporters.d.ts.map +1 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +3 -0
  36. package/dist/index.js.LICENSE.txt +1661 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/listeners.d.ts.map +1 -0
  39. package/dist/otel/helpers.d.ts.map +1 -0
  40. package/dist/otel/index.d.ts.map +1 -0
  41. package/dist/patch/index.d.ts.map +1 -0
  42. package/dist/patch/xhr.d.ts.map +1 -0
  43. package/dist/rrweb/exporter.d.ts.map +1 -0
  44. package/dist/rrweb/index.d.ts.map +1 -0
  45. package/dist/services/api.service.d.ts.map +1 -0
  46. package/dist/sessionRecorder.d.ts.map +1 -0
  47. package/dist/sessionWidget/UIManager.d.ts.map +1 -0
  48. package/dist/sessionWidget/buttonStateConfigs.d.ts.map +1 -0
  49. package/dist/sessionWidget/index.d.ts.map +1 -0
  50. package/dist/sessionWidget/templates/finalPopover.d.ts.map +1 -0
  51. package/dist/sessionWidget/templates/initialPopover.d.ts.map +1 -0
  52. package/dist/sessionWidget/templates/toast.d.ts.map +1 -0
  53. package/dist/types/index.d.ts.map +1 -0
  54. package/dist/types/session.d.ts.map +1 -0
  55. package/dist/types/sessionRecorder.d.ts.map +1 -0
  56. package/dist/utils/index.d.ts.map +1 -0
  57. package/dist/utils/navigator.d.ts.map +1 -0
  58. package/dist/utils/request-utils.d.ts.map +1 -0
  59. package/package.json +75 -0
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+
2
+ MIT License
3
+
4
+ Copyright (c) 2024 Multiplayer Software, Inc.
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,560 @@
1
+ # Multiplayer Session Recorder
2
+
3
+ The Multiplayer **Session Recorder** is a powerful tool that offers deep session replays with insights spanning frontend screens, platform traces, metrics, and logs. It helps your team pinpoint and resolve bugs faster by providing a complete picture of your backend system architecture. No more wasted hours combing through APM data; the Multiplayer Session Recorder does it all in one place.
4
+
5
+ ## Key Features
6
+
7
+ - **Reduced Inefficiencies**: Effortlessly capture the exact steps to reproduce an issue along with backend data in one click. No more hunting through scattered documentation, APM data, logs, or traces.
8
+ - **Faster Cross-Team Alignment**: Engineers can share session links containing all relevant information, eliminating the need for long tickets or clarifying issues through back-and-forth communication.
9
+ - **Uninterrupted Deep Work**: All system information—from architecture diagrams to API designs—is consolidated in one place. Minimize context switching and stay focused on what matters.
10
+
11
+ ## Getting Started
12
+
13
+ ### Installation
14
+
15
+ You can install the Multiplayer Session Recorder using npm or yarn:
16
+
17
+ ```bash
18
+ npm install @multiplayer-app/session-recorder-browser
19
+ # or
20
+ yarn add @multiplayer-app/session-recorder-browser
21
+ ```
22
+
23
+ ### Basic Setup
24
+
25
+ To initialize the Multiplayer Session Recorder in your application, follow the steps below.
26
+
27
+ #### Import the Session Recorder
28
+
29
+ ```javascript
30
+ import SessionRecorder from '@multiplayer-app/session-recorder-browser'
31
+ ```
32
+
33
+ #### Initialization
34
+
35
+ Use the following code to initialize the session recorder with your application details:
36
+
37
+ ```javascript
38
+ SessionRecorder.init({
39
+ version: '{YOUR_APPLICATION_VERSION}',
40
+ application: '{YOUR_APPLICATION_NAME}',
41
+ environment: '{YOUR_APPLICATION_ENVIRONMENT}',
42
+ apiKey: '{YOUR_API_KEY}'
43
+ })
44
+ ```
45
+
46
+ Replace the placeholders with your application’s version, name, environment, and API key (OpenTelemetry Frontend Token).
47
+
48
+ #### Add User attributes
49
+
50
+ To track user-specific attributes in session replays, add the following:
51
+
52
+ ```javascript
53
+ SessionRecorder.setSessionAttributes({
54
+ userId: '{userId}',
55
+ userName: '{userName}'
56
+ })
57
+ ```
58
+
59
+ Replace the placeholders with the actual user information (e.g., user ID and username).
60
+
61
+ ## Dependencies
62
+
63
+ This library relies on the following packages:
64
+
65
+ - **[rrweb](https://github.com/rrweb-io/rrweb)**: Provides the frontend session replay functionality, recording the user’s interactions with the app.
66
+ - **[OpenTelemetry](https://opentelemetry.io/)**: Used to capture backend traces, metrics, and logs that integrate seamlessly with the session replays for comprehensive debugging.
67
+
68
+ ## Configuration Options
69
+
70
+ The Session Recorder supports various configuration options with sensible defaults:
71
+
72
+ ### Default Values
73
+
74
+ - `showWidget`: `true` - Show the recording widget by default
75
+ - `recordCanvas`: `false` - Disable canvas recording by default
76
+ - `docTraceRatio`: `0.15` - 15% of traces for auto-documentation
77
+ - `sampleTraceRatio`: `0.15` - 15% sampling ratio
78
+ - `schemifyDocSpanPayload`: `true` - Enable payload schematization
79
+ - `maxCapturingHttpPayloadSize`: `100000` - 100KB max payload size
80
+ - `usePostMessageFallback`: `false` - Disable post message fallback
81
+ - `widgetButtonPlacement`: `'bottom-right'` - Default widget position
82
+ - `masking.maskAllInputs`: `true` - Mask all inputs by default
83
+ - `masking.isMaskingEnabled`: `true` - Enable masking for debug span payload by default
84
+ - `captureBody`: `true` - Capture body in traces by default
85
+ - `captureHeaders`: `true` - Capture headers in traces by default
86
+
87
+ ## Example Usage
88
+
89
+ ```javascript
90
+ import SessionRecorder from '@multiplayer-app/debugger-browser'
91
+
92
+ SessionRecorder.init({
93
+ version: '1.0.0',
94
+ application: 'my-app',
95
+ environment: 'production',
96
+ apiKey: 'your-api-key',
97
+ showWidget: true,
98
+ recordCanvas: true,
99
+ ignoreUrls: [
100
+ /https:\/\/domain\.to\.ignore\/.*/, // can be regex or string
101
+ /https:\/\/another\.domain\.to\.ignore\/.*/
102
+ ],
103
+ // NOTE: if frontend domain doesn't match to backend one, set backend domain to `propagateTraceHeaderCorsUrls` parameter
104
+ propagateTraceHeaderCorsUrls: [
105
+ new RegExp('https://your.backend.api.domain', 'i'), // can be regex or string
106
+ new RegExp('https://another.backend.api.domain', 'i')
107
+ ],
108
+ docTraceRatio: 0.15, // 15% of traces will be sent for auto-documentation
109
+ sampleTraceRatio: 0.15, // 15% sampling ratio
110
+ schemifyDocSpanPayload: true,
111
+ maxCapturingHttpPayloadSize: 100000,
112
+ usePostMessageFallback: false, // Enable post message fallback if needed
113
+ exporterApiBaseUrl: 'https://api.multiplayer.app', // Custom API base URL (optional)
114
+ captureBody: true, // Capture body in traces
115
+ captureHeaders: true, // Capture headers in traces
116
+ // Configure masking for sensitive data in session recordings
117
+ masking: {
118
+ maskAllInputs: true, // Masks all input fields by default
119
+ maskInputOptions: {
120
+ password: true, // Always mask password fields
121
+ email: false, // Don't mask email fields by default
122
+ tel: false, // Don't mask telephone fields by default
123
+ number: false, // Don't mask number fields by default
124
+ url: false, // Don't mask URL fields by default
125
+ search: false, // Don't mask search fields by default
126
+ textarea: false // Don't mask textarea elements by default
127
+ },
128
+ // Class-based masking
129
+ maskTextClass: /sensitive|private/, // Mask text in elements with these classes
130
+ // CSS selector for text masking
131
+ maskTextSelector: '.sensitive-data', // Mask text in elements matching this selector
132
+ // Custom masking functions
133
+ maskInput: (text, element) => {
134
+ if (element.classList.contains('credit-card')) {
135
+ return '****-****-****-' + text.slice(-4)
136
+ }
137
+ return '***MASKED***'
138
+ },
139
+ maskText: (text, element) => {
140
+ if (element.dataset.type === 'email') {
141
+ const [local, domain] = text.split('@')
142
+ return local.charAt(0) + '***@' + domain
143
+ }
144
+ return '***MASKED***'
145
+ },
146
+ maskConsoleEvent: (payload) => {
147
+ // Custom console event masking
148
+ if (payload && payload.payload && payload.payload.args) {
149
+ // Mask sensitive console arguments
150
+ payload.payload.args = payload.payload.args.map((arg) =>
151
+ typeof arg === 'string' && arg.includes('password') ? '***MASKED***' : arg
152
+ )
153
+ }
154
+ return payload
155
+ },
156
+ isMaskingEnabled: true, // Enable masking for debug span payload in traces
157
+ maskBody: (payload, span) => {
158
+ // Custom trace payload masking
159
+ if (payload && typeof payload === 'object') {
160
+ const maskedPayload = { ...payload }
161
+ // Mask sensitive trace data
162
+ if (maskedPayload.requestHeaders) {
163
+ maskedPayload.requestHeaders = '***MASKED***'
164
+ }
165
+ if (maskedPayload.responseBody) {
166
+ maskedPayload.responseBody = '***MASKED***'
167
+ }
168
+ return maskedPayload
169
+ }
170
+ return payload
171
+ },
172
+ maskHeaders: (headers, span) => {
173
+ // Custom headers masking
174
+ if (headers && typeof headers === 'object') {
175
+ const maskedHeaders = { ...headers }
176
+ // Mask sensitive headers
177
+ if (maskedHeaders.authorization) {
178
+ maskedHeaders.authorization = '***MASKED***'
179
+ }
180
+ if (maskedHeaders.cookie) {
181
+ maskedHeaders.cookie = '***MASKED***'
182
+ }
183
+ return maskedHeaders
184
+ }
185
+ return headers
186
+ },
187
+ // List of body fields to mask in traces
188
+ maskBodyFieldsList: ['password', 'token', 'secret'],
189
+ // List of headers to mask in traces
190
+ maskHeadersList: ['authorization', 'cookie', 'x-api-key'],
191
+ // List of headers to include in traces (if specified, only these headers will be captured)
192
+ headersToInclude: ['content-type', 'user-agent'],
193
+ // List of headers to exclude from traces
194
+ headersToExclude: ['authorization', 'cookie']
195
+ }
196
+ })
197
+
198
+ SessionRecorder.setSessionAttributes({
199
+ userId: '12345',
200
+ userName: 'John Doe'
201
+ })
202
+ ```
203
+
204
+ ## API Methods
205
+
206
+ The Session Recorder provides several methods for controlling session recording:
207
+
208
+ ### Session Control
209
+
210
+ - `SessionRecorder.start(type?, session?)` - Start a new session with optional existing session
211
+ - `type`: Optional `SessionType.PLAIN` or `SessionType.CONTINUOUS`, default: `SessionType.PLAIN`
212
+ - `session`: Optional existing session object
213
+ - `SessionRecorder.stop(comment?)` - Stop the current session with optional comment
214
+ - `SessionRecorder.pause()` - Pause the current session
215
+ - `SessionRecorder.resume()` - Resume the current session
216
+ - `SessionRecorder.cancel()` - Cancel the current session
217
+ - `SessionRecorder.save()` - Save the continuous debugging session
218
+
219
+ ### Configuration
220
+
221
+ - `SessionRecorder.setSessionAttributes(attributes)` - Set session metadata
222
+ - `SessionRecorder.recordingButtonClickHandler = handler` - Set custom click handler
223
+
224
+ ### Properties
225
+
226
+ - `SessionRecorder.sessionId` - Get current session ID (readonly)
227
+ - `SessionRecorder.sessionType` - Get current session type (readonly)
228
+ - `SessionRecorder.sessionState` - Get current session state (readonly)
229
+ - `SessionRecorder.session` - Get current session object (readonly)
230
+ - `SessionRecorder.sessionAttributes` - Get current session attributes (readonly)
231
+ - `SessionRecorder.error` - Get/set error message
232
+ - `SessionRecorder.sessionWidgetButtonElement` - Get the widget button element (readonly)
233
+
234
+ ### Session Types
235
+
236
+ - `SessionType.PLAIN` - Standard session recording
237
+ - `SessionType.CONTINUOUS` - Continuous debugging session
238
+
239
+ ### Session States
240
+
241
+ - `SessionState.started` - Session is currently recording
242
+ - `SessionState.paused` - Session is paused
243
+ - `SessionState.stopped` - Session is stopped
244
+
245
+ ### Session Attributes
246
+
247
+ You can set various session attributes for better tracking:
248
+
249
+ ```javascript
250
+ SessionRecorder.setSessionAttributes({
251
+ userId: '12345',
252
+ userName: 'John Doe',
253
+ userEmail: 'john@example.com',
254
+ accountId: 'acc_123',
255
+ accountName: 'Enterprise Account'
256
+ })
257
+ ```
258
+
259
+ ## Masking Configuration
260
+
261
+ The Session Recorder includes comprehensive masking options to protect sensitive data during session recordings. You can configure masking behavior through the `masking` option:
262
+
263
+ ### Basic Masking Options
264
+
265
+ - `maskAllInputs`: If `true`, masks all input fields in the recording (default: `true`)
266
+ - `isMaskingEnabled`: If `true`, enables masking for debug span payload in traces (default: `true`)
267
+
268
+ ### Input Type Masking
269
+
270
+ You can control masking for specific input types:
271
+
272
+ ```javascript
273
+ maskInputOptions: {
274
+ password: true, // Always mask password fields (default: true)
275
+ email: false, // Don't mask email fields by default
276
+ tel: false, // Don't mask telephone fields by default
277
+ number: false, // Don't mask number fields by default
278
+ url: false, // Don't mask URL fields by default
279
+ search: false, // Don't mask search fields by default
280
+ textarea: false, // Don't mask textarea elements by default
281
+ select: false, // Don't mask select elements by default
282
+ // ...other types
283
+ }
284
+ ```
285
+
286
+ ### CSS Selector Masking
287
+
288
+ You can mask specific elements using CSS selectors:
289
+
290
+ ```javascript
291
+ masking: {
292
+ // Mask text in elements matching this selector
293
+ maskTextSelector: '.sensitive-data, [data-private="true"], .user-profile .email',
294
+ }
295
+ ```
296
+
297
+ ### Class-Based Masking
298
+
299
+ You can mask text based on CSS classes using string or RegExp patterns:
300
+
301
+ ```javascript
302
+ masking: {
303
+ maskTextClass: 'sensitive', // Mask text in elements with class 'sensitive'
304
+ }
305
+ ```
306
+
307
+ Or with RegExp pattern:
308
+
309
+ ```javascript
310
+ masking: {
311
+ maskTextClass: /private|confidential/, // Mask text in elements with classes 'private' or 'confidential'
312
+ }
313
+ ```
314
+
315
+ ### Custom Masking Functions
316
+
317
+ For advanced masking scenarios, you can provide custom functions:
318
+
319
+ ```javascript
320
+ masking: {
321
+ // Custom function for input masking
322
+ maskInput: (text, element) => {
323
+ // Custom logic to mask input text
324
+ if (element.classList.contains('credit-card')) {
325
+ return '****-****-****-' + text.slice(-4);
326
+ }
327
+ return '***MASKED***';
328
+ },
329
+
330
+ // Custom function for text masking
331
+ maskText: (text, element) => {
332
+ // Custom logic to mask text content
333
+ if (element.dataset.type === 'email') {
334
+ const [local, domain] = text.split('@');
335
+ return local.charAt(0) + '***@' + domain;
336
+ }
337
+ return '***MASKED***';
338
+ },
339
+
340
+ // Custom function for masking body in traces
341
+ maskBody: (payload, span) => {
342
+ // Custom logic to mask sensitive data in trace payloads
343
+ if (payload && typeof payload === 'object') {
344
+ const maskedPayload = { ...payload };
345
+ // Mask sensitive fields
346
+ if (maskedPayload.headers) {
347
+ maskedPayload.headers = '***MASKED***';
348
+ }
349
+ if (maskedPayload.body) {
350
+ maskedPayload.body = '***MASKED***';
351
+ }
352
+ return maskedPayload;
353
+ }
354
+ return payload;
355
+ },
356
+ // Custom function for masking headers in traces
357
+ maskHeaders: (headers, span) => {
358
+ // Custom logic to mask sensitive headers
359
+ if (headers && typeof headers === 'object') {
360
+ const maskedHeaders = { ...headers };
361
+ // Mask sensitive headers
362
+ if (maskedHeaders.authorization) {
363
+ maskedHeaders.authorization = '***MASKED***';
364
+ }
365
+ if (maskedHeaders.cookie) {
366
+ maskedHeaders.cookie = '***MASKED***';
367
+ }
368
+ return maskedHeaders;
369
+ }
370
+ return headers;
371
+ },
372
+ }
373
+ ```
374
+
375
+ ### Example: Comprehensive Masking Setup
376
+
377
+ ```javascript
378
+ SessionRecorder.init({
379
+ // ... other options
380
+ masking: {
381
+ maskAllInputs: true,
382
+ maskInputOptions: {
383
+ password: true,
384
+ email: true, // Mask email fields for privacy
385
+ tel: true, // Mask telephone fields for privacy
386
+ number: false, // Allow number fields
387
+ url: false, // Allow URL fields
388
+ search: false, // Allow search fields
389
+ textarea: false // Allow textarea elements
390
+ // ...other types
391
+ },
392
+ maskTextClass: /sensitive|private|confidential/, // Mask text in elements with these classes
393
+ maskTextSelector: '.user-email, .user-phone, .credit-card, [data-sensitive="true"]', // Mask text in elements matching this selector
394
+ maskInput: (text, element) => {
395
+ // Custom credit card masking
396
+ if (element.classList.contains('credit-card')) {
397
+ return '****-****-****-' + text.slice(-4)
398
+ }
399
+ return '***MASKED***'
400
+ },
401
+ maskText: (text, element) => {
402
+ // Custom email masking
403
+ if (element.dataset.type === 'email') {
404
+ const [local, domain] = text.split('@')
405
+ return local.charAt(0) + '***@' + domain
406
+ }
407
+ return '***MASKED***'
408
+ },
409
+ maskConsoleEvent: (payload) => {
410
+ // Custom console event masking
411
+ if (payload && payload.payload && payload.payload.args) {
412
+ payload.payload.args = payload.payload.args.map((arg) =>
413
+ typeof arg === 'string' && arg.includes('password') ? '***MASKED***' : arg
414
+ )
415
+ }
416
+ return payload
417
+ },
418
+ isMaskingEnabled: true, // Enable masking for debug span payload in traces
419
+ maskBody: (payload, span) => {
420
+ // Custom trace payload masking
421
+ if (payload && typeof payload === 'object') {
422
+ const maskedPayload = { ...payload }
423
+ // Mask sensitive trace data
424
+ if (maskedPayload.requestHeaders) {
425
+ maskedPayload.requestHeaders = '***MASKED***'
426
+ }
427
+ if (maskedPayload.responseBody) {
428
+ maskedPayload.responseBody = '***MASKED***'
429
+ }
430
+ return maskedPayload
431
+ }
432
+ return payload
433
+ },
434
+ maskHeaders: (headers, span) => {
435
+ // Custom headers masking
436
+ if (headers && typeof headers === 'object') {
437
+ const maskedHeaders = { ...headers }
438
+ // Mask sensitive headers
439
+ if (maskedHeaders.authorization) {
440
+ maskedHeaders.authorization = '***MASKED***'
441
+ }
442
+ if (maskedHeaders.cookie) {
443
+ maskedHeaders.cookie = '***MASKED***'
444
+ }
445
+ return maskedHeaders
446
+ },
447
+ // List of body fields to mask in traces
448
+ maskBodyFieldsList: ['password', 'token', 'secret'],
449
+ // List of headers to mask in traces
450
+ maskHeadersList: ['authorization', 'cookie', 'x-api-key'],
451
+ // List of headers to include in traces (if specified, only these headers will be captured)
452
+ headersToInclude: ['content-type', 'user-agent'],
453
+ // List of headers to exclude from traces
454
+ headersToExclude: ['authorization', 'cookie']
455
+ }
456
+ })
457
+ ```
458
+
459
+ ## Session Recorder for Next.js
460
+
461
+ To integrate the MySessionRecorder component into your Next.js application, follow these steps:
462
+
463
+ - Create a new file (e.g., MySessionRecorder.js or MySessionRecorder.tsx) in your root directory or a components directory.
464
+
465
+ - Import the component
466
+
467
+ In the newly created file, add the following code:
468
+
469
+ ```javascript
470
+ 'use client' // Mark as Client Component
471
+ import { useEffect } from 'react'
472
+ import SessionRecorder from '@multiplayer-app/session-recorder-browser'
473
+
474
+ export default function MySessionRecorder() {
475
+ useEffect(() => {
476
+ if (typeof window !== 'undefined') {
477
+ SessionRecorder.init({
478
+ version: '{YOUR_APPLICATION_VERSION}',
479
+ application: '{YOUR_APPLICATION_NAME}',
480
+ environment: '{YOUR_APPLICATION_ENVIRONMENT}',
481
+ apiKey: '{YOUR_API_KEY}',
482
+ recordCanvas: true, // Enable canvas recording
483
+ masking: {
484
+ maskAllInputs: true,
485
+ maskInputOptions: {
486
+ password: true,
487
+ email: false,
488
+ tel: false
489
+ }
490
+ }
491
+ })
492
+
493
+ SessionRecorder.setSessionAttributes({
494
+ userId: '{userId}',
495
+ userName: '{userName}'
496
+ })
497
+ }
498
+ }, [])
499
+
500
+ return null // No UI output needed
501
+ }
502
+ ```
503
+
504
+ Replace the placeholders with the actual information.
505
+
506
+ Now, you can use the MySessionRecorder component in your application by adding it to your desired page or layout file:
507
+
508
+ ```javascript
509
+ import MySessionRecorder from './MySessionRecorder' // Adjust the path as necessary
510
+
511
+ export default function MyApp() {
512
+ return (
513
+ <>
514
+ <MySessionRecorder />
515
+ {/* Other components */}
516
+ </>
517
+ )
518
+ }
519
+ ```
520
+
521
+ ## Note
522
+
523
+ If frontend domain doesn't match to backend one, set backend domain to `propagateTraceHeaderCorsUrls` parameter:
524
+
525
+ ```javascript
526
+ import SessionRecorder from '@multiplayer-app/session-recorder-browser'
527
+
528
+ SessionRecorder.init({
529
+ version: '{YOUR_APPLICATION_VERSION}',
530
+ application: '{YOUR_APPLICATION_NAME}',
531
+ environment: '{YOUR_APPLICATION_ENVIRONMENT}',
532
+ apiKey: '{YOUR_API_KEY}',
533
+ propagateTraceHeaderCorsUrls: new RegExp(`https://your.backend.api.domain`, 'i')
534
+ })
535
+ ```
536
+
537
+ If frontend sends api requests to two or more different domains put them to `propagateTraceHeaderCorsUrls` as array:
538
+
539
+ ```javascript
540
+ import SessionRecorder from '@multiplayer-app/session-recorder-browser'
541
+
542
+ SessionRecorder.init({
543
+ version: '{YOUR_APPLICATION_VERSION}',
544
+ application: '{YOUR_APPLICATION_NAME}',
545
+ environment: '{YOUR_APPLICATION_ENVIRONMENT}',
546
+ apiKey: '{YOUR_API_KEY}',
547
+ propagateTraceHeaderCorsUrls: [
548
+ new RegExp(`https://your.backend.api.domain`, 'i'),
549
+ new RegExp(`https://another.backend.api.domain`, 'i')
550
+ ]
551
+ })
552
+ ```
553
+
554
+ ## Documentation
555
+
556
+ For more details on how the Multiplayer Session Recorder integrates with your backend architecture and system auto-documentation, check out our [official documentation](https://www.multiplayer.app/docs/features/system-auto-documentation/).
557
+
558
+ ## License
559
+
560
+ This library is distributed under the [MIT License](LICENSE).