Welcome to Encatch Docs

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-sdk

Pin 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:

OperationDescription
$setSet user attributes (overwrites existing values)
$setOnceSet user attributes only if they don't already exist
$incrementIncrement numeric user attributes
$decrementDecrement numeric user attributes
$unsetRemove 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 preference

When 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 slug

Prop

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):

FieldTypical use
npsnumber
csatnumber
starRatingnumber
singleChoicestring
singleChoiceOtherstring
multipleChoiceMultiplestring[]
multipleChoiceMultipleOtherstring
nestedSelectionstring[]
shortAnswerstring
longTextstring

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();
EventDescription
form:showFired when a form is displayed
form:startedFired when a form is started
form:submitFired when a form is submitted
form:completeFired when a form is completed
form:closeFired when a form is closed
form:dismissedFired when a form is dismissed
form:errorFired when an error occurs
form:section:changeFired when the user changes sections
form:answeredFired 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

How is this guide?