JavaScript Web SDK
A lightweight, type-safe JavaScript SDK for integrating Encatch forms and surveys into your web application
A lightweight, type-safe JavaScript SDK for integrating Encatch forms and surveys into your web application.
Installation
npm install @encatch/web-sdkPin the version in the URL to the same @encatch/web-sdk version you install from npm, and update it when you upgrade the package.
<script src="https://cdn.jsdelivr.net/npm/@encatch/web-sdk@1.1.0-beta.7/dist/encatch.iife.js"></script>Quick Start
import { _encatch } from '@encatch/web-sdk';
// Initialize with your API key
_encatch.init('YOUR_PUBLISHABLE_SDK_KEY');
// Identify the user
_encatch.identifyUser('user-123', {
$set: {
email: 'user@example.com',
name: 'John Doe',
},
});<script src="https://cdn.jsdelivr.net/npm/@encatch/web-sdk@1.1.0-beta.7/dist/encatch.iife.js"></script>
<script>
// The SDK is available as window._encatch
_encatch.init('YOUR_PUBLISHABLE_SDK_KEY');
_encatch.identifyUser('user-123', {
$set: {
email: 'user@example.com',
name: 'John Doe',
},
});
</script>API Reference
Initialization
Initialize the SDK with your API key. This must be called before any other methods. It triggers the loading of the remote implementation script.
_encatch.init('YOUR_PUBLISHABLE_SDK_KEY', {
webHost: 'https://custom-cdn.example.com',
theme: 'dark',
apiBaseUrl: 'https://app.encatch.com',
isFullScreen: false,
});Optional: intercept before the built-in iframe opens so you can render a custom form UI (use with Submit form, Emit event, and Refine text (AI)):
_encatch.init('YOUR_PUBLISHABLE_SDK_KEY', {
onBeforeShowForm: async (payload) => {
// Return false to skip the iframe; pending addToResponse() values are cleared.
// Return true (default) to show the Encatch iframe as usual.
return true;
},
});Prop
Type
Prop
Type
onBeforeShowForm payload (each show attempt):
Prop
Type
User Identification
Identify the current user. The userName is required (can be a username, email, or unique identifier). Traits and options are optional.
// Simple — just ID
_encatch.identifyUser('user-123');// With traits
_encatch.identifyUser('user-123', {
$set: {
email: 'user@example.com',
name: 'John Doe',
plan: 'premium',
signed_up_at: new Date(),
},
});// With multiple operations
_encatch.identifyUser('user-123', {
$set: { email: 'user@example.com', name: 'John Doe' },
$setOnce: { firstSeenAt: new Date() },
$increment: { loginCount: 1 },
$unset: ['oldField'],
});// With options
_encatch.identifyUser('user-123', traits, {
locale: 'fr,en,es',
country: 'US',
});Prop
Type
User traits support nested operations:
| Operation | Description |
|---|---|
$set | Set user attributes (overwrites existing values) |
$setOnce | Set user attributes only if they don't already exist |
$increment | Increment numeric user attributes |
$decrement | Decrement numeric user attributes |
$unset | Remove user attributes |
Prop
Type
Session after identify
After a successful identify response, the SDK calls startSession({ skipImmediatePing: true }): the 30-second ping interval still runs, but there is no immediate ping. If the response includes pingAgainIn, the SDK may adjust the next ping timing. The initial automatic trackScreen for the current URL follows the same default as startSession (see Session) unless your app calls startSession again with different options.
Secure Identification
Recommended
Using the secure option with a server-generated signature is recommended to verify that identification requests come from your backend. Keep your secret key on the server only — never expose it in client-side code.
Use the secure option when you need to verify that the identification request comes from your backend. Pass a server-generated signature (and optionally generatedDateTimeinUTC) so Encatch can validate the request. The generatedDateTimeinUTC value — the timestamp used during signature generation — ensures the signature is limited to a defined lifespan.
_encatch.identifyUser('user-123', traits, {
secure: {
signature: 'server-generated-signature',
generatedDateTimeinUTC: '2025-03-13T14:30:00.000Z', // Optional — timestamp used during signature generation; limits signature to a defined lifespan
},
});Locale
When using our centralized translation interface or language targeting, you can manually set the language of a user. If you don't set the language, the preferred web-browser languages are used instead.
The expected format is a comma-separated list of two-character ISO 639-1 codes.
As an alternative to the setLocale method, you can provide a locale option when identifying a user.
_encatch.setLocale('fr,en,es'); // Comma-separated two-character ISO 639-1 codes_encatch.identifyUser('user-123', {}, {
locale: 'fr,en,es'
});Country
When using country targeting, the country of a user is by default detected automatically using their IP address. You can choose to manually set the country of a user and thus deactivate the IP address lookup.
The expected format of the country variable is a two-character ISO 3166 country code.
We recommend calling the setCountry method right before the identifyUser method.
As an alternative to the setCountry method, you can also provide a country option when identifying a user.
_encatch.setCountry('in'); // ISO 3166 country code_encatch.identifyUser('user-123', {}, {
country: 'in'
});Theme
Set the theme for forms and surveys. Default is 'system'.
_encatch.setTheme('dark'); // 'light', 'dark', or 'system'
_encatch.setTheme('light');
_encatch.setTheme('system'); // Follows system preferenceWhen tracking runs
trackEvent and trackScreen do nothing until the SDK has established a device identifier (for example after startSession() or a successful identifyUser() that loads persisted identity). They also do nothing when init was called with isFullScreen: true.
Event Tracking
Track a custom event.
_encatch.trackEvent('button_clicked');
_encatch.trackEvent('purchase_completed');Screen Tracking
Track a screen view.
_encatch.trackScreen('Dashboard');
_encatch.trackScreen('Checkout');Session
Manually start a new session. Useful after user login to reset session timing.
The two skip flags behave differently. With no arguments, the SDK runs an immediate ping once, but does not send the initial automatic trackScreen for the current URL (URL change listeners still attach, so later navigations can be tracked). Pass skipImmediatePing: true to skip that first ping only. Pass skipImmediateTrackScreen: false to also send the initial trackScreen for the current URL.
_encatch.startSession();
// Also send an immediate trackScreen for the current URL (in addition to URL listeners)
_encatch.startSession({ skipImmediateTrackScreen: false });Prop
Type
Reset User
Reset the current user (logout). Reverts the SDK to anonymous mode.
_encatch.resetUser();Clear all
Clear all SDK state and stored identifiers, reverting to a brand-new visitor. Stops the ping interval and URL change listeners, clears localStorage and IndexedDB data written by the SDK, and resets in-memory identity.
showForm() and related form APIs still work after this call, but tracking does not run again until you call startSession() or identifyUser(). Use this for a “forget me” or consent-withdrawal flow.
_encatch.clearAll();Show Form
Show a specific form by ID.
_encatch.showForm('form-abc-123');
_encatch.showForm('form-abc-123', { reset: 'never' });
_encatch.showForm('form-abc-123', {
reset: 'always',
context: { plan: 'enterprise', trialEndsAt: new Date('2026-12-31') },
});Prop
Type
Show form options:
Prop
Type
Dismiss Form
Dismiss a form and report to the server. Closes the iframe if open and calls the dismiss-form endpoint.
// Dismiss a specific form configuration
_encatch.dismissForm('form-config-123');
// Dismiss whichever form iframe is currently visible
_encatch.dismissForm();Prop
Type
Prepopulate Response
Prepopulate a form response.
_encatch.addToResponse('question-1', 'Pre-filled answer');
_encatch.addToResponse('question-2', ['option-a', 'option-b']);
_encatch.addToResponse('nps-score', 9); // questionId can be a stable ID or a question slugProp
Type
Refine text (AI)
Call the AI text refinement endpoint for long-text answers. Returns a Promise that resolves with the API response (for example refinedText, or error / code on failure).
Typical use is with a custom form UI—for example when init is configured with onBeforeShowForm (see Initialization, Interceptor tab) so you render your own long-text field with an “enhance” action.
const result = await _encatch.refineText({
questionId: 'question-long-text-1',
feedbackConfigurationId: 'form-config-abc-123',
userText: 'Draft feedback paragraph…',
});
if (result.refinedText) {
console.log(result.refinedText);
}Prop
Type
Prop
Type
Submit form
Send a completed (or partial) form response to the Encatch API from your own UI. Use this when onBeforeShowForm returns false and you do not use the built-in iframe.
The shape below matches the published @encatch/web-sdk TypeScript types (SubmitFormRequest, FormDetails, QuestionResponse, QuestionAnswer).
_encatch.submitForm({
triggerType: 'manual',
formDetails: {
formConfigurationId: 'form-config-abc-123',
isPartialSubmit: false,
responseLanguageCode: 'en',
response: {
questions: [
{
questionId: 'nps-1',
type: 'nps',
answer: { nps: 9 },
},
],
},
context: { source: 'custom-ui' },
completionTimeInSeconds: 42,
visitedQuestionIds: ['nps-1'],
},
});Prop
Type
Prop
Type
Each QuestionResponse has questionId (required), optional type, optional answer (QuestionAnswer), and optional isOnPath (whether the question was on the respondent path).
QuestionAnswer fields depend on the question type; set the field that matches your question (only examples below):
| Field | Typical use |
|---|---|
nps | number |
csat | number |
starRating | number |
singleChoice | string |
singleChoiceOther | string |
multipleChoiceMultiple | string[] |
multipleChoiceMultipleOther | string |
nestedSelection | string[] |
shortAnswer | string |
longText | string |
Emit event
Emit a form lifecycle event to every subscriber registered with on(). The SDK adds timestamp automatically; your payload should omit it (same shape as EventPayload minus timestamp).
Use this with a custom UI when onBeforeShowForm returns false, so analytics and integrations still receive the same events as with the iframe form.
_encatch.emitEvent('form:show', {
formId: 'form-slug-or-id',
data: { source: 'custom-ui' },
});
_encatch.emitEvent('form:complete', {
formId: 'form-slug-or-id',
});Prop
Type
Event Subscription
Subscribe to all form events. The callback receives every form event with the event type and payload. Returns an unsubscribe function. Custom UIs can mirror iframe behavior by calling emitEvent with the same event names.
const unsubscribe = _encatch.on((eventType, payload) => {
console.log(`[Encatch] ${eventType}:`, payload);
});
// Later, to unsubscribe:
unsubscribe();| Event | Description |
|---|---|
form:show | Fired when a form is displayed |
form:started | Fired when a form is started |
form:submit | Fired when a form is submitted |
form:complete | Fired when a form is completed |
form:close | Fired when a form is closed |
form:dismissed | Fired when a form is dismissed |
form:error | Fired when an error occurs |
form:section:change | Fired when the user changes sections |
form:answered | Fired when a question is answered |
Event payload structure:
interface EventPayload {
formId?: string;
timestamp: number;
data?: Record<string, unknown>;
}Raising Issues
Github Issue Link: https://github.com/get-encatch/web-sdk
