@encatch/web-sdk
v0.0.28
Published
A powerful, lightweight JavaScript SDK for collecting user feedback and running surveys on web applications
Readme
Encatch Web SDK
A powerful, lightweight JavaScript SDK for collecting user feedback and running surveys on web applications. Built with Preact and TypeScript, the Encatch Web SDK provides intelligent trigger-based feedback collection with advanced targeting and frequency control.
Features
- Intelligent Triggers: Automatically display feedback based on user behavior
- Page load triggers
- Custom event triggers
- Scroll-based triggers
- Time-delayed triggers
- User Session Management: Track and manage user sessions with device fingerprinting
- Frequency Control: Configure feedback display frequency and scheduling
- Multi-language Support: Display feedback in multiple languages
- Theme Support: Light and dark mode with custom CSS
- Prepopulated Answers: Pre-fill feedback forms with known data
- Event Tracking: Track user interactions and custom events
- TypeScript Support: Fully typed API for better developer experience
- Lightweight: Minimal bundle size with optimized performance
Installation
Via Script Tag (Recommended)
Add the following script to your HTML file before the closing </head> tag:
<script>
!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))}}))}}();
</script>Then initialize the SDK:
<script>
encatch.init('YOUR_API_KEY', {
host: 'https://your-host.com',
autoStartEnabled: true
});
</script>Via NPM (For Module Bundlers)
npm install @encatch/web-sdkimport '@encatch/web-sdk';
encatch.init('YOUR_API_KEY', {
host: 'https://your-host.com',
autoStartEnabled: true
});Quick Start
Basic Setup
// Initialize the SDK
encatch.init('YOUR_API_KEY', {
host: 'https://your-host.com',
autoStartEnabled: true,
themeMode: 'light',
language: 'en'
});
// Set user identity (optional)
encatch.setUser('user-123', {
$set: {
email: '[email protected]',
name: 'John Doe',
plan: 'premium'
}
});
// Track custom events
encatch.trackEvent('button_clicked', {
path: '/dashboard',
button_id: 'upgrade-button'
});Manual Trigger
// Open feedback by ID
encatch.openFeedbackById('feedback-config-id-123');
// Open feedback by name
encatch.openFeedbackByName('Customer Satisfaction Survey');
// With theme and language override
encatch.openFeedbackById('feedback-config-id-123', 'dark', 'es');Configuration Options
Initialization Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| host | string | - | Required. The host URL for the Encatch API |
| autoStartEnabled | boolean | false | Automatically start fetching eligible feedbacks |
| autoStartSessionDisabled | boolean | true | Disable automatic session management |
| processAfterIdentitySet | boolean | false | Wait for user identity before processing |
| themeMode | 'light' \| 'dark' | 'light' | Default theme mode |
| language | string | 'en' | Default language code |
| customCssLink | string | - | URL to custom CSS file |
| setUser | UserInfo | - | Initial user identity |
| customProperties | Record<string, string> | - | Custom properties for targeting |
| onSessionDisabled | (action, message) => void | - | Callback when session functions are disabled |
Example: Complete Configuration
encatch.init('YOUR_API_KEY', {
host: 'https://your-host.com',
autoStartEnabled: true,
autoStartSessionDisabled: false,
themeMode: 'light',
language: 'en',
customCssLink: 'https://your-cdn.com/custom-theme.css',
setUser: {
userId: 'user-123',
traits: {
$set: {
email: '[email protected]',
plan: 'premium'
}
}
},
onSessionDisabled: (action, message) => {
console.warn(`Session action blocked: ${action} - ${message}`);
}
});API Reference
init(apiKey, options)
Initialize the Encatch SDK.
encatch.init('YOUR_API_KEY', {
host: 'https://your-host.com',
autoStartEnabled: true
});start(userId?, traits?)
Start the SDK and optionally set user identity. Useful when autoStartEnabled: false.
// Start without user
encatch.start();
// Start with user identity
encatch.start('user-123', {
$set: {
email: '[email protected]',
name: 'John Doe'
}
});stop()
Stop the SDK. Behavior depends on initialization:
- If initialized with
autoStartEnabled: false: Clears all data, feedbacks, and frequency tracking - If initialized with
autoStartEnabled: true: Makes user anonymous but retains feedbacks
encatch.stop();setUser(userId?, traits?)
Set or update user identity.
// Set user identity
encatch.setUser('user-123', {
$set: { email: '[email protected]', plan: 'premium' },
$set_once: { signup_date: '2024-01-01' },
$counter: { logins: 1 },
$unset: ['temp_property']
});
// Make user anonymous
encatch.setUser();User Traits Operators
$set: Set property value (overwrites existing)$set_once: Set only if property doesn't exist$counter: Increment counter by value$unset: Remove properties (array of property names)
trackEvent(eventName, properties?)
Track custom events for trigger matching.
encatch.trackEvent('purchase_completed', {
path: '/checkout/success',
product_id: 'prod-123',
amount: 99.99
});openFeedbackById(feedbackConfigId, theme?, language?, event?, customProperties?, prepopulatedAnswers?)
Manually open a feedback form by its configuration ID.
// Basic usage
encatch.openFeedbackById('feedback-config-id-123');
// With theme and language override
encatch.openFeedbackById('feedback-config-id-123', 'dark', 'es');
// With prepopulated answers
encatch.openFeedbackById('feedback-config-id-123', 'light', 'en', undefined, undefined, [
{
sectionIndex: 0,
questionIndex: 0,
value: { text: 'Pre-filled answer' }
}
]);openFeedbackByName(feedbackName, theme?, language?, event?, customProperties?, prepopulatedAnswers?)
Manually open a feedback form by its name.
encatch.openFeedbackByName('Customer Satisfaction Survey');
// With options
encatch.openFeedbackByName('NPS Survey', 'dark', 'es');setThemeMode(theme)
Change the theme mode dynamically.
encatch.setThemeMode('dark');
encatch.setThemeMode('light');setLanguage(language)
Change the language dynamically.
encatch.setLanguage('es'); // Spanish
encatch.setLanguage('fr'); // French
encatch.setLanguage('en'); // EnglishforceFetchEligibleFeedbacks()
Force refresh the list of eligible feedbacks.
await encatch.forceFetchEligibleFeedbacks();verifyFeedbackIds(feedbackIds)
Verify which feedback IDs are currently eligible.
const validIds = encatch.verifyFeedbackIds([
'feedback-id-1',
'feedback-id-2',
'feedback-id-3'
]);
console.log('Valid feedback IDs:', validIds);capturePageScrollEvent(scrollPercent)
Manually trigger scroll-based feedback.
// Track scroll percentage
window.addEventListener('scroll', () => {
const scrollPercent = (window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)) * 100;
encatch.capturePageScrollEvent(`${scrollPercent}%`);
});Event Tracking
Automatic Page Tracking
The SDK automatically tracks page changes in single-page applications:
// Page changes are tracked automatically
// Triggers "pageLoad" event for configured triggersCustom Events
Track custom events for business logic:
// E-commerce example
encatch.trackEvent('product_viewed', {
path: '/products/123',
category: 'electronics',
price: 299.99
});
encatch.trackEvent('add_to_cart', {
path: '/products/123',
product_id: 'prod-123'
});
encatch.trackEvent('checkout_started', {
path: '/checkout',
cart_value: 599.98
});Scroll Tracking
// Automatic scroll tracking (if configured in feedback triggers)
// Or manual tracking:
let scrollTriggered = false;
window.addEventListener('scroll', () => {
const scrollPercent = (window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)) * 100;
if (scrollPercent > 50 && !scrollTriggered) {
encatch.capturePageScrollEvent('50%');
scrollTriggered = true;
}
});Advanced Usage
Prepopulated Answers
Pre-fill feedback forms with known data:
encatch.openFeedbackById('feedback-config-id', 'light', 'en', undefined, undefined, [
{
sectionIndex: 0, // First section
questionIndex: 0, // First question
value: { text: 'Pre-filled text answer' }
},
{
sectionIndex: 0,
questionIndex: 1,
value: { rating: 5 }
}
]);Custom Properties for Targeting
Pass custom properties for advanced targeting:
encatch.openFeedbackById(
'feedback-config-id',
'light',
'en',
undefined,
{
user_segment: 'premium',
feature_flag: 'beta_features',
experiment_group: 'variant_a'
}
);Session Management
// Disable automatic session management
encatch.init('YOUR_API_KEY', {
host: 'https://your-host.com',
autoStartSessionDisabled: false
});
// Manual session control (when autoStartSessionDisabled: false)
encatch.start(); // Start a new session
encatch.stop(); // End current sessionDynamic Theme Switching
// Listen to system theme changes
const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)');
darkModeQuery.addEventListener('change', (e) => {
encatch.setThemeMode(e.matches ? 'dark' : 'light');
});
// Or use a theme toggle
function toggleTheme() {
const currentTheme = getCurrentTheme(); // Your theme logic
encatch.setThemeMode(currentTheme === 'dark' ? 'light' : 'dark');
}Custom CSS Styling
// Option 1: Provide custom CSS URL during initialization
encatch.init('YOUR_API_KEY', {
host: 'https://your-host.com',
customCssLink: 'https://your-cdn.com/custom-encatch-theme.css'
});
// Option 2: Configure custom CSS per feedback in the Encatch dashboardConditional Feedback Display
// Only show feedback to premium users
if (user.plan === 'premium') {
encatch.openFeedbackById('premium-user-feedback');
}
// Show different feedback based on user journey
if (isNewUser) {
encatch.openFeedbackByName('Onboarding Feedback');
} else {
encatch.openFeedbackByName('Feature Usage Survey');
}Form Event Listeners
The SDK provides two approaches for listening to feedback form events: config-based and runtime-based.
Available Form Events
| Event | Payload | Description |
|-------|---------|-------------|
| form:submit | { feedbackIdentifier: string, feedbackConfigurationId: string, completionTimeInSeconds: number, response: Object } | Emitted when the user completes and submits the feedback form |
| form:view | { feedbackIdentifier: string, feedbackConfigurationId: string } | Emitted when the feedback form is displayed to the user |
| form:close | { feedbackIdentifier: string, feedbackConfigurationId: string } | Emitted when the user closes the feedback form (with or without submitting) |
| form:questionAnswered | { questionId: string, answer: Object } | Emitted when the user answers a question |
| form:sectionChange | { sectionIndex: number } | Emitted when the user navigates to a different section |
| form:error | { error: string } | Emitted when an error occurs during form interaction |
Approach 1: Config-Based (Recommended)
Define event handlers during SDK initialization using the onFormEvent callback:
encatch.init('YOUR_API_KEY', {
host: 'https://your-host.com',
autoStartEnabled: true,
onFormEvent: (formEvent) => {
// Listen to form submission
formEvent.onSubmit((data) => {
console.log('Form submitted:', data);
console.log('Feedback ID:', data.feedbackIdentifier);
console.log('Config ID:', data.feedbackConfigurationId);
console.log('Completion time:', data.completionTimeInSeconds);
// Send to analytics
analytics.track('Feedback Submitted', {
feedbackId: data.feedbackIdentifier,
configId: data.feedbackConfigurationId
});
});
// Listen to form view
formEvent.onView((data) => {
console.log('Form viewed:', data);
});
// Listen to form close
formEvent.onClose((data) => {
console.log('Form closed:', data);
});
// Listen to question answered
formEvent.onQuestionAnswered((data) => {
console.log('Question answered:', data.questionId, data.answer);
});
// Listen to section change
formEvent.onSectionChange((data) => {
console.log('Section changed to:', data.sectionIndex);
});
// Listen to errors
formEvent.onError((data) => {
console.error('Form error:', data.error);
});
}
});Approach 2: Runtime-Based
Subscribe to events at runtime using the encatch.on() method:
// Subscribe to form submission
const unsubscribeSubmit = encatch.on('form:submit', (data) => {
console.log('Form submitted:', data);
alert(`Feedback submitted! ID: ${data.feedbackIdentifier}`);
});
// Subscribe to form view
const unsubscribeView = encatch.on('form:view', (data) => {
console.log('Form viewed:', data);
});
// Subscribe to form close
const unsubscribeClose = encatch.on('form:close', (data) => {
console.log('Form closed:', data);
});
// Subscribe to question answered
const unsubscribeQuestion = encatch.on('form:questionAnswered', (data) => {
console.log('Question answered:', data);
});
// Subscribe to section change
const unsubscribeSection = encatch.on('form:sectionChange', (data) => {
console.log('Section changed:', data);
});
// Subscribe to errors
const unsubscribeError = encatch.on('form:error', (data) => {
console.error('Form error:', data);
});
// Unsubscribe when no longer needed
unsubscribeSubmit();
unsubscribeView();Integration Examples
Google Analytics Integration
encatch.init('YOUR_API_KEY', {
host: 'https://your-host.com',
autoStartEnabled: true,
onFormEvent: (formEvent) => {
formEvent.onView((data) => {
gtag('event', 'feedback_viewed', {
feedback_id: data.feedbackIdentifier,
config_id: data.feedbackConfigurationId
});
});
formEvent.onSubmit((data) => {
gtag('event', 'feedback_submitted', {
feedback_id: data.feedbackIdentifier,
config_id: data.feedbackConfigurationId,
completion_time: data.completionTimeInSeconds
});
});
formEvent.onClose((data) => {
gtag('event', 'feedback_closed', {
feedback_id: data.feedbackIdentifier
});
});
}
});Segment Analytics Integration
encatch.init('YOUR_API_KEY', {
host: 'https://your-host.com',
autoStartEnabled: true,
onFormEvent: (formEvent) => {
formEvent.onSubmit((data) => {
analytics.track('Feedback Completed', {
feedbackId: data.feedbackIdentifier,
configId: data.feedbackConfigurationId,
duration: data.completionTimeInSeconds
});
});
formEvent.onQuestionAnswered((data) => {
analytics.track('Question Answered', {
questionId: data.questionId,
answerType: data.answer.answer_type
});
});
}
});Custom Data Layer (GTM)
encatch.init('YOUR_API_KEY', {
host: 'https://your-host.com',
autoStartEnabled: true,
onFormEvent: (formEvent) => {
formEvent.onSubmit((data) => {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'feedback_submitted',
feedbackId: data.feedbackIdentifier,
configId: data.feedbackConfigurationId,
completionTime: data.completionTimeInSeconds
});
});
}
});CRM Integration (e.g., Salesforce, HubSpot)
encatch.init('YOUR_API_KEY', {
host: 'https://your-host.com',
autoStartEnabled: true,
onFormEvent: (formEvent) => {
formEvent.onSubmit(async (data) => {
// Send to your CRM
await fetch('https://your-crm.com/api/feedback', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
feedbackId: data.feedbackIdentifier,
userId: window.currentUserId,
response: data.response,
timestamp: new Date().toISOString()
})
});
});
}
});TypeScript Support
The SDK is fully typed. TypeScript definitions are included:
import '@encatch/web-sdk';
// All methods are typed
encatch.init('YOUR_API_KEY', {
host: 'https://your-host.com',
autoStartEnabled: true,
themeMode: 'light', // Type: 'light' | 'dark'
language: 'en'
});
// User traits are typed
encatch.setUser('user-123', {
$set: { email: '[email protected]' },
$set_once: { signup_date: '2024-01-01' },
$counter: { logins: 1 },
$unset: ['temp_field']
});
// Event properties are typed
encatch.trackEvent('custom_event', {
path: '/page',
event: 'click'
});Development
Prerequisites
- Node.js 18+
- pnpm
Setup
# Install dependencies
pnpm install
# Start development server
pnpm dev
# Build for production
pnpm build
# Preview production build
pnpm previewProject Structure
packages/web-sdk/
├── src/
│ ├── @types/ # TypeScript type definitions
│ ├── hooks/ # Preact hooks for functionality
│ ├── utils/ # Utility functions
│ ├── index.tsx # Main SDK initialization
│ ├── core-wrapper.tsx # Core SDK logic
│ └── surveySDK.ts # Event SDK
├── dist-sdk/ # Build output
├── package.json
├── vite.config.ts # Vite configuration
└── README.mdBuild Output
The build produces:
encatch-web-sdk.js- Main SDK bundleencatch-web-sdk.css- Default stylespreview-sdk.js- Preview/demo versionembedded-sdk.js- Embedded version
Browser Support
- Chrome 62+
- Firefox 59+
- Safari 12+
- iOS Safari 10.3+
- Opera 50+
- Edge (Chromium-based)
License
Private - Copyright (c) Encatch
Support
For issues, questions, or feature requests, please contact your Encatch account manager or visit the Encatch Dashboard.
