# JavaScript Web SDK (/docs/sdk-reference/web)




The Encatch Web SDK lets you collect in-app feedback and surveys on your website. Display forms in a built-in modal iframe, identify users, track pages and events, and submit responses to the Encatch backend.

***

## Overview [#overview]

* **Package:** [`@encatch/web-sdk`](https://www.npmjs.com/package/@encatch/web-sdk)
* **Version:** 1.3.0
* **Platforms:** Modern browsers (Chrome, Firefox, Safari, Edge)
* **Repository:** [github.com/get-encatch/web-sdk](https://github.com/get-encatch/web-sdk)

<Callout type="info" title="Prerequisites">
  1. **Publishable SDK key** — Create a key in [Publishable SDK Keys](/docs/settings/security/publishable-sdk-keys). Your site's domain must be listed under **Allowed Domains / Packages**.
  2. **Form ID** — Use the form slug or ID from the Encatch dashboard in `showForm()`.
</Callout>

***

## Installation [#installation]

<Tabs items="['npm', 'yarn', 'pnpm', 'CDN / Script Tag']" defaultIndex="0">
  <Tab value="npm">
    ```bash
    npm install @encatch/web-sdk
    ```
  </Tab>

  <Tab value="yarn">
    ```bash
    yarn add @encatch/web-sdk
    ```
  </Tab>

  <Tab value="pnpm">
    ```bash
    pnpm add @encatch/web-sdk
    ```
  </Tab>

  <Tab value="CDN / Script Tag">
    Pin the CDN version to the same `@encatch/web-sdk` version you use from npm.

    ```html
    <script src="https://cdn.jsdelivr.net/npm/@encatch/web-sdk@1.3.0/dist/encatch.iife.js"></script>
    ```
  </Tab>
</Tabs>

Call `init()` as early as possible in the page lifecycle. Commands issued before the remote implementation script loads are queued automatically.

***

## Quick Start [#quick-start]

### 1. Initialization [#1-initialization]

<Tabs items="['Basic usage', 'Configuration']" defaultIndex="0">
  <Tab value="Basic usage">
    Initialize the SDK with your publishable API key, start a session, and show a form.

    <Tabs items="['ES Modules', 'Script Tag']" defaultIndex="0">
      <Tab value="ES Modules">
        ```javascript
        import { _encatch } from '@encatch/web-sdk';

        _encatch.init('your-api-key');
        _encatch.startSession();
        _encatch.showForm('your-form-slug');
        ```
      </Tab>

      <Tab value="Script Tag">
        ```html
        <script src="https://cdn.jsdelivr.net/npm/@encatch/web-sdk@1.3.0/dist/encatch.iife.js"></script>
        <script>
          _encatch.init('your-api-key');
          _encatch.startSession();
          _encatch.showForm('your-form-slug');
        </script>
        ```
      </Tab>
    </Tabs>

    Only the first `init()` call runs — subsequent calls are ignored. After a successful `identifyUser()`, the SDK starts a session automatically; you do not need `startSession()` before identify.
  </Tab>

  <Tab value="Configuration">
    Pass an optional `config` object to customize SDK behavior:

    <Tabs items="['ES Modules', 'Script Tag']" defaultIndex="0">
      <Tab value="ES Modules">
        ```javascript
        import { _encatch } from '@encatch/web-sdk';

        _encatch.init('your-api-key', {
          theme: 'system',
          apiBaseUrl: 'https://app.encatch.com',
          onBeforeShowForm: async (payload) => {
            // Return false to prevent the built-in iframe from showing
            return true;
          },
        });
        ```
      </Tab>

      <Tab value="Script Tag">
        ```html
        <script>
          _encatch.init('your-api-key', {
            theme: 'system',
            apiBaseUrl: 'https://app.encatch.com',
            onBeforeShowForm: async (payload) => {
              return true;
            },
          });
        </script>
        ```
      </Tab>
    </Tabs>

    <TypeTable
      type="{
  apiBaseUrl: {
    description: 'Base URL for all API calls.',
    type: 'string',
    default: &#x22;'https://app.encatch.com'&#x22;,
    required: false
  },
  webHost: {
    description: 'Base URL for loading the remote SDK implementation script. Defaults to apiBaseUrl.',
    type: 'string',
    required: false
  },
  theme: {
    description: 'Form theme.',
    type: &#x22;'light' | 'dark' | 'system'&#x22;,
    default: &#x22;'system'&#x22;,
    required: false
  },
  onBeforeShowForm: {
    description: 'Interceptor called before any form is shown. Return false to skip the built-in iframe and render a custom UI instead.',
    type: '(payload) => boolean | Promise<boolean>',
    required: false
  }
}"
    />
  </Tab>
</Tabs>

### 2. Identify users [#2-identify-users]

Identify the current user. The `userName` is required (can be a username, email, or unique identifier). Traits and options are optional.

<Callout type="info" title="Username format">
  `userName` must be an **ASCII** identifier: **1–50 characters**, using only letters `A–Z` / `a–z`, digits `0–9`, and `.`, `_`, `@`, `-`. Spaces and non-English characters (Unicode, accented letters, emoji, etc.) are not supported. Use an email address, internal user ID, or ASCII username — for example `user@example.com` or `user_123`. To store a display name in another language, pass it as a trait instead (e.g. `$set: { display_name: '…' }`).
</Callout>

<Tabs items="['Simple', 'With traits', 'Multiple operations', 'Parameters', 'Secure identification']" defaultIndex="0">
  <Tab value="Simple">
    ```javascript
    _encatch.identifyUser('user@example.com');
    ```
  </Tab>

  <Tab value="With traits">
    ```javascript
    _encatch.identifyUser('user@example.com', {
      $set: { name: 'Alice', plan: 'team' },
    });
    ```
  </Tab>

  <Tab value="Multiple operations">
    ```javascript
    _encatch.identifyUser('user@example.com', {
      $set: { name: 'Alice', plan: 'team' },
      $setOnce: { firstSeen: new Date().toISOString() },
      $increment: { loginCount: 1 },
      $decrement: { credits: 5 },
      $unset: ['trialEndDate'],
    });
    ```
  </Tab>

  <Tab value="Parameters">
    <TypeTable
      type="{
  userName: {
    description: 'ASCII user identifier (1–50 chars: letters, digits, `.`, `_`, `@`, `-`). Email addresses and internal IDs work if they match this format.',
    type: 'string',
    required: true
  },
  traits: {
    description: 'User attributes with nested operations.',
    type: 'UserTraits',
    required: false
  },
  options: {
    description: 'Locale, country, and secure identification.',
    type: 'IdentifyOptions',
    required: false
  }
}"
    />

    **User traits** support the following 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                               |
  </Tab>

  <Tab value="Secure identification">
    <Callout type="warn" title="<strong>Recommended</strong>">
      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.
    </Callout>

    Pass a server-generated HMAC signature so Encatch can validate the request. `generatedDateTimeinUTC` must be **milliseconds since the Unix epoch** (for example `String(Date.now())` from your server). When your publishable key has a session timeout, use the same value in `HMAC-SHA256(userName + epochMs, secretKey)`. It is sent as the `X-User-Signature-Time` header and limits the signature's lifespan.

    ```javascript
    _encatch.identifyUser('user@example.com', undefined, {
      secure: {
        signature: 'your-hmac-signature',
        generatedDateTimeinUTC: '1741867200000', // ms since epoch (2025-03-13T12:00:00Z)
      },
    });
    ```
  </Tab>
</Tabs>

### 3. Show a form manually [#3-show-a-form-manually]

Show a specific form by slug or ID.

<Tabs items="['Example', 'Parameters', 'Options']" defaultIndex="0">
  <Tab value="Example">
    ```javascript
    _encatch.showForm('feedback-form');
    _encatch.showForm('feedback-form', { reset: 'always' });
    ```
  </Tab>

  <Tab value="Parameters">
    <TypeTable
      type="{
  formId: {
    description: 'The slug or ID of the form to display.',
    type: 'string',
    required: true
  },
  options: {
    description: 'Controls when form data is cleared.',
    type: 'ShowFormOptions',
    required: false
  }
}"
    />
  </Tab>

  <Tab value="Options">
    <TypeTable
      type="{
  reset: {
    description: 'When to clear form data.',
    type: &#x22;'always' | 'on-complete' | 'never'&#x22;,
    default: &#x22;'always'&#x22;,
    required: false
  },
  context: {
    description: 'Arbitrary key-value metadata attached to the form submission. Date values are serialized to ISO 8601 strings.',
    type: 'Record<string, ContextValue>',
    required: false
  }
}"
    />

    | Reset mode      | Behavior                                               |
    | --------------- | ------------------------------------------------------ |
    | `'always'`      | Reset pre-fill and response data on every form display |
    | `'on-complete'` | Reset only after the form is completed                 |
    | `'never'`       | Never reset response data                              |

    Pass caller context when showing a form:

    ```javascript
    _encatch.showForm('feedback-form', {
      reset: 'always',
      context: { plan: 'team', feature: 'checkout' },
    });
    ```

    The `context` object is exposed as `context.*` in [Logic jumps](/docs/feedback-management/form-builder/logic-jumps) Start conditions.
  </Tab>
</Tabs>

### Other actions [#other-actions]

<Accordions type="single">
  <Accordion title="Locale">
    Set the user's preferred language.

    ```javascript
    _encatch.setLocale('fr,en,es');
    ```
  </Accordion>

  <Accordion title="Country">
    Set the user's country.

    ```javascript
    _encatch.setCountry('FR'); // ISO 3166 country code
    ```
  </Accordion>

  <Accordion title="Theme">
    Set the theme for forms and surveys.

    ```javascript
    _encatch.setTheme('dark');
    _encatch.setTheme('light');
    _encatch.setTheme('system'); // Follows system preference
    ```
  </Accordion>

  <Accordion title="Track events">
    ```javascript
    _encatch.trackEvent('button_clicked');
    ```

    Requires a device id from `startSession()` or a successful `identifyUser()`.
  </Accordion>

  <Accordion title="Track screens">
    ```javascript
    _encatch.trackScreen('Dashboard');
    ```

    With an active session, SPA navigations (`pushState`, `replaceState`, `popstate`) also call `trackScreen` with the full page URL automatically.
  </Accordion>

  <Accordion title="Source tracking">
    Merge campaign parameters into the source tracking store. Values set here take precedence over URL query params on key collision. Web SDK only.

    ```javascript
    _encatch.addSourceTracking({
      utm_campaign: 'spring-sale',
    });
    _encatch.showForm('feedback-form');
    ```

    On each `showForm()`, the SDK merges the page URL query string with `addSourceTracking()` values. The server filters keys per form; filtered values are auto-injected into `submitForm` for custom UIs.
  </Accordion>

  <Accordion title="Listen to form events">
    Subscribe to form lifecycle events. Returns an unsubscribe function.

    <Tabs items="['Example', 'Event Types']" defaultIndex="0">
      <Tab value="Example">
        ```javascript
        const unsubscribe = _encatch.on((eventType, payload) => {
          console.log('Event:', eventType, payload.data);
        });
        // Later:
        unsubscribe();
        ```
      </Tab>

      <Tab value="Event Types">
        | Event                 | Description                                                                     |
        | --------------------- | ------------------------------------------------------------------------------- |
        | `form:show`           | Fired when a form is displayed                                                  |
        | `form:started`        | Fired when a user starts interacting                                            |
        | `form:submit`         | Fired when a form is submitted                                                  |
        | `form:complete`       | Fired when a form is fully completed                                            |
        | `form:close`          | Fired when a form is closed                                                     |
        | `form:dismissed`      | Fired when a form is dismissed without completion                               |
        | `form:error`          | Fired when an error occurs                                                      |
        | `form:section:change` | Fired when the visible section changes                                          |
        | `form:answered`       | Fired when a question is answered                                               |
        | `form:remindmelater`  | Fired when the user taps "Remind me later" (hides iframe only — no dismiss API) |
        | `form:ctaTriggered`   | Fired when a completion CTA is triggered on thank-you or exit screens           |
      </Tab>
    </Tabs>

    Handle completion CTAs via `form:ctaTriggered`. Configure actions in the form builder — see [Call to action](/docs/feedback-management/form-builder/call-to-action).

    ```javascript
    _encatch.on((eventType, payload) => {
      if (eventType !== 'form:ctaTriggered') return;

      const action = payload.data?.action;
      if (action === 'app_navigate') {
        const route = payload.data?.route;
        // Navigate in your app — the SDK closes the form automatically
        window.location.hash = route;
      }
    });
    ```

    For in-app navigation, the SDK closes the form after emitting the event and expects your app to perform navigation. For URL redirect actions, the SDK opens the URL and closes the form automatically.
  </Accordion>

  <Accordion title="Pre-fill responses">
    Call `addToResponse` before `showForm` to stage answers. `questionId` is the question UUID or slug. Pass the raw answer value — the form engine wraps it (pass `5` for a rating, not `{ rating: 5 }`). Staged values apply on the next `showForm()`, or immediately if the iframe is already open.

    ```javascript
    _encatch.addToResponse('email_question', 'user@example.com');
    _encatch.addToResponse('nps_question', 10);
    _encatch.addToResponse('choices', ['option1', 'option2']);
    _encatch.addToResponse('address_question', {
      addressLine1: '123 Main St',
      city: 'San Francisco',
      country: 'US',
    });
    _encatch.showForm('your-form-slug');
    ```

    You can test the same values in the form builder via [logic jumps](/docs/feedback-management/form-builder/logic-jumps#test-logic-jumps).

    `addToResponse` works for **22 of 27** question types. Three value shapes:

    * **Form builder** — option Value / data identifier from admin (not the Label)
    * **Fixed keys** — address and phone use Encatch property names (`city`, `countryCode`, …)
    * **Open text** — a single string

    ### Form builder (14 types) [#form-builder-14-types]

    | Question type             | Configured in form builder                                   | What to pass                                                       | Example                                      |
    | ------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------ | -------------------------------------------- |
    | Rating                    | `numberOfRatings` (3–10 in builder)                          | Number from `1` to `numberOfRatings`                               | `5`                                          |
    | CSAT (Rating)             | Scale size: 2, 3, 4, or 5 pt                                 | Number from `1` to scale size                                      | `5`                                          |
    | NPS                       | Fixed 0–10 scale                                             | Number from `0` to `10`                                            | `10`                                         |
    | Opinion scale             | `startValue` (0 or 1) and `steps` (5–11)                     | Number from `startValue` to `startValue + steps - 1`               | `10`                                         |
    | Single choice             | Options (value + label)                                      | One option **value** string                                        | `"option1"`                                  |
    | Yes / No                  | `yesLabel` / `noLabel` in UI only                            | `true` (Yes) or `false` (No) — not option value strings            | `true`                                       |
    | Nested selection          | Nested options tree (value + label per level)                | Array of option **value**s along the path                          | `["parent1", "child1"]`                      |
    | Picture choice            | Options (value + label, optional image)                      | Array of option **value**s (one element when single-select)        | `["option-1"]`                               |
    | Multiple choice           | Options (value + label)                                      | Array of selected option **value**s                                | `["option1", "option2"]`                     |
    | Consent                   | Checkbox label in UI only                                    | `true` (agreed) or `false` (not agreed) — not option value strings | `true`                                       |
    | Ranking                   | Options (value + label)                                      | Array of option **value**s in rank order (index `0` = rank 1)      | `["option-1", "option-2", "option-3"]`       |
    | Rating matrix             | Statements + scale points (label + data identifier per item) | Object: statement **value** → scale point **value**                | `{ statement1: 4, statement2: 5 }`           |
    | Matrix (single per row)   | Rows and columns (label + data identifier per item)          | Object: row **value** → column **value**                           | `{ row1: "col1", row2: "col2" }`             |
    | Matrix (multiple per row) | Rows and columns (label + data identifier per item)          | Object: row **value** → array of column **value**s                 | `{ row1: ["col1"], row2: ["col1", "col2"] }` |

    Pass **Value** or **Data identifier** from admin — not the Label. Multiple choice, picture choice, and ranking take an array. Yes/No and Consent take `true`/`false`. Other option: `"$Other"` (Other free-text cannot be prefilled alone).

    ### Fixed keys (2 types) [#fixed-keys-2-types]

    Same property names on every form. The builder only changes labels and which fields are shown.

    | Question type | Predefined keys                                                                  | Example                                                                                                           |
    | ------------- | -------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
    | Phone number  | `countryCode`, `number`, `e164`                                                  | `{ countryCode: "+1", number: "5551234567", e164: "+15551234567" }`                                               |
    | Address       | `addressLine1`, `addressLine2`, `city`, `stateProvince`, `postalCode`, `country` | `{ addressLine1: "123 Main St", city: "San Francisco", stateProvince: "CA", postalCode: "94105", country: "US" }` |

    ### Open text (6 types) [#open-text-6-types]

    | Question type | What to pass              | Example                 |
    | ------------- | ------------------------- | ----------------------- |
    | Short answer  | Any text string           | `"Sample short answer"` |
    | Long answer   | Any text string           | `"Sample long answer"`  |
    | Date          | ISO 8601 date string      | `"2024-06-15"`          |
    | Number        | Numeric value as a string | `"42"`                  |
    | Email         | Email address string      | `"user@example.com"`    |
    | Website       | URL string                | `"https://example.com"` |

    ### Not supported (5 types) [#not-supported-5-types]

    These question types do **not** support `addToResponse`:

    | Question type         | Reason                                                                     |
    | --------------------- | -------------------------------------------------------------------------- |
    | Signature             | Requires the respondent to type, draw, or upload through the form UI       |
    | File upload           | Files must be uploaded through the form's file picker                      |
    | Video / audio / photo | Requires recording, camera capture, or in-form upload                      |
    | Scheduler             | Bookings are created through the embedded Calendly or Google Calendar flow |
    | Q\&A with AI          | Answers are generated live from the AI knowledge base during the session   |

    Panels (`welcome`, `thank_you`, `message_panel`, `exit_form`) have no answer. `annotation` and `payments_upi` are not in the 27-type set.
  </Accordion>

  <Accordion title="Dismiss form">
    Dismiss the currently displayed form.

    ```javascript
    _encatch.dismissForm();
    // Or dismiss a specific form configuration:
    _encatch.dismissForm('form-config-id');
    ```
  </Accordion>

  <Accordion title="Form interceptor">
    Use `onBeforeShowForm` in `init()` config to conditionally block forms from showing or render a custom UI instead.

    ```javascript
    _encatch.init('your-api-key', {
      onBeforeShowForm: async (payload) => {
        // Inspect payload.formId, payload.formConfig, payload.triggerType, etc.
        if (payload.triggerType === 'automatic' && someCondition) {
          return false; // Block this form or use custom UI
        }
        return true; // Allow built-in iframe
      },
    });
    ```

    **`onBeforeShowForm` payload:**

    <TypeTable
      type="{
  formId: { description: 'Form slug or ID', type: 'string', required: true },
  formConfig: { description: 'Show-form API response', type: 'object', required: true },
  resetMode: { description: &#x22;'always' | 'on-complete' | 'never'&#x22;, type: 'string', required: true },
  triggerType: { description: &#x22;'manual' | 'automatic'&#x22;, type: 'string', required: true },
  prefillResponses: { description: 'Values from addToResponse()', type: 'object', required: true },
  locale: { description: 'Active locale', type: 'string', required: false },
  theme: { description: 'Active theme', type: 'string', required: false },
  context: { description: 'Serialized showForm context', type: 'object', required: false }
}"
    />
  </Accordion>

  <Accordion title="Session">
    Start and control the session lifecycle manually:

    <Tabs items="['Start', 'Pause / Resume', 'Stop', 'Reset user', 'Clear all']" defaultIndex="0">
      <Tab value="Start">
        ```javascript
        _encatch.startSession();

        // Skip the immediate ping or screen re-track on start:
        _encatch.startSession({
          skipImmediatePing: true,
          skipImmediateTrackScreen: true,
        });
        ```

        Each `startSession()` generates a new session id (24-hour rolling expiry).
      </Tab>

      <Tab value="Pause / Resume">
        ```javascript
        // Temporarily stop the background ping (not persisted)
        _encatch.pauseSession();

        // Resume the ping interval after pauseSession()
        _encatch.resumeSession();
        ```
      </Tab>

      <Tab value="Stop">
        ```javascript
        // Fully suspend SDK activity — stops ping, URL listeners, and dismisses open forms.
        // Persists across page reloads. Re-enable with startSession().
        _encatch.stopSession();
        ```
      </Tab>

      <Tab value="Reset user">
        Reset the current user identity and clear persisted identity data. Reverts the SDK to anonymous mode. User identity is preserved across `stopSession()` — use `resetUser()` after logout.

        ```javascript
        _encatch.resetUser();
        ```
      </Tab>

      <Tab value="Clear all">
        Wipes **all** persisted SDK data and resets in-memory state. Stronger than `resetUser()` — also clears session-stopped state and device preferences. Tracking stops until `startSession()` or `identifyUser()` is called again.

        ```javascript
        _encatch.clearAll();
        ```
      </Tab>
    </Tabs>

    The SDK sends a background ping every 30 seconds (configurable via server response) to maintain engagement sessions and check for triggered forms. Ping is suppressed while a form is visible.

    <Callout type="info" title="Reload behavior">
      If a prior session or user exists in browser storage, the SDK restores identifiers on load and may restart the session unless it was explicitly stopped.
    </Callout>
  </Accordion>
</Accordions>

***

### Full-screen / Inline mode [#full-screen--inline-mode]

Not available at the moment.

### Build Your Own Form UX & UI [#build-your-own-form-ux--ui]

If your feedback flow uses a **fixed, predictable question set** — the same fields and workflow every time — you can build the form with your own HTML/CSS/JS and submit responses through the SDK. That keeps typography, spacing, colors, and interaction patterns aligned with the rest of your site, so the survey feels like part of your app rather than an embedded iframe.

Example coming soon.

***

### Content Security Policy [#content-security-policy]

If your site uses CSP headers, whitelist Encatch for SDK loading, HTTP API calls, and the form iframe. Add the CDN host only when you install through the script tag.

```http
Content-Security-Policy:
  script-src 'self' https://app.encatch.com https://cdn.jsdelivr.net;
  connect-src 'self' https://app.encatch.com; /* fetch/XHR API calls */
  frame-src 'self' https://app.encatch.com;
```

The form's CSS loads inside the Encatch iframe. If your CSP blocks inline styles and the modal wrapper is not positioned correctly, allow inline styles in `style-src` for the host page.

If you configure a custom `webHost`, whitelist that host instead of `https://app.encatch.com` for script loading.

***

<Accordions type="single">
  <Accordion title="API quick reference">
    | Method                                      | Description                                 |
    | ------------------------------------------- | ------------------------------------------- |
    | `init(apiKey, config?)`                     | Initialize the SDK                          |
    | `identifyUser(userName, traits?, options?)` | Identify a user                             |
    | `setLocale(locale)`                         | Set locale                                  |
    | `setCountry(country)`                       | Set country (ISO 3166)                      |
    | `setTheme(theme)`                           | Set form theme                              |
    | `trackEvent(eventName)`                     | Track a custom event                        |
    | `trackScreen(screenName)`                   | Track screen navigation                     |
    | `showForm(formId, options?)`                | Show a form in the modal iframe             |
    | `dismissForm(formConfigurationId?)`         | Dismiss the current form                    |
    | `addToResponse(questionId, value)`          | Pre-fill a question answer (22 of 27 types) |
    | `addSourceTracking(values)`                 | Merge source tracking params (web only)     |
    | `startSession(options?)`                    | Start a new session                         |
    | `pauseSession()`                            | Pause background ping                       |
    | `resumeSession()`                           | Resume background ping                      |
    | `stopSession()`                             | Suspend SDK activity                        |
    | `resetUser()`                               | Reset user identity                         |
    | `clearAll()`                                | Wipe all persisted SDK data                 |
    | `on(callback)`                              | Subscribe to lifecycle events               |
    | `submitForm(params)`                        | Submit a custom form                        |
    | `emitEvent(eventType, payload)`             | Emit a lifecycle event (custom UI)          |
    | `refineText(params)`                        | AI text refinement                          |
    | `uploadFile(params)`                        | Upload a file (custom forms)                |
    | `qnaWithAi(params)`                         | Q\&A with AI                                |
    | `streamQnaWithAi(params, callbacks)`        | Streaming Q\&A with AI                      |
  </Accordion>
</Accordions>

## Support [#support]

* **npm:** [@encatch/web-sdk](https://www.npmjs.com/package/@encatch/web-sdk)
* **Issues:** [github.com/get-encatch/web-sdk/issues](https://github.com/get-encatch/web-sdk/issues)
