@data-netmonk/mona-chat-widget 2.1.37 → 2.3.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 CHANGED
@@ -2,6 +2,83 @@
2
2
 
3
3
  Chat widget package developed by Netmonk data & solution team to be imported in Netmonk products
4
4
 
5
+ ---
6
+
7
+ ### Recent Updates & Breaking Changes
8
+
9
+ ---
10
+
11
+ **Latest Version Changes:**
12
+
13
+ ⚠️ **Breaking Changes:**
14
+ 1. **Removed `type` and `agentType` props** - These parameters are no longer used and have been removed from all components
15
+ 2. **Renamed `botServerUrl` to `webhookUrl`** - For better clarity and consistency
16
+ 3. **`webhookUrl` is now required** - Must be provided as a prop
17
+ 4. **`authUrl` and `username` are now direct props** - No longer part of `data` prop for better clarity and type safety
18
+ 5. **`userId` is now optional** - Widget automatically generates visitor ID for guest users via browser fingerprinting when `userId` is not provided
19
+
20
+ ✨ **New Features:**
21
+ 1. **Guest user support** - Users can chat without logging in
22
+ - Automatic visitor ID generation using browser fingerprinting (FingerprintJS + SHA256)
23
+ - `auth: false` flag automatically added to API requests for guest users
24
+ - Persistent sessions across page reloads for anonymous visitors
25
+ 2. **Authentication support** - Automatic token management with refresh on 401 errors
26
+ - Pass `authUrl` as a direct prop
27
+ - Widget handles token lifecycle automatically
28
+ 3. **Enhanced user authentication handling** - Smart detection of authenticated vs guest users
29
+ - Compares `userId` with visitor ID to determine authentication status
30
+ - Automatic `auth` flag management in all API requests
31
+ 4. **Enhanced data prop** - Support for custom variables passed to backend via `data` prop
32
+ 5. **Improved error handling** - Better fallback mechanisms and error messages
33
+ 6. **Direct `username` prop** - Pass username as a top-level prop instead of in data string
34
+
35
+ 📝 **Migration Guide:**
36
+ ```jsx
37
+ // Old usage (deprecated)
38
+ <ChatWidget
39
+ userId="user123"
40
+ sourceId="source456"
41
+ type="prime"
42
+ botServerUrl="https://api.example.com"
43
+ />
44
+
45
+ // Previous version (with data prop)
46
+ <ChatWidget
47
+ userId="user123"
48
+ sourceId="source456"
49
+ webhookUrl="https://api.example.com/webhook"
50
+ data="authUrl=https://api.example.com/login/chatwidget~username=John"
51
+ />
52
+
53
+ // New usage - Authenticated user (current - recommended)
54
+ <ChatWidget
55
+ userId="user123"
56
+ sourceId="source456"
57
+ webhookUrl="https://api.example.com/webhook"
58
+ authUrl="https://api.example.com/login/chatwidget"
59
+ username="John"
60
+ data="email=john@example.com~phone=+1234567890"
61
+ />
62
+
63
+ // New usage - Guest user (without login)
64
+ <ChatWidget
65
+ sourceId="source456"
66
+ webhookUrl="https://api.example.com/webhook"
67
+ username="Guest"
68
+ />
69
+ // Widget automatically generates visitor ID and adds auth: false flag
70
+
71
+ // New usage - Conditional (handles both logged-in and guest users)
72
+ <ChatWidget
73
+ userId={currentUser?.id} // undefined for guests
74
+ sourceId="source456"
75
+ webhookUrl="https://api.example.com/webhook"
76
+ username={currentUser?.name || "Guest"}
77
+ />
78
+ ```
79
+
80
+ ---
81
+
5
82
  ## 🚅 Quick start
6
83
 
7
84
  ### Prerequisites
@@ -10,7 +87,7 @@ Chat widget package developed by Netmonk data & solution team to be imported in
10
87
 
11
88
  1. Install dependencies
12
89
  ```
13
- npm install
90
+ npm install --legacy-peer-deps
14
91
  ```
15
92
  2. Copy .env.example
16
93
  ```
@@ -79,7 +156,7 @@ For responses with buttons:
79
156
 
80
157
  ---
81
158
 
82
- 1. **How to run Storybook locally** (access at http://localhost:6006)
159
+ 1. **How to run Storybook locally** (access at http://localhost:5177)
83
160
 
84
161
  ```
85
162
  npm run storybook
@@ -165,10 +242,9 @@ For responses with buttons:
165
242
  function App() {
166
243
  return (
167
244
  <ChatWidget
168
- type="prime"
169
245
  userId="user123"
170
246
  sourceId="691e1b5952068ff7aaeccffc9"
171
- botServerUrl="https://your-backend-url.com"
247
+ webhookUrl="https://your-backend-url.com"
172
248
  />
173
249
  );
174
250
  }
@@ -184,22 +260,17 @@ For responses with buttons:
184
260
 
185
261
  | Prop | Type | Description |
186
262
  |------|------|-------------|
187
- | `userId` | `string` | **Required.** Unique identifier for the user |
188
263
  | `sourceId` | `string` | **Required.** Source/channel identifier for the chat |
189
-
190
- #### Dynamic Data Prop (NEW!)
191
- | Prop | Type | Description |
192
- |------|------|-------------|
193
- | `data` | `string` | URL-encoded config string (see advanced usage below) |
194
-
264
+ | `webhookUrl` | `string` | **Required.** Backend webhook URL |
195
265
 
196
266
  #### Optional Props
197
267
 
198
268
  | Prop | Type | Default | Description |
199
269
  |------|------|---------|-------------|
200
- | `type` | `"prime" \| "hi"` | `"hi"` | Agent type for multi-agent system |
201
- | `botServerUrl` | `string` | - | Backend API URL (falls back to env vars if not provided) |
202
- | `data` | `string` | - | URL-encoded config string (see advanced usage below) |
270
+ | `userId` | `string` | Generated visitor ID | Unique identifier for the user. **Optional** - if not provided, a unique visitor ID is automatically generated using browser fingerprinting for guest users |
271
+ | `authUrl` | `string` | - | Authentication endpoint URL for token-based authentication |
272
+ | `username` | `string` | - | Username for the session (sent to backend in variables) |
273
+ | `data` | `string` | - | Additional custom variables in format `key1=value1~key2=value2` |
203
274
  | `width` | `string` | `"25vw"` | Widget width (CSS value) |
204
275
  | `height` | `string` | `"90vh"` | Widget height (CSS value) |
205
276
  | `right` | `string` | `"1.25rem"` | Distance from right edge |
@@ -210,11 +281,45 @@ For responses with buttons:
210
281
 
211
282
  ---
212
283
 
284
+ ### Guest User Support
285
+
286
+ ---
287
+
288
+ The widget now supports **guest users** (users who haven't logged in or before logging in). When `userId` is not provided, the widget automatically generates a unique visitor ID using browser fingerprinting.
289
+
290
+ **How it works:**
291
+
292
+ 1. **Browser Fingerprinting**: Uses FingerprintJS to generate a unique identifier based on:
293
+ - Browser characteristics (user agent, screen resolution, timezone, etc.)
294
+ - Incognito/private browsing detection
295
+ - Combined into a SHA256 hash for consistency
296
+
297
+ 2. **Automatic Guest Detection**: The widget automatically detects guest users and:
298
+ - Generates a visitor ID if `userId` is not provided
299
+ - Adds `auth: false` flag to all API requests for guest users
300
+ - Uses the visitor ID as the effective user ID throughout the session
301
+
302
+ 3. **Persistent Sessions**: The visitor ID remains consistent across page reloads (unless browser fingerprint changes or user clears data)
303
+
304
+ **When to use guest mode:**
305
+ - Public-facing websites where users can chat without logging in
306
+ - Support widgets for anonymous visitors
307
+ - Pre-login customer service interactions
308
+ - Any scenario where user authentication is optional
309
+
310
+ **When to provide userId:**
311
+ - Users who are logged into your application
312
+ - When you need to track chat history across devices
313
+ - When authentication is required for personalized responses
314
+ - Enterprise or internal applications
315
+
316
+ ---
317
+
213
318
  ### Usage Examples
214
319
 
215
320
  ---
216
321
 
217
- #### Basic Usage
322
+ #### Basic Usage (Authenticated User)
218
323
 
219
324
  ```jsx
220
325
  import { ChatWidget } from "@data-netmonk/mona-chat-widget";
@@ -225,33 +330,167 @@ function App() {
225
330
  <ChatWidget
226
331
  userId="user123"
227
332
  sourceId="691e1b5952068ff7aaeccffc9"
333
+ webhookUrl="https://api.example.com/webhook"
334
+ />
335
+ );
336
+ }
337
+ ```
338
+
339
+ #### Guest User (Without Login)
340
+
341
+ For anonymous visitors or users who haven't logged in:
342
+
343
+ ```jsx
344
+ import { ChatWidget } from "@data-netmonk/mona-chat-widget";
345
+ import "@data-netmonk/mona-chat-widget/dist/style.css";
346
+
347
+ function App() {
348
+ return (
349
+ <ChatWidget
350
+ sourceId="691e1b5952068ff7aaeccffc9"
351
+ webhookUrl="https://api.example.com/webhook"
228
352
  />
229
353
  );
230
354
  }
231
355
  ```
232
356
 
233
- #### With Backend URL
357
+ **What happens:**
358
+ - Widget automatically generates a visitor ID using browser fingerprinting
359
+ - All API requests include `auth: false` in variables to indicate guest user
360
+ - No login required - users can start chatting immediately
361
+
362
+ #### Conditional userId (Logged in or Guest)
363
+
364
+ Handle both logged-in users and guests dynamically:
365
+
366
+ ```jsx
367
+ import { ChatWidget } from "@data-netmonk/mona-chat-widget";
368
+ import "@data-netmonk/mona-chat-widget/dist/style.css";
369
+
370
+ function App() {
371
+ const currentUser = getCurrentUser(); // Your auth function
372
+
373
+ return (
374
+ <ChatWidget
375
+ userId={currentUser?.id} // Provide userId if logged in, undefined if not
376
+ sourceId="691e1b5952068ff7aaeccffc9"
377
+ webhookUrl="https://api.example.com/webhook"
378
+ username={currentUser?.name}
379
+ />
380
+ );
381
+ }
382
+ ```
383
+
384
+ **Behavior:**
385
+ - If `currentUser.id` exists → Uses provided userId (authenticated user)
386
+ - If `currentUser.id` is `null`/`undefined` → Generates visitor ID (guest user)
387
+ - Backend receives `auth: false` flag only for guest users
388
+
389
+ #### With Custom Variables
390
+
391
+ Pass custom user data like email, phone number, etc. to the backend:
234
392
 
235
393
  ```jsx
236
394
  <ChatWidget
237
- userId="user123"
395
+ userId="user123"
238
396
  sourceId="691e1b5952068ff7aaeccffc9"
239
- botServerUrl="https://api.example.com"
240
- type="prime"
397
+ webhookUrl="https://api.example.com/webhook"
398
+ username="John Doe"
399
+ data="telephone_number=+628123456789~email=john@example.com"
241
400
  />
242
401
  ```
243
402
 
244
- #### With Custom Variables (NEW!)
403
+ **Variables sent to backend:**
404
+ ```json
405
+ {
406
+ "chat_id": "...",
407
+ "session_id": "...",
408
+ "user_id": "user123",
409
+ "message": "Hello",
410
+ "type": "text",
411
+ "variables": {
412
+ "username": "John Doe",
413
+ "telephone_number": "+628123456789",
414
+ "email": "john@example.com"
415
+ }
416
+ }
417
+ ```
418
+ }
419
+ ```
420
+ #### With Authentication (NEW!)
245
421
 
246
- Pass custom user data like username, phone number, etc. to the backend:
422
+ The widget supports automatic authentication with token refresh on expiry:
247
423
 
248
424
  ```jsx
249
425
  <ChatWidget
250
- data="url:https://api.example.com~user_id=user123~source_id=691e1b5952068ff7aaeccffc9~username=John Doe~telephone_number=+628123456789~email=john@example.com"
426
+ userId="user123"
427
+ sourceId="691e1b5952068ff7aaeccffc9"
428
+ webhookUrl="https://api.example.com/webhook"
429
+ authUrl="https://api.example.com/login/chatwidget"
430
+ username="John Doe"
251
431
  />
252
432
  ```
253
433
 
254
- **Variables sent to backend:**
434
+ **How authentication works:**
435
+
436
+ 1. **Initial Authentication**: When the widget loads (on Launcher mount), if `authUrl` is provided as a prop, it automatically calls the auth API:
437
+ ```
438
+ POST {authUrl}
439
+ Body: { "user_id": "user123" }
440
+ Response: { "token": "eyJ..." }
441
+ ```
442
+
443
+ 2. **Session Initialization**: After getting the token, the widget calls the init endpoint to establish the session:
444
+ ```
445
+ POST {webhookUrl}/{sourceId}/init
446
+ Body: {
447
+ "session_id": "...",
448
+ "user_id": "user123",
449
+ "token": "eyJ...",
450
+ "username": "John Doe"
451
+ }
452
+ ```
453
+
454
+ 3. **Automatic Token Refresh**: If the webhook returns **401 Unauthorized** (token expired/revoked), the widget automatically:
455
+ - Calls the `authUrl` again to get a fresh token
456
+ - Re-initializes the session with the new token
457
+ - Updates the `authToken` in variables
458
+ - Retries the failed request with the new token
459
+ - This happens transparently without user interaction
460
+
461
+ **Combined example with auth and custom variables:**
462
+ ```jsx
463
+ <ChatWidget
464
+ userId="user123"
465
+ sourceId="691e1b5952068ff7aaeccffc9"
466
+ webhookUrl="https://api.example.com/webhook"
467
+ authUrl="https://api.example.com/login/chatwidget"
468
+ username="John"
469
+ data="email=john@example.com~phone=+628123456789"
470
+ />
471
+ ```
472
+
473
+ **Auth Flag (`auth` variable):**
474
+ The widget automatically adds an `auth: false` flag to the `variables` object when the user is a guest (not authenticated):
475
+ - When `userId === visitorId` (browser fingerprint), the widget adds `auth: false` to variables
476
+ - When `userId !== visitorId` (authenticated user), no `auth` flag is added to variables
477
+
478
+ **Guest user example** (userId equals browser fingerprint):
479
+ ```json
480
+ {
481
+ "chat_id": "...",
482
+ "session_id": "...",
483
+ "user_id": "visitor_abc123",
484
+ "message": "Hello",
485
+ "type": "text",
486
+ "variables": {
487
+ "username": "Guest",
488
+ "auth": false
489
+ }
490
+ }
491
+ ```
492
+
493
+ **Authenticated user example** (userId is different from browser fingerprint):
255
494
  ```json
256
495
  {
257
496
  "chat_id": "...",
@@ -261,26 +500,25 @@ Pass custom user data like username, phone number, etc. to the backend:
261
500
  "type": "text",
262
501
  "variables": {
263
502
  "username": "John Doe",
264
- "telephone_number": "+628123456789",
265
503
  "email": "john@example.com"
266
504
  }
267
505
  }
268
506
  ```
269
507
 
270
- **Reserved keys** (won't go into `variables`):
271
- - `url` - Backend URL
272
- - `user_id` - User identifier
273
- - `source_id` - Source identifier
274
- - `type` - Agent type
508
+ This `auth: false` flag is automatically added in:
509
+ - Session initialization payload (when guest)
510
+ - All message requests (when guest)
511
+ - Button postback requests (when guest)
275
512
 
276
- **Any other key** you add will be included in the `variables` object automatically!
513
+ **Note:** The `data` prop is for additional custom variables only. Required parameters (`userId`, `sourceId`, `webhookUrl`) and common optional parameters (`authUrl`, `username`) should be passed as direct props for better type safety and clarity.
277
514
 
278
515
  #### Custom Styling
279
516
 
280
517
  ```jsx
281
518
  <ChatWidget
282
- userId="user123"
519
+ userId="user123" // Optional
283
520
  sourceId="691e1b5952068ff7aaeccffc9"
521
+ webhookUrl="https://api.example.com/webhook"
284
522
  width="400px"
285
523
  height="600px"
286
524
  right="20px"
@@ -295,8 +533,9 @@ Pass custom user data like username, phone number, etc. to the backend:
295
533
  <div style={{ display: 'grid', gridTemplateColumns: '1fr 400px' }}>
296
534
  <div>Main content</div>
297
535
  <ChatWidget
298
- userId="user123"
536
+ userId="user123" // Optional
299
537
  sourceId="691e1b5952068ff7aaeccffc9"
538
+ webhookUrl="https://api.example.com/webhook"
300
539
  position="relative"
301
540
  width="100%"
302
541
  height="100vh"
@@ -315,8 +554,9 @@ function App() {
315
554
 
316
555
  return (
317
556
  <ChatWidget
318
- userId="user123"
557
+ userId="user123" // Optional
319
558
  sourceId="691e1b5952068ff7aaeccffc9"
559
+ webhookUrl="https://api.example.com/webhook"
320
560
  onToggle={handleToggle}
321
561
  />
322
562
  );
@@ -327,8 +567,9 @@ function App() {
327
567
 
328
568
  ```jsx
329
569
  <ChatWidget
330
- userId="user123"
570
+ userId="user123" // Optional - supports guest users
331
571
  sourceId="691e1b5952068ff7aaeccffc9"
572
+ webhookUrl="https://api.example.com/webhook"
332
573
  width="100vw"
333
574
  height="100vh"
334
575
  right="0"
@@ -342,92 +583,153 @@ function App() {
342
583
 
343
584
  ---
344
585
 
345
- The `data` prop allows you to pass configuration via a single string. This is especially useful when you need to dynamically build the configuration or pass it through URL parameters.
586
+ The `data` prop allows you to pass additional custom variables via a single string. This is especially useful when you need to dynamically pass user-specific data or pass it through URL parameters.
346
587
 
347
- **Format:** `key:value` pairs separated by `~`
588
+ **Format:** `key=value` pairs separated by `~`
348
589
 
349
590
  **Example data string:**
350
591
  ```
351
- url:https://api.example.com~user_id=user123~source_id=abc~username=John~phone=+1234567890
592
+ email=john@example.com~phone=+1234567890~department=Engineering
352
593
  ```
353
594
 
595
+ **Note:** `authUrl` and `username` are now **direct props** and should not be included in the `data` string.
596
+
354
597
  #### Building Data String Programmatically
355
598
 
356
- Instead of manually constructing the data string, you can create a helper function to build it dynamically:
599
+ Instead of manually constructing the data string, you can create a helper function to build it dynamically. This approach is recommended for production applications as it:
600
+ - Prevents syntax errors in the data string format
601
+ - Makes the code more maintainable and readable
602
+ - Allows for conditional inclusion of parameters
603
+ - Handles URL encoding automatically if needed
604
+
605
+ **Create a helper function** (`src/helpers/chatWidget.js` or similar):
606
+
607
+ ```jsx
608
+ /**
609
+ * Builds the data string for ChatWidget component
610
+ * @param {Object} params - Object containing all parameters
611
+ * @param {string} params.email - Optional: User's email address
612
+ * @param {string} params.phone - Optional: User's phone number
613
+ * @param {Object} params.customFields - Optional: Any additional custom fields as key-value pairs
614
+ * @returns {string} Formatted data string for ChatWidget (always returns a string)
615
+ *
616
+ * @example
617
+ * // Returns: "email=john@example.com~phone=+1234567890~department=Engineering"
618
+ * buildChatWidgetData({
619
+ * email: "john@example.com",
620
+ * phone: "+1234567890",
621
+ * customFields: { department: "Engineering" }
622
+ * });
623
+ */
624
+ export const buildChatWidgetData = ({
625
+ email,
626
+ phone,
627
+ customFields = {}
628
+ }) => {
629
+ const parts = [];
630
+
631
+ // Add standard fields
632
+ if (email) {
633
+ parts.push(`email=${encodeURIComponent(email)}`);
634
+ }
635
+
636
+ if (phone) {
637
+ parts.push(`phone=${encodeURIComponent(phone)}`);
638
+ }
639
+
640
+ // Add any custom fields dynamically
641
+ // Note: customFields is just a convenience parameter for the helper function
642
+ // Each field will be flattened into the string format: key=value~key2=value2
643
+ Object.entries(customFields).forEach(([key, value]) => {
644
+ if (value) {
645
+ parts.push(`${key}=${encodeURIComponent(String(value))}`);
646
+ }
647
+ });
648
+
649
+ // Returns a string like: "email=john@example.com~phone=+1234567890~department=Engineering"
650
+ return parts.join("~");
651
+ };
652
+ ```
653
+
654
+ **Important:** The `customFields` parameter is **NOT** passed as an object to the widget. It's just a convenient way to pass multiple additional fields to the helper function. The function flattens everything into a single string format.
655
+
656
+ **Usage in your application:**
357
657
 
358
- **Usage:**
359
658
  ```jsx
360
659
  import { ChatWidget } from "@data-netmonk/mona-chat-widget";
660
+ import "@data-netmonk/mona-chat-widget/dist/style.css";
361
661
  import { buildChatWidgetData } from "./helpers/chatWidget";
362
662
 
363
663
  function App() {
364
- const chatData = buildChatWidgetData({
365
- userId: "user123",
366
- sourceId: "691e1b5952068ff7aaeccffc9",
367
- botServerUrl: "https://api.example.com",
368
- username: "John Doe",
664
+ // Get user data from your auth system, state, or props
665
+ const user = {
666
+ id: "user123",
667
+ name: "John Doe",
369
668
  email: "john@example.com",
370
669
  phone: "+628123456789"
670
+ };
671
+
672
+ // Build the data string with custom variables only
673
+ const customData = buildChatWidgetData({
674
+ email: user.email,
675
+ phone: user.phone,
676
+ customFields: {
677
+ department: "Engineering",
678
+ role: "Developer",
679
+ company: "Acme Corp"
680
+ }
371
681
  });
682
+
683
+ // customData is now a STRING like:
684
+ // "email=john@example.com~phone=%2B628123456789~department=Engineering~role=Developer~company=Acme%20Corp"
372
685
 
373
- return <ChatWidget data={chatData} />;
686
+ return (
687
+ <ChatWidget
688
+ userId={user.id}
689
+ sourceId="691e1b5952068ff7aaeccffc9"
690
+ webhookUrl="https://api.example.com/webhook"
691
+ authUrl="https://api.example.com/login/chatwidget" // Direct prop
692
+ username={user.name} // Direct prop
693
+ data={customData} // Only additional variables
694
+ />
695
+ );
374
696
  }
375
697
  ```
376
698
 
377
- The helper function should:
378
- - Accept configuration parameters (userId, sourceId, botServerUrl, and any custom variables)
379
- - Build the data string in format: `key=value` pairs separated by `~`
380
- - Use `url:` prefix (not `url=`) for the backend URL
381
- - Return the formatted string
382
-
383
- #### Using with URL Parameters (Optional)
384
-
385
- If you need to pass the data through URL parameters:
386
-
387
- ```jsx
388
- // Parse from URL
389
- const urlParams = new URLSearchParams(window.location.search);
390
- const dataParam = urlParams.get('data');
391
-
392
- <ChatWidget data={dataParam} />
393
- ```
394
-
395
- **URL example:**
396
- ```
397
- https://yourapp.com/chat?data=url:https://api.example.com~user_id=user123~source_id=abc~username=John~phone=%2B628123456789
398
- ```
399
-
400
- #### Real-World Example from ui-mona-web
401
-
402
- See the complete helper implementation in `ui-mona-web/src/helpers/chatWidget.js`:
699
+ **With conditional authentication:**
403
700
 
404
701
  ```jsx
405
- import { getUserId } from './cookie';
406
-
407
- export const buildChatWidgetData = ({ loginType, sourceId, userId, botServerUrl }) => {
408
- // Get userId from cookies if not provided
409
- const finalUserId = userId || getUserId();
410
-
411
- // Get sourceId based on loginType
412
- const finalSourceId = sourceId || getSourceIdByLoginType(loginType);
413
-
414
- // Get bot server URL from env
415
- const finalBotServerUrl = import.meta.env.VITE_CHAT_WIDGET_WEBHOOK_URL || botServerUrl;
416
-
417
- const parts = [
418
- `user_id=${String(finalUserId)}`,
419
- `source_id=${finalSourceId}`,
420
- ];
421
-
422
- if (finalBotServerUrl) {
423
- parts.unshift(`url:${finalBotServerUrl}`);
424
- }
702
+ function App() {
703
+ const authUrl = import.meta.env.VITE_CHAT_AUTH_ENABLED === "true"
704
+ ? import.meta.env.VITE_CHAT_AUTH_URL
705
+ : null;
425
706
 
426
- return parts.join("~");
427
- };
707
+ const customData = buildChatWidgetData({
708
+ email: getCurrentUser().email,
709
+ customFields: {
710
+ department: "Sales"
711
+ }
712
+ });
713
+
714
+ return (
715
+ <ChatWidget
716
+ userId={getCurrentUser().id}
717
+ sourceId="691e1b5952068ff7aaeccffc9"
718
+ webhookUrl={import.meta.env.VITE_WEBHOOK_URL}
719
+ authUrl={authUrl} // Direct prop (conditionally set)
720
+ username={getCurrentUser().name} // Direct prop
721
+ data={customData} // Only additional variables
722
+ />
723
+ );
724
+ }
428
725
  ```
429
726
 
430
- ---
727
+ **The helper function handles:**
728
+ - ✅ Proper formatting with `~` separators
729
+ - ✅ URL encoding for special characters
730
+ - ✅ Conditional parameter inclusion (only adds if value exists)
731
+ - ✅ Support for dynamic custom fields
732
+ - ✅ Type safety and documentation via JSDoc comments
431
733
 
432
734
  ### Standalone app (for demonstration)
433
735