@encatch/web-sdk 0.0.35 → 1.0.0-beta.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 +140 -638
- package/dist/encatch.es.js +2 -0
- package/dist/encatch.es.js.map +1 -0
- package/dist/encatch.iife.js +2 -0
- package/dist/encatch.iife.js.map +1 -0
- package/dist/index.d.ts +191 -0
- package/package.json +32 -50
- package/dist-sdk/plugin/sdk/core-wrapper-BMvOyc0u.js +0 -22926
- package/dist-sdk/plugin/sdk/module-DC2Edddk.js +0 -481
- package/dist-sdk/plugin/sdk/module.js +0 -5
- package/dist-sdk/plugin/sdk/preview-sdk.html +0 -1182
- package/dist-sdk/plugin/sdk/vite.svg +0 -15
- package/dist-sdk/plugin/sdk/web-form-engine-core.css +0 -1
- package/index.d.ts +0 -207
- package/src/@types/encatch-type.ts +0 -111
- package/src/encatch-instance.ts +0 -161
- package/src/feedback-api-types.ts +0 -18
- package/src/hooks/useDevice.ts +0 -30
- package/src/hooks/useFeedbackInterval.ts +0 -71
- package/src/hooks/useFeedbackTriggers.ts +0 -342
- package/src/hooks/useFetchElligibleFeedbackConfiguration.ts +0 -363
- package/src/hooks/useFetchFeedbackConfigurationDetails.ts +0 -92
- package/src/hooks/usePageChangeTracker.ts +0 -88
- package/src/hooks/usePrepopulatedAnswers.ts +0 -123
- package/src/hooks/useRefineTextForm.ts +0 -55
- package/src/hooks/useSubmitFeedbackForm.ts +0 -134
- package/src/hooks/useUserSession.ts +0 -53
- package/src/module.tsx +0 -428
- package/src/store/formResponses.ts +0 -211
- package/src/utils/browser-details.ts +0 -36
- package/src/utils/duration-utils.ts +0 -158
- package/src/utils/feedback-frequency-storage.ts +0 -214
- package/src/utils/feedback-storage.ts +0 -166
package/README.md
CHANGED
|
@@ -1,756 +1,258 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @encatch/web-sdk
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A lightweight, type-safe JavaScript SDK for integrating Encatch forms and surveys into your web application.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- Time-delayed triggers
|
|
12
|
-
- **User Session Management**: Track and manage user sessions with device fingerprinting
|
|
13
|
-
- **Frequency Control**: Configure feedback display frequency and scheduling
|
|
14
|
-
- **Multi-language Support**: Display feedback in multiple languages
|
|
15
|
-
- **Theme Support**: Light and dark mode with custom CSS
|
|
16
|
-
- **Prepopulated Answers**: Pre-fill feedback forms with known data
|
|
17
|
-
- **Event Tracking**: Track user interactions and custom events
|
|
18
|
-
- **TypeScript Support**: Fully typed API for better developer experience
|
|
19
|
-
- **Lightweight**: Minimal bundle size with optimized performance
|
|
7
|
+
- **Lightweight**: Minimal stub that loads the full implementation asynchronously
|
|
8
|
+
- **Type-safe**: Full TypeScript support with comprehensive type definitions
|
|
9
|
+
- **Queue-based**: Commands are queued until the SDK is ready, ensuring no calls are lost
|
|
10
|
+
- **Framework agnostic**: Works with any JavaScript framework or vanilla JS
|
|
20
11
|
|
|
21
12
|
## Installation
|
|
22
13
|
|
|
23
|
-
###
|
|
24
|
-
|
|
25
|
-
Add the following script to your HTML file before the closing `</head>` tag:
|
|
26
|
-
|
|
27
|
-
```html
|
|
28
|
-
<script>
|
|
29
|
-
!function(){if(!window.encatch){var e={_i:[],apiKey:"",config:{host:"https://your-host.com",autoStartEnabled:!1,autoStartSessionDisabled:!0,themeMode:"light",language:"en",customCssLink:""},initialized:!1,chunkUrlLoader:function(e){return window.encatch.config.host+e},init:function(n,t){if(!("initialized"in window.encatch&&window.encatch.initialized)){if(window.encatch.apiKey=n,t?.host&&(window.encatch.config.host=t.host),t?.identity&&(window.encatch.config.identity=t.identity),void 0!==t?.autoStartSessionDisabled&&(window.encatch.config.autoStartSessionDisabled=t.autoStartSessionDisabled),void 0!==t?.processAfterIdentitySet?window.encatch.config.processAfterIdentitySet=t.processAfterIdentitySet:window.encatch.config.processAfterIdentitySet=!1,void 0!==t?.autoStartEnabled&&(window.encatch.config.autoStartEnabled=t.autoStartEnabled),t?.themeMode?window.encatch.config.themeMode=t.themeMode:window.encatch.config.themeMode="light",t?.language?window.encatch.config.language=t.language:window.encatch.config.language="en",t?.customCssLink&&(window.encatch.config.customCssLink=t.customCssLink),t?.setUser&&(window.encatch.config.setUser=t.setUser),window.encatch.initialized=!0,!import.meta.env.VITE_PATH_PREFIX||import.meta.env.VITE_PATH_PREFIX.startsWith("/")||(import.meta.env.VITE_PATH_PREFIX="/"+import.meta.env.VITE_PATH_PREFIX),import.meta.env.VITE_PATH_PREFIX=import.meta.env.VITE_PATH_PREFIX.replace(/\/+$/,""),scriptSrc=`${window.encatch.config.host}${import.meta.env.VITE_PATH_PREFIX||""}/encatch-web-sdk.js`,(script=document.createElement("script")).src=scriptSrc,script.type="module",script.async=!0,firstHeadElement=document.head.firstChild)firstHeadElement?document.head.insertBefore(script,firstHeadElement):document.head.appendChild(script);var o=document.createElement("div");o.id="enisght-root",document.body.appendChild(o)}}};window.encatch=e,["trackEvent","stop","start","setUser","setThemeMode","setLanguage","openFeedbackById","openFeedbackByName","verifyFeedbackIds","forceFetchEligibleFeedbacks","capturePageScrollEvent"].forEach((function(n){e[n]=function(){for(var t=arguments.length,o=new Array(t),i=0;i<t;i++)o[i]=arguments[i];window.encatch._i.push([n].concat(o))}}))}}();
|
|
30
|
-
</script>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Then initialize the SDK:
|
|
34
|
-
|
|
35
|
-
```html
|
|
36
|
-
<script>
|
|
37
|
-
encatch.init('YOUR_API_KEY', {
|
|
38
|
-
host: 'https://your-host.com',
|
|
39
|
-
autoStartEnabled: true
|
|
40
|
-
});
|
|
41
|
-
</script>
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
### Via NPM (For Module Bundlers)
|
|
14
|
+
### NPM / Yarn / PNPM
|
|
45
15
|
|
|
46
16
|
```bash
|
|
47
17
|
npm install @encatch/web-sdk
|
|
18
|
+
# or
|
|
19
|
+
yarn add @encatch/web-sdk
|
|
20
|
+
# or
|
|
21
|
+
pnpm add @encatch/web-sdk
|
|
48
22
|
```
|
|
49
23
|
|
|
50
|
-
|
|
51
|
-
import '@encatch/web-sdk';
|
|
24
|
+
### CDN / Script Tag
|
|
52
25
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
autoStartEnabled: true
|
|
56
|
-
});
|
|
26
|
+
```html
|
|
27
|
+
<script src="https://unpkg.com/@encatch/web-sdk/dist/encatch.iife.js"></script>
|
|
57
28
|
```
|
|
58
29
|
|
|
59
30
|
## Quick Start
|
|
60
31
|
|
|
61
|
-
###
|
|
32
|
+
### ES Modules
|
|
62
33
|
|
|
63
34
|
```javascript
|
|
64
|
-
|
|
65
|
-
encatch.init('YOUR_API_KEY', {
|
|
66
|
-
host: 'https://your-host.com',
|
|
67
|
-
autoStartEnabled: true,
|
|
68
|
-
themeMode: 'light',
|
|
69
|
-
language: 'en'
|
|
70
|
-
});
|
|
35
|
+
import { _encatch } from '@encatch/web-sdk';
|
|
71
36
|
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
$set: {
|
|
75
|
-
email: 'user@example.com',
|
|
76
|
-
name: 'John Doe',
|
|
77
|
-
plan: 'premium'
|
|
78
|
-
}
|
|
79
|
-
});
|
|
37
|
+
// Initialize with your API key
|
|
38
|
+
_encatch.init('YOUR_API_KEY');
|
|
80
39
|
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
40
|
+
// Identify the user
|
|
41
|
+
_encatch.identifyUser('user-123', {
|
|
42
|
+
email: 'user@example.com',
|
|
43
|
+
name: 'John Doe',
|
|
85
44
|
});
|
|
86
45
|
```
|
|
87
46
|
|
|
88
|
-
###
|
|
47
|
+
### Script Tag
|
|
89
48
|
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
## Configuration Options
|
|
102
|
-
|
|
103
|
-
### Initialization Options
|
|
104
|
-
|
|
105
|
-
| Option | Type | Default | Description |
|
|
106
|
-
|--------|------|---------|-------------|
|
|
107
|
-
| `host` | `string` | - | **Required**. The host URL for the Encatch API |
|
|
108
|
-
| `autoStartEnabled` | `boolean` | `false` | Automatically start fetching eligible feedbacks |
|
|
109
|
-
| `autoStartSessionDisabled` | `boolean` | `true` | Disable automatic session management |
|
|
110
|
-
| `processAfterIdentitySet` | `boolean` | `false` | Wait for user identity before processing |
|
|
111
|
-
| `themeMode` | `'light' \| 'dark'` | `'light'` | Default theme mode |
|
|
112
|
-
| `language` | `string` | `'en'` | Default language code |
|
|
113
|
-
| `customCssLink` | `string` | - | URL to custom CSS file |
|
|
114
|
-
| `setUser` | `UserInfo` | - | Initial user identity |
|
|
115
|
-
| `customProperties` | `Record<string, string>` | - | Custom properties for targeting |
|
|
116
|
-
| `onSessionDisabled` | `(action, message) => void` | - | Callback when session functions are disabled |
|
|
117
|
-
|
|
118
|
-
### Example: Complete Configuration
|
|
119
|
-
|
|
120
|
-
```javascript
|
|
121
|
-
encatch.init('YOUR_API_KEY', {
|
|
122
|
-
host: 'https://your-host.com',
|
|
123
|
-
autoStartEnabled: true,
|
|
124
|
-
autoStartSessionDisabled: false,
|
|
125
|
-
themeMode: 'light',
|
|
126
|
-
language: 'en',
|
|
127
|
-
customCssLink: 'https://your-cdn.com/custom-theme.css',
|
|
128
|
-
setUser: {
|
|
129
|
-
userId: 'user-123',
|
|
130
|
-
traits: {
|
|
131
|
-
$set: {
|
|
132
|
-
email: 'user@example.com',
|
|
133
|
-
plan: 'premium'
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
},
|
|
137
|
-
onSessionDisabled: (action, message) => {
|
|
138
|
-
console.warn(`Session action blocked: ${action} - ${message}`);
|
|
139
|
-
}
|
|
140
|
-
});
|
|
49
|
+
```html
|
|
50
|
+
<script src="https://unpkg.com/@encatch/web-sdk/dist/encatch.iife.js"></script>
|
|
51
|
+
<script>
|
|
52
|
+
// The SDK is available as window._encatch
|
|
53
|
+
_encatch.init('YOUR_API_KEY');
|
|
54
|
+
|
|
55
|
+
_encatch.identifyUser('user-123', {
|
|
56
|
+
email: 'user@example.com',
|
|
57
|
+
name: 'John Doe',
|
|
58
|
+
});
|
|
59
|
+
</script>
|
|
141
60
|
```
|
|
142
61
|
|
|
143
62
|
## API Reference
|
|
144
63
|
|
|
145
|
-
### `init(apiKey,
|
|
64
|
+
### `init(apiKey, config?)`
|
|
146
65
|
|
|
147
|
-
Initialize the
|
|
66
|
+
Initialize the SDK with your API key. This must be called before any other methods. It triggers the loading of the remote implementation script.
|
|
148
67
|
|
|
149
68
|
```javascript
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
69
|
+
_encatch.init('YOUR_API_KEY', {
|
|
70
|
+
webHost: 'https://custom-cdn.example.com', // Optional: override default web host (script will be loaded from webHost + '/s/sdk/v1/encatch.js')
|
|
71
|
+
theme: 'dark', // Optional: 'light', 'dark', or 'system' (default: 'system')
|
|
153
72
|
});
|
|
154
73
|
```
|
|
155
74
|
|
|
156
|
-
### `
|
|
75
|
+
### `identifyUser(id, traits?, options?)`
|
|
157
76
|
|
|
158
|
-
|
|
77
|
+
Identify the current user. The `id` is required, traits and options are optional.
|
|
159
78
|
|
|
160
79
|
```javascript
|
|
161
|
-
//
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
//
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
80
|
+
// Simple - just ID
|
|
81
|
+
_encatch.identifyUser('user-123');
|
|
82
|
+
|
|
83
|
+
// With traits
|
|
84
|
+
_encatch.identifyUser('user-123', {
|
|
85
|
+
email: 'user@example.com', // Optional: user's email
|
|
86
|
+
name: 'John Doe', // Optional: user's full name
|
|
87
|
+
plan: 'premium', // Optional: custom traits
|
|
88
|
+
signed_up_at: new Date(), // Optional: date fields (must end with _at or _date)
|
|
170
89
|
});
|
|
171
|
-
```
|
|
172
90
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
```javascript
|
|
181
|
-
encatch.stop();
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
### `setUser(userId?, traits?)`
|
|
185
|
-
|
|
186
|
-
Set or update user identity.
|
|
187
|
-
|
|
188
|
-
```javascript
|
|
189
|
-
// Set user identity
|
|
190
|
-
encatch.setUser('user-123', {
|
|
191
|
-
$set: { email: 'user@example.com', plan: 'premium' },
|
|
192
|
-
$set_once: { signup_date: '2024-01-01' },
|
|
193
|
-
$counter: { logins: 1 },
|
|
194
|
-
$unset: ['temp_property']
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
// Make user anonymous
|
|
198
|
-
encatch.setUser();
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
#### User Traits Operators
|
|
202
|
-
|
|
203
|
-
- `$set`: Set property value (overwrites existing)
|
|
204
|
-
- `$set_once`: Set only if property doesn't exist
|
|
205
|
-
- `$counter`: Increment counter by value
|
|
206
|
-
- `$unset`: Remove properties (array of property names)
|
|
207
|
-
|
|
208
|
-
### `trackEvent(eventName, properties?)`
|
|
209
|
-
|
|
210
|
-
Track custom events for trigger matching.
|
|
211
|
-
|
|
212
|
-
```javascript
|
|
213
|
-
encatch.trackEvent('purchase_completed', {
|
|
214
|
-
path: '/checkout/success',
|
|
215
|
-
product_id: 'prod-123',
|
|
216
|
-
amount: 99.99
|
|
91
|
+
// With traits and options
|
|
92
|
+
_encatch.identifyUser('user-123', {
|
|
93
|
+
email: 'user@example.com',
|
|
94
|
+
name: 'John Doe',
|
|
95
|
+
}, {
|
|
96
|
+
locale: 'en', // Optional: user's locale
|
|
97
|
+
country: 'US', // Optional: user's country
|
|
217
98
|
});
|
|
218
99
|
```
|
|
219
100
|
|
|
220
|
-
### `
|
|
101
|
+
### `setLocale(locale)`
|
|
221
102
|
|
|
222
|
-
|
|
103
|
+
Set the user's preferred language.
|
|
223
104
|
|
|
224
105
|
```javascript
|
|
225
|
-
//
|
|
226
|
-
encatch.openFeedbackById('feedback-config-id-123');
|
|
227
|
-
|
|
228
|
-
// With theme and language override
|
|
229
|
-
encatch.openFeedbackById('feedback-config-id-123', 'dark', 'es');
|
|
230
|
-
|
|
231
|
-
// With prepopulated answers
|
|
232
|
-
encatch.openFeedbackById('feedback-config-id-123', 'light', 'en', undefined, undefined, [
|
|
233
|
-
{
|
|
234
|
-
sectionIndex: 0,
|
|
235
|
-
questionIndex: 0,
|
|
236
|
-
value: { text: 'Pre-filled answer' }
|
|
237
|
-
}
|
|
238
|
-
]);
|
|
106
|
+
_encatch.setLocale('fr,en,es'); // Comma-separated ISO 639-1 codes
|
|
239
107
|
```
|
|
240
108
|
|
|
241
|
-
### `
|
|
109
|
+
### `setCountry(country)`
|
|
242
110
|
|
|
243
|
-
|
|
111
|
+
Set the user's country.
|
|
244
112
|
|
|
245
113
|
```javascript
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
// With options
|
|
249
|
-
encatch.openFeedbackByName('NPS Survey', 'dark', 'es');
|
|
114
|
+
_encatch.setCountry('FR'); // ISO 3166 country code
|
|
250
115
|
```
|
|
251
116
|
|
|
252
|
-
### `
|
|
117
|
+
### `setTheme(theme)`
|
|
253
118
|
|
|
254
|
-
|
|
119
|
+
Set the theme. Default is 'system'.
|
|
255
120
|
|
|
256
121
|
```javascript
|
|
257
|
-
|
|
258
|
-
|
|
122
|
+
_encatch.setTheme('dark'); // 'light', 'dark', or 'system'
|
|
123
|
+
_encatch.setTheme('light');
|
|
124
|
+
_encatch.setTheme('system'); // Follows system preference
|
|
259
125
|
```
|
|
260
126
|
|
|
261
|
-
### `
|
|
127
|
+
### `trackEvent(eventName)`
|
|
262
128
|
|
|
263
|
-
|
|
129
|
+
Track a custom event.
|
|
264
130
|
|
|
265
131
|
```javascript
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
encatch.setLanguage('en'); // English
|
|
132
|
+
_encatch.trackEvent('button_clicked');
|
|
133
|
+
_encatch.trackEvent('purchase_completed');
|
|
269
134
|
```
|
|
270
135
|
|
|
271
|
-
### `
|
|
136
|
+
### `startSession()`
|
|
272
137
|
|
|
273
|
-
|
|
138
|
+
Manually start a new session. Useful after user login.
|
|
274
139
|
|
|
275
140
|
```javascript
|
|
276
|
-
|
|
141
|
+
_encatch.startSession();
|
|
277
142
|
```
|
|
278
143
|
|
|
279
|
-
### `
|
|
144
|
+
### `resetUser()`
|
|
280
145
|
|
|
281
|
-
|
|
146
|
+
Reset the current user (logout). Reverts the SDK to anonymous mode.
|
|
282
147
|
|
|
283
148
|
```javascript
|
|
284
|
-
|
|
285
|
-
'feedback-id-1',
|
|
286
|
-
'feedback-id-2',
|
|
287
|
-
'feedback-id-3'
|
|
288
|
-
]);
|
|
289
|
-
console.log('Valid feedback IDs:', validIds);
|
|
149
|
+
_encatch.resetUser();
|
|
290
150
|
```
|
|
291
151
|
|
|
292
|
-
### `
|
|
152
|
+
### `showForm(formId, force?)`
|
|
293
153
|
|
|
294
|
-
|
|
154
|
+
Show a specific form by ID.
|
|
295
155
|
|
|
296
156
|
```javascript
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const scrollPercent = (window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)) * 100;
|
|
300
|
-
encatch.capturePageScrollEvent(`${scrollPercent}%`);
|
|
301
|
-
});
|
|
157
|
+
_encatch.showForm('form-abc-123');
|
|
158
|
+
_encatch.showForm('form-abc-123', true); // Force show even if already shown
|
|
302
159
|
```
|
|
303
160
|
|
|
304
|
-
|
|
161
|
+
### `addToResponse(questionId, value)`
|
|
305
162
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
The SDK automatically tracks page changes in single-page applications:
|
|
163
|
+
Prepopulate a form response.
|
|
309
164
|
|
|
310
165
|
```javascript
|
|
311
|
-
|
|
312
|
-
// Triggers "pageLoad" event for configured triggers
|
|
166
|
+
_encatch.addToResponse('question-1', 'Pre-filled answer');
|
|
313
167
|
```
|
|
314
168
|
|
|
315
|
-
###
|
|
169
|
+
### `on(event, callback)`
|
|
316
170
|
|
|
317
|
-
|
|
171
|
+
Subscribe to SDK events. Returns an unsubscribe function.
|
|
318
172
|
|
|
319
173
|
```javascript
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
path: '/products/123',
|
|
323
|
-
category: 'electronics',
|
|
324
|
-
price: 299.99
|
|
174
|
+
const unsubscribe = _encatch.on('form:submit', (payload) => {
|
|
175
|
+
console.log('Form submitted:', payload);
|
|
325
176
|
});
|
|
326
177
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
product_id: 'prod-123'
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
encatch.trackEvent('checkout_started', {
|
|
333
|
-
path: '/checkout',
|
|
334
|
-
cart_value: 599.98
|
|
335
|
-
});
|
|
178
|
+
// Later, to unsubscribe:
|
|
179
|
+
unsubscribe();
|
|
336
180
|
```
|
|
337
181
|
|
|
338
|
-
###
|
|
339
|
-
|
|
340
|
-
```javascript
|
|
341
|
-
// Automatic scroll tracking (if configured in feedback triggers)
|
|
342
|
-
// Or manual tracking:
|
|
343
|
-
let scrollTriggered = false;
|
|
182
|
+
### `off(event, callback)`
|
|
344
183
|
|
|
345
|
-
|
|
346
|
-
const scrollPercent = (window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)) * 100;
|
|
347
|
-
|
|
348
|
-
if (scrollPercent > 50 && !scrollTriggered) {
|
|
349
|
-
encatch.capturePageScrollEvent('50%');
|
|
350
|
-
scrollTriggered = true;
|
|
351
|
-
}
|
|
352
|
-
});
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
## Advanced Usage
|
|
356
|
-
|
|
357
|
-
### Prepopulated Answers
|
|
358
|
-
|
|
359
|
-
Pre-fill feedback forms with known data:
|
|
184
|
+
Unsubscribe from SDK events.
|
|
360
185
|
|
|
361
186
|
```javascript
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
sectionIndex: 0, // First section
|
|
365
|
-
questionIndex: 0, // First question
|
|
366
|
-
value: { text: 'Pre-filled text answer' }
|
|
367
|
-
},
|
|
368
|
-
{
|
|
369
|
-
sectionIndex: 0,
|
|
370
|
-
questionIndex: 1,
|
|
371
|
-
value: { rating: 5 }
|
|
372
|
-
}
|
|
373
|
-
]);
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
### Custom Properties for Targeting
|
|
377
|
-
|
|
378
|
-
Pass custom properties for advanced targeting:
|
|
379
|
-
|
|
380
|
-
```javascript
|
|
381
|
-
encatch.openFeedbackById(
|
|
382
|
-
'feedback-config-id',
|
|
383
|
-
'light',
|
|
384
|
-
'en',
|
|
385
|
-
undefined,
|
|
386
|
-
{
|
|
387
|
-
user_segment: 'premium',
|
|
388
|
-
feature_flag: 'beta_features',
|
|
389
|
-
experiment_group: 'variant_a'
|
|
390
|
-
}
|
|
391
|
-
);
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
### Session Management
|
|
395
|
-
|
|
396
|
-
```javascript
|
|
397
|
-
// Disable automatic session management
|
|
398
|
-
encatch.init('YOUR_API_KEY', {
|
|
399
|
-
host: 'https://your-host.com',
|
|
400
|
-
autoStartSessionDisabled: false
|
|
401
|
-
});
|
|
402
|
-
|
|
403
|
-
// Manual session control (when autoStartSessionDisabled: false)
|
|
404
|
-
encatch.start(); // Start a new session
|
|
405
|
-
encatch.stop(); // End current session
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
### Dynamic Theme Switching
|
|
409
|
-
|
|
410
|
-
```javascript
|
|
411
|
-
// Listen to system theme changes
|
|
412
|
-
const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
413
|
-
|
|
414
|
-
darkModeQuery.addEventListener('change', (e) => {
|
|
415
|
-
encatch.setThemeMode(e.matches ? 'dark' : 'light');
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
// Or use a theme toggle
|
|
419
|
-
function toggleTheme() {
|
|
420
|
-
const currentTheme = getCurrentTheme(); // Your theme logic
|
|
421
|
-
encatch.setThemeMode(currentTheme === 'dark' ? 'light' : 'dark');
|
|
422
|
-
}
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
### Custom CSS Styling
|
|
426
|
-
|
|
427
|
-
```javascript
|
|
428
|
-
// Option 1: Provide custom CSS URL during initialization
|
|
429
|
-
encatch.init('YOUR_API_KEY', {
|
|
430
|
-
host: 'https://your-host.com',
|
|
431
|
-
customCssLink: 'https://your-cdn.com/custom-encatch-theme.css'
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
// Option 2: Configure custom CSS per feedback in the Encatch dashboard
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
### Conditional Feedback Display
|
|
438
|
-
|
|
439
|
-
```javascript
|
|
440
|
-
// Only show feedback to premium users
|
|
441
|
-
if (user.plan === 'premium') {
|
|
442
|
-
encatch.openFeedbackById('premium-user-feedback');
|
|
187
|
+
function handleSubmit(payload) {
|
|
188
|
+
console.log('Form submitted:', payload);
|
|
443
189
|
}
|
|
444
190
|
|
|
445
|
-
|
|
446
|
-
if (isNewUser) {
|
|
447
|
-
encatch.openFeedbackByName('Onboarding Feedback');
|
|
448
|
-
} else {
|
|
449
|
-
encatch.openFeedbackByName('Feature Usage Survey');
|
|
450
|
-
}
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
## Form Event Listeners
|
|
454
|
-
|
|
455
|
-
The SDK provides two approaches for listening to feedback form events: **config-based** and **runtime-based**.
|
|
456
|
-
|
|
457
|
-
### Available Form Events
|
|
458
|
-
|
|
459
|
-
| Event | Payload | Description |
|
|
460
|
-
|-------|---------|-------------|
|
|
461
|
-
| `form:submit` | `{ feedbackIdentifier: string, feedbackConfigurationId: string, completionTimeInSeconds: number, response: Object }` | Emitted when the user completes and submits the feedback form |
|
|
462
|
-
| `form:view` | `{ feedbackIdentifier: string, feedbackConfigurationId: string }` | Emitted when the feedback form is displayed to the user |
|
|
463
|
-
| `form:close` | `{ feedbackIdentifier: string, feedbackConfigurationId: string }` | Emitted when the user closes the feedback form (with or without submitting) |
|
|
464
|
-
| `form:questionAnswered` | `{ questionId: string, answer: Object }` | Emitted when the user answers a question |
|
|
465
|
-
| `form:sectionChange` | `{ sectionIndex: number }` | Emitted when the user navigates to a different section |
|
|
466
|
-
| `form:error` | `{ error: string }` | Emitted when an error occurs during form interaction |
|
|
467
|
-
|
|
468
|
-
### Approach 1: Config-Based (Recommended)
|
|
469
|
-
|
|
470
|
-
Define event handlers during SDK initialization using the `onFormEvent` callback:
|
|
471
|
-
|
|
472
|
-
```javascript
|
|
473
|
-
encatch.init('YOUR_API_KEY', {
|
|
474
|
-
host: 'https://your-host.com',
|
|
475
|
-
autoStartEnabled: true,
|
|
476
|
-
onFormEvent: (formEvent) => {
|
|
477
|
-
// Listen to form submission
|
|
478
|
-
formEvent.onSubmit((data) => {
|
|
479
|
-
console.log('Form submitted:', data);
|
|
480
|
-
console.log('Feedback ID:', data.feedbackIdentifier);
|
|
481
|
-
console.log('Config ID:', data.feedbackConfigurationId);
|
|
482
|
-
console.log('Completion time:', data.completionTimeInSeconds);
|
|
483
|
-
|
|
484
|
-
// Send to analytics
|
|
485
|
-
analytics.track('Feedback Submitted', {
|
|
486
|
-
feedbackId: data.feedbackIdentifier,
|
|
487
|
-
configId: data.feedbackConfigurationId
|
|
488
|
-
});
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
// Listen to form view
|
|
492
|
-
formEvent.onView((data) => {
|
|
493
|
-
console.log('Form viewed:', data);
|
|
494
|
-
});
|
|
495
|
-
|
|
496
|
-
// Listen to form close
|
|
497
|
-
formEvent.onClose((data) => {
|
|
498
|
-
console.log('Form closed:', data);
|
|
499
|
-
});
|
|
500
|
-
|
|
501
|
-
// Listen to question answered
|
|
502
|
-
formEvent.onQuestionAnswered((data) => {
|
|
503
|
-
console.log('Question answered:', data.questionId, data.answer);
|
|
504
|
-
});
|
|
505
|
-
|
|
506
|
-
// Listen to section change
|
|
507
|
-
formEvent.onSectionChange((data) => {
|
|
508
|
-
console.log('Section changed to:', data.sectionIndex);
|
|
509
|
-
});
|
|
510
|
-
|
|
511
|
-
// Listen to errors
|
|
512
|
-
formEvent.onError((data) => {
|
|
513
|
-
console.error('Form error:', data.error);
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
});
|
|
517
|
-
```
|
|
518
|
-
|
|
519
|
-
### Approach 2: Runtime-Based
|
|
520
|
-
|
|
521
|
-
Subscribe to events at runtime using the `encatch.on()` method:
|
|
522
|
-
|
|
523
|
-
```javascript
|
|
524
|
-
// Subscribe to form submission
|
|
525
|
-
const unsubscribeSubmit = encatch.on('form:submit', (data) => {
|
|
526
|
-
console.log('Form submitted:', data);
|
|
527
|
-
alert(`Feedback submitted! ID: ${data.feedbackIdentifier}`);
|
|
528
|
-
});
|
|
529
|
-
|
|
530
|
-
// Subscribe to form view
|
|
531
|
-
const unsubscribeView = encatch.on('form:view', (data) => {
|
|
532
|
-
console.log('Form viewed:', data);
|
|
533
|
-
});
|
|
534
|
-
|
|
535
|
-
// Subscribe to form close
|
|
536
|
-
const unsubscribeClose = encatch.on('form:close', (data) => {
|
|
537
|
-
console.log('Form closed:', data);
|
|
538
|
-
});
|
|
539
|
-
|
|
540
|
-
// Subscribe to question answered
|
|
541
|
-
const unsubscribeQuestion = encatch.on('form:questionAnswered', (data) => {
|
|
542
|
-
console.log('Question answered:', data);
|
|
543
|
-
});
|
|
544
|
-
|
|
545
|
-
// Subscribe to section change
|
|
546
|
-
const unsubscribeSection = encatch.on('form:sectionChange', (data) => {
|
|
547
|
-
console.log('Section changed:', data);
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
// Subscribe to errors
|
|
551
|
-
const unsubscribeError = encatch.on('form:error', (data) => {
|
|
552
|
-
console.error('Form error:', data);
|
|
553
|
-
});
|
|
554
|
-
|
|
555
|
-
// Unsubscribe when no longer needed
|
|
556
|
-
unsubscribeSubmit();
|
|
557
|
-
unsubscribeView();
|
|
558
|
-
```
|
|
559
|
-
|
|
560
|
-
### Integration Examples
|
|
561
|
-
|
|
562
|
-
#### Google Analytics Integration
|
|
563
|
-
|
|
564
|
-
```javascript
|
|
565
|
-
encatch.init('YOUR_API_KEY', {
|
|
566
|
-
host: 'https://your-host.com',
|
|
567
|
-
autoStartEnabled: true,
|
|
568
|
-
onFormEvent: (formEvent) => {
|
|
569
|
-
formEvent.onView((data) => {
|
|
570
|
-
gtag('event', 'feedback_viewed', {
|
|
571
|
-
feedback_id: data.feedbackIdentifier,
|
|
572
|
-
config_id: data.feedbackConfigurationId
|
|
573
|
-
});
|
|
574
|
-
});
|
|
575
|
-
|
|
576
|
-
formEvent.onSubmit((data) => {
|
|
577
|
-
gtag('event', 'feedback_submitted', {
|
|
578
|
-
feedback_id: data.feedbackIdentifier,
|
|
579
|
-
config_id: data.feedbackConfigurationId,
|
|
580
|
-
completion_time: data.completionTimeInSeconds
|
|
581
|
-
});
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
formEvent.onClose((data) => {
|
|
585
|
-
gtag('event', 'feedback_closed', {
|
|
586
|
-
feedback_id: data.feedbackIdentifier
|
|
587
|
-
});
|
|
588
|
-
});
|
|
589
|
-
}
|
|
590
|
-
});
|
|
591
|
-
```
|
|
191
|
+
_encatch.on('form:submit', handleSubmit);
|
|
592
192
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
```javascript
|
|
596
|
-
encatch.init('YOUR_API_KEY', {
|
|
597
|
-
host: 'https://your-host.com',
|
|
598
|
-
autoStartEnabled: true,
|
|
599
|
-
onFormEvent: (formEvent) => {
|
|
600
|
-
formEvent.onSubmit((data) => {
|
|
601
|
-
analytics.track('Feedback Completed', {
|
|
602
|
-
feedbackId: data.feedbackIdentifier,
|
|
603
|
-
configId: data.feedbackConfigurationId,
|
|
604
|
-
duration: data.completionTimeInSeconds
|
|
605
|
-
});
|
|
606
|
-
});
|
|
607
|
-
|
|
608
|
-
formEvent.onQuestionAnswered((data) => {
|
|
609
|
-
analytics.track('Question Answered', {
|
|
610
|
-
questionId: data.questionId,
|
|
611
|
-
answerType: data.answer.answer_type
|
|
612
|
-
});
|
|
613
|
-
});
|
|
614
|
-
}
|
|
615
|
-
});
|
|
193
|
+
// Later:
|
|
194
|
+
_encatch.off('form:submit', handleSubmit);
|
|
616
195
|
```
|
|
617
196
|
|
|
618
|
-
|
|
197
|
+
## Event Types
|
|
619
198
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
window.dataLayer.push({
|
|
628
|
-
event: 'feedback_submitted',
|
|
629
|
-
feedbackId: data.feedbackIdentifier,
|
|
630
|
-
configId: data.feedbackConfigurationId,
|
|
631
|
-
completionTime: data.completionTimeInSeconds
|
|
632
|
-
});
|
|
633
|
-
});
|
|
634
|
-
}
|
|
635
|
-
});
|
|
636
|
-
```
|
|
637
|
-
|
|
638
|
-
#### CRM Integration (e.g., Salesforce, HubSpot)
|
|
639
|
-
|
|
640
|
-
```javascript
|
|
641
|
-
encatch.init('YOUR_API_KEY', {
|
|
642
|
-
host: 'https://your-host.com',
|
|
643
|
-
autoStartEnabled: true,
|
|
644
|
-
onFormEvent: (formEvent) => {
|
|
645
|
-
formEvent.onSubmit(async (data) => {
|
|
646
|
-
// Send to your CRM
|
|
647
|
-
await fetch('https://your-crm.com/api/feedback', {
|
|
648
|
-
method: 'POST',
|
|
649
|
-
headers: { 'Content-Type': 'application/json' },
|
|
650
|
-
body: JSON.stringify({
|
|
651
|
-
feedbackId: data.feedbackIdentifier,
|
|
652
|
-
userId: window.currentUserId,
|
|
653
|
-
response: data.response,
|
|
654
|
-
timestamp: new Date().toISOString()
|
|
655
|
-
})
|
|
656
|
-
});
|
|
657
|
-
});
|
|
658
|
-
}
|
|
659
|
-
});
|
|
660
|
-
```
|
|
199
|
+
| Event | Description |
|
|
200
|
+
|-------|-------------|
|
|
201
|
+
| `form:show` | Fired when a form is displayed |
|
|
202
|
+
| `form:submit` | Fired when a form is submitted |
|
|
203
|
+
| `form:close` | Fired when a form is closed |
|
|
204
|
+
| `form:complete` | Fired when a form is completed |
|
|
205
|
+
| `form:error` | Fired when an error occurs |
|
|
661
206
|
|
|
662
207
|
## TypeScript Support
|
|
663
208
|
|
|
664
|
-
The SDK is
|
|
209
|
+
The SDK is written in TypeScript and includes full type definitions.
|
|
665
210
|
|
|
666
211
|
```typescript
|
|
667
|
-
import '@encatch/web-sdk';
|
|
668
|
-
|
|
669
|
-
// All methods are typed
|
|
670
|
-
encatch.init('YOUR_API_KEY', {
|
|
671
|
-
host: 'https://your-host.com',
|
|
672
|
-
autoStartEnabled: true,
|
|
673
|
-
themeMode: 'light', // Type: 'light' | 'dark'
|
|
674
|
-
language: 'en'
|
|
675
|
-
});
|
|
676
|
-
|
|
677
|
-
// User traits are typed
|
|
678
|
-
encatch.setUser('user-123', {
|
|
679
|
-
$set: { email: 'user@example.com' },
|
|
680
|
-
$set_once: { signup_date: '2024-01-01' },
|
|
681
|
-
$counter: { logins: 1 },
|
|
682
|
-
$unset: ['temp_field']
|
|
683
|
-
});
|
|
684
|
-
|
|
685
|
-
// Event properties are typed
|
|
686
|
-
encatch.trackEvent('custom_event', {
|
|
687
|
-
path: '/page',
|
|
688
|
-
event: 'click'
|
|
689
|
-
});
|
|
690
|
-
```
|
|
212
|
+
import { _encatch, UserTraits, EncatchConfig, EventType } from '@encatch/web-sdk';
|
|
691
213
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
```bash
|
|
702
|
-
# Install dependencies
|
|
703
|
-
pnpm install
|
|
704
|
-
|
|
705
|
-
# Start development server
|
|
706
|
-
pnpm dev
|
|
214
|
+
// Example with $set operation
|
|
215
|
+
const userTraits: UserTraits = {
|
|
216
|
+
$set: {
|
|
217
|
+
email: 'user@example.com',
|
|
218
|
+
name: 'John Doe',
|
|
219
|
+
customField: 'value',
|
|
220
|
+
},
|
|
221
|
+
};
|
|
707
222
|
|
|
708
|
-
|
|
709
|
-
pnpm build
|
|
223
|
+
_encatch.identifyUser('user-123', userTraits);
|
|
710
224
|
|
|
711
|
-
|
|
712
|
-
|
|
225
|
+
// Example with multiple operations
|
|
226
|
+
const userTraitsAdvanced: UserTraits = {
|
|
227
|
+
$set: { email: 'user@example.com', name: 'John Doe' },
|
|
228
|
+
$setOnce: { firstSeenAt: new Date() },
|
|
229
|
+
$increment: { loginCount: 1 },
|
|
230
|
+
$unset: ['oldField'],
|
|
231
|
+
};
|
|
713
232
|
```
|
|
714
233
|
|
|
715
|
-
|
|
234
|
+
## How It Works
|
|
716
235
|
|
|
717
|
-
|
|
718
|
-
packages/web-sdk/
|
|
719
|
-
├── src/
|
|
720
|
-
│ ├── @types/ # TypeScript type definitions
|
|
721
|
-
│ ├── hooks/ # Preact hooks for functionality
|
|
722
|
-
│ ├── utils/ # Utility functions
|
|
723
|
-
│ ├── index.tsx # Main SDK initialization
|
|
724
|
-
│ ├── core-wrapper.tsx # Core SDK logic
|
|
725
|
-
│ └── surveySDK.ts # Event SDK
|
|
726
|
-
├── dist-sdk/ # Build output
|
|
727
|
-
├── package.json
|
|
728
|
-
├── vite.config.ts # Vite configuration
|
|
729
|
-
└── README.md
|
|
730
|
-
```
|
|
731
|
-
|
|
732
|
-
### Build Output
|
|
236
|
+
The SDK uses a "stub + async loader" pattern:
|
|
733
237
|
|
|
734
|
-
The
|
|
238
|
+
1. The lightweight stub is loaded immediately and exposes the `_encatch` object
|
|
239
|
+
2. All method calls are queued in an internal array
|
|
240
|
+
3. When `init()` is called, the full implementation script is loaded from the CDN
|
|
241
|
+
4. Once loaded, the queued commands are processed in order
|
|
242
|
+
5. Future calls go directly to the real implementation
|
|
735
243
|
|
|
736
|
-
|
|
737
|
-
-
|
|
738
|
-
-
|
|
739
|
-
-
|
|
244
|
+
This pattern ensures:
|
|
245
|
+
- Fast initial page load (tiny stub)
|
|
246
|
+
- No lost commands (queue preserves all calls)
|
|
247
|
+
- Type safety (full TypeScript definitions)
|
|
740
248
|
|
|
741
249
|
## Browser Support
|
|
742
250
|
|
|
743
|
-
- Chrome
|
|
744
|
-
- Firefox
|
|
745
|
-
- Safari
|
|
746
|
-
-
|
|
747
|
-
- Opera 50+
|
|
748
|
-
- Edge (Chromium-based)
|
|
251
|
+
- Chrome 80+
|
|
252
|
+
- Firefox 75+
|
|
253
|
+
- Safari 13.1+
|
|
254
|
+
- Edge 80+
|
|
749
255
|
|
|
750
256
|
## License
|
|
751
257
|
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
## Support
|
|
755
|
-
|
|
756
|
-
For issues, questions, or feature requests, please contact your Encatch account manager or visit the [Encatch Dashboard](https://app.encatch.com).
|
|
258
|
+
MIT
|