# General FAQ (/docs/general-faq) ### General FAQ [#general-faq]

The organization owner is the user who has created the organization. To change the organization owner, you need to contact us at [support@encatch.com](mailto:support@encatch.com) .

To delete the organization, you need to contact us at [support@encatch.com](mailto:support@encatch.com) .

You can add a new member to the organization by going to the **organization** menu in your dashboard and clicking the add member button. You can add a new member to the organization by clicking the add member button.

AI API calls are the calls made to the AI API endpoints when using the application.

Data pipeline triggers are the triggers that are used to trigger the data pipeline.

#### Other documents and questions: [#other-documents-and-questions] 1. Billing FAQ, click [here](/docs/billing/billing-faq) for more details. 2. Rate Limiting, click [here](/docs/sandbox-limits/rate-limits) for more details. 3. Sandbox Environment, click [here](/docs/sandbox-limits/sandbox-environment) for more details. 4. Privacy Policy, click [here](/docs/legal/privacy-policy) for more details. 5. Terms of Service, click [here](/docs/legal/terms-of-service) for more details. # Get Started Checklist (/docs/get-started-onboarding) New projects include a **Get Started** checklist that takes you from an empty project to a working feedback loop. Progress is saved as you complete each step, so you can leave the setup and return later. ## The guided path [#the-guided-path] 1. **Create your first form** — Start with a template, Encatch AI, or a blank form, then customize the questions and appearance. 2. **Install an SDK** — Connect the web SDK or one of the mobile SDKs to the application where you want to collect in-app feedback. 3. **Collect a response** — Publish the form, configure its audience and trigger, and submit a test response from the connected application. 4. **Open Overview** — Review the project-level summary after feedback starts arriving. You can also distribute a form through a [shareable link](/docs/shareable-feedback/feedback-links) while the in-app SDK setup is in progress. ## Continue with the right guide [#continue-with-the-right-guide] * [Create a feedback form](/docs/feedback-management/form-creation-methods/create-a-feedback) * [Configure targeting and triggers](/docs/feedback-management/targeting-and-triggers) * [Install the JavaScript Web SDK](/docs/sdk-reference/web) * [Choose a mobile or native SDK](/docs/sdk-reference/mobile-sdk) * [Understand the feedback dashboard](/docs/feedback-management/reports-and-export/feedback-dashboard) # Welcome to encatch Documentation (/docs) ## Introduction [#introduction] encatch (en-catch) is a feedback platform that allows you to collect feedback from your users. You can seamlessly integrate it into your app or website using our SDKs. If this is a new project, begin with the [Get Started checklist](/docs/get-started-onboarding) to create a form, connect an SDK, collect a response, and open Overview. ## What is Next? [#what-is-next] # Identify User (/docs/api-reference/identify-user) Create or update a user and sync traits from your backend. This is the server-to-server counterpart of SDK `identifyUser` — same identify pipeline, **admin key only**, and no in-app form payload. Use it when traits live in backend systems (plan, company, billing) rather than in the client. For keys, auth, and rate limits, see [Admin API Reference](/docs/api-reference). ## Authentication [#authentication] Admin (secret) API key Request body format Publishable SDK keys receive `403` (`publishable API keys cannot call /v2/admin routes`). Keep admin API keys on your server. Never ship them in client code. ## Request body [#request-body] Maximum body size: **100 KB** (413 if larger). Unique user identifier — email, internal id, or ASCII username. Empty or missing returns 401. Prefer 1–50 characters: letters, digits, and . \_ @ -. Store display names with spaces or non-ASCII characters as traits, not as the user name. Trait operations to apply to this user. Set or overwrite traits. Set a trait only if it is not already set. Increment numeric traits. Decrement numeric traits. Trait keys to remove. Optional device metadata. For admin identify, country code is the useful field. Invalid country codes return 400. ISO 3166-1 alpha-2. Invalid value returns 400 (invalid country passed). IANA timezone Device operating system OS version Client SDK version Application identifier Application version Device locale, e.g. en-US User language, e.g. en Device identifier Current URL or screen name Client surface Viewport class Color scheme Browser name Browser version SDK HMAC field. Not required for admin identify. ### Trait limits [#trait-limits] | Limit | Value | | ------------------------- | -------------- | | Trait key length | 100 characters | | Trait string value length | 500 characters | Exceeding either limit returns `400`. ### Trait policy [#trait-policy] * **New traits** — Admin identify **registers unknown slugs** even when the project has client-created traits turned off. * **Disabled traits** — Slugs marked disabled are still dropped. * **Usage cap** — The unique-traits limit still applies. New slugs over the cap are stripped. * **PII allow-list** — Known device and PII fields are still filtered. Custom traits pass through. Same trait operations as [SDK identify](/docs/sdk-reference/web#identify--track-users). Most device-info fields are SDK-oriented — send country code when you know the user's country. Admin identify does **not** GeoIP-fill country from the caller’s server IP. ## Examples [#examples] ## Success response [#success-response] Status. ok on success. UUID for this organization, project, and user name. Available immediately. Trait writes are applied asynchronously after this response. Admin identify does **not** return SDK-only fields (`pingAgainIn`, `pingOnNextPageVisit`, `nextFeedbackId`, `onPageDelay`). ## Errors [#errors] These are specific to Identify User. Shared Admin API errors — invalid API key, publishable key (`403`), rate limits (`429`), and `500` — are on [Admin API Reference](/docs/api-reference#errors). | Status | When | | ------ | -------------------------------------------------------------------------------------------- | | `400` | Invalid `$countryCode`; trait key longer than 100 characters or string value longer than 500 | | `400` | Project MAU quota exhausted (`Monthly active users limit reached for your plan`) | | `401` | Missing or empty `userName` (`userName not found`) | | `413` | Request body larger than 100 KB | ## Admin vs SDK identify [#admin-vs-sdk-identify] | | Admin `POST /v2/admin/identify-user` | SDK `POST /v2/encatch/identify-user` | | -------------------- | ----------------------------------------------------- | ------------------------------------ | | Key | Admin / secret (`X-Api-Key`) | Publishable SDK key | | Form to show | Never | May return `nextFeedbackId` | | New traits | Registered even if client-created traits are disabled | Honors `allowNewTraitsFromClient` | | GeoIP from caller IP | No | Yes | ## Related [#related] * [Admin API Reference](/docs/api-reference) — auth, base URL, sandbox and live rate limits * [Identify & track users (Web SDK)](/docs/sdk-reference/web#identify--track-users) * [User Traits](/docs/settings/user-data/user-traits) # Admin API Reference (/docs/api-reference) The Admin API is for **server-to-server** calls from your backend. Use it when user properties live in your systems (billing, CRM, auth) and you want to sync them to Encatch without sending them through a client SDK. Create and manage admin API keys under **Settings** in the dashboard. Admin keys authorize admin routes only — they cannot call [publishable SDK](/docs/settings/security/publishable-sdk-keys) endpoints. Admin API keys are secret credentials. Store them on your server. Never embed them in browsers, mobile apps, or public repositories. ## Base URL [#base-url] All Admin API paths are under `/v2/admin`. ## Authentication [#authentication] Every request must include your admin API key. Admin (secret) API key for the project Publishable SDK keys are rejected on admin routes (403). Admin keys are rejected on SDK routes (403). ## Endpoints [#endpoints] ## Rate limits [#rate-limits] Admin API traffic is limited **per minute** on two independent scopes. A request counts against **both**. If either bucket is exhausted, the API returns 429 Too Many Requests. Limits depend on whether the project is **Sandbox** or **Live** (production). That choice is fixed when the project is created — see [Sandbox Environment](/docs/sandbox-limits/sandbox-environment). ### Sandbox projects [#sandbox-projects] Shared by every admin key on the project Cap for a single admin key A single admin key in sandbox can send **50 requests/minute**. All keys on the same sandbox project share a **100 requests/minute** project cap. ### Live projects [#live-projects] Shared by every admin key on the project Cap for a single admin key A single admin key in a live project can send **4,000 requests/minute**. All keys on the same live project share a **10,000 requests/minute** project cap. The tighter remaining quota wins. In sandbox, one key hits the **50/min** key limit before the **100/min** project limit. In live, one key hits **4,000/min** before the project hits **10,000/min**. These Admin API limits are separate from [SDK rate limits](/docs/sandbox-limits/rate-limits), which apply to publishable-key traffic from the Web and Mobile SDKs. ### Rate limit headers [#rate-limit-headers] Maximum requests in the current window Requests left in the current window When the window resets (Unix timestamp, seconds) ### Handling 429 [#handling-429] 1. Wait until X-RateLimit-Reset. 2. Retry with exponential backoff. 3. Spread traffic across keys only if you are still under the **project** cap. ## Errors [#errors] These apply to every Admin API route. Gateway rejections are `{ "error": "…" }`. Unexpected Core API failures return a sanitized 500. | Status | When | | ------ | ---------------------------------------------------------------- | | `401` | Missing `X-Api-Key` (`api key is required`) | | `401` | Unknown, inactive, expired, or malformed key (`invalid api key`) | | `403` | Publishable SDK key used on an admin route | | `429` | [Rate limit](#rate-limits) exceeded | | `500` | Unexpected server error. Internal details are not returned | Route-specific errors (validation, userName, MAU) are documented on each endpoint — start with [Identify User](/docs/api-reference/identify-user#errors). # Billing FAQ (/docs/billing/billing-faq) For how MAU, responses, page views, tracked events, and other limits are measured, see [Usage Limits](/docs/billing/usage-limits).

Yes — every new account gets a free 1-month limited Growth trial so you can explore all features before committing. No credit card required. After the trial your account moves to the Free plan unless you choose to upgrade.

You can subscribe on a **monthly** or **annual** basis.

**Monthly plans** are recurring payments billed each month.

**Annual plans** are paid upfront in one payment for the year — effectively 12 months for the price of 10, a ~16% saving compared to paying monthly.

We accept all major credit cards and popular payment providers. For enterprise plans, we also support invoicing and bank transfers.

Yes. We use Dodo Payments as our Merchant of Record (MOR), which means all payment processing, billing compliance, and card data handling is managed by them — we never see or store your card details. Dodo Payments is PCI DSS compliant and handles transactions securely on our behalf.

You can check your usage and plan limits by going to the **billing** menu in the left sidebar of your dashboard. For what counts toward each limit and what happens when you reach them, see [Usage Limits](/docs/billing/usage-limits) .

We never overcharge for overages — if usage exceeds your plan limits, we absorb that burden rather than passing surprise charges to you. Our systems are designed to stop over-usage in near real time, with only a seconds-to-minutes delay in usage sync. You can monitor your current usage at any time from the billing dashboard. If you're regularly hitting your limits, you can scale them up directly from the billing screen without changing your plan.

For how each limit is measured and what happens at the cap, see [Usage Limits](/docs/billing/usage-limits) .

A response is one partial or fully submitted form submission from an in-app feedback form or survey link tied to your workspace. Impressions or dismissals without any submission do not count toward your monthly response limit.

See [Usage Limits](/docs/billing/usage-limits) for Free vs paid response limits and fair usage on paid plans.

Some limits (like AI credits or destinations) can be increased from your billing screen without switching plans. If you regularly exceed self-serve limits or need custom deployment, talk to Enterprise sales.

Yes. Changes between paid plans — whether an upgrade or a downgrade — are applied **immediately** after you confirm the change. Your new limits and features start right away, and your billing cycle resets to the date of the paid plan change.

If a paid-to-paid change leaves unused value from your previous paid plan, that surplus is stored as internal credit with Dodo Payments. This credit is not paid back to your card, bank account, or other payment channel. It can be applied to eligible future Encatch charges processed through Dodo Payments, including higher-value plan changes and subsequent subscription renewals.

If you are on a paid plan and want to move to the Free plan, that change takes effect only after your current paid billing cycle is completed. You keep your paid-plan limits and features until the end of that cycle.

You can change plans from the **billing** menu in the left sidebar of your dashboard.

Yes. Upgrades are instant — higher limits and features apply as soon as you confirm the change. You can move from Free to Team or Growth whenever you're ready, and talk to us when you need Enterprise.

For paid-plan upgrades, any available internal credit stored with Dodo Payments is applied to eligible charges first. If the new plan costs more than your available credit balance, the remaining amount is charged through checkout. The billing cycle resets to the date of the paid plan change.

Your upgrade is effective **immediately** — new limits and features apply as soon as you confirm the change.

When an upgrade starts or changes a paid subscription, the billing cycle starts from the upgrade date.

Downgrades between paid plans are effective **immediately** . Your new paid-plan limits and features apply as soon as you confirm the change, and your billing cycle resets to the downgrade date.

If the change leaves unused value from your previous paid plan, the surplus is stored as internal credit with Dodo Payments. This credit can be applied to eligible future Encatch charges processed through Dodo Payments, including higher-value plan changes and subsequent subscription renewals.

A move from a paid plan to the Free plan is different: it takes effect only after your current paid billing cycle is completed. You keep your paid-plan limits and features until that cycle ends.

You can upgrade or downgrade your plan from the **billing** menu in the left sidebar of your dashboard. Before confirming a paid-plan change, the billing screen shows the new plan, any internal credit applied through Dodo Payments, any amount due, and the new billing-cycle date.

When a paid-plan change creates surplus value, that amount is stored as internal credit with Dodo Payments. It can be applied to eligible future Encatch charges processed through Dodo Payments, such as higher-value paid plan changes and subsequent subscription renewals.

Dodo Payments internal credit is not a cash refund and is not paid back to your card, bank account, payment provider balance, or any other customer payment channel. It remains available as internal credit for eligible future Encatch charges, subject to the applicable Billing Policy, checkout flow, or Enterprise Agreement.

When you change from one paid plan to another paid plan, the billing cycle resets to the date of the plan change. Future subscription renewals follow that new cycle date.

Moving from a paid plan to the Free plan does not reset the paid cycle mid-period. The Free plan starts after the current paid billing cycle is completed.

We don't offer cash refunds unless required by law or expressly stated in an applicable Enterprise Agreement. Internal credits from paid-plan changes are stored with Dodo Payments for eligible future Encatch charges, not refunds or payouts to your payment method.

If you experience issues, reach out to our support team and we'll make it right.

Yes. You can cancel at any time from the billing page in your dashboard by clicking **Cancel subscription** . Canceling schedules your move to the Free plan at the end of your current paid billing cycle. You keep access to your current paid plan until that cycle ends, and scheduled subscription payments after cancellation are not deducted.

If you don't renew, your account is **automatically moved to the Free plan** after the paid billing cycle is completed, and you lose access to paid-plan features. Usage and limits then follow the Free plan — see [Usage Limits](/docs/billing/usage-limits) for details.

No. Enterprise includes private cloud or your own cloud hosting for organizations that need it, but every deal is tailored. If you need SSO, audit logs, and compliance controls on our managed stack, we can shape that too — talk to Enterprise sales about the right deployment model.

*** ## Related [#related] * [Usage Limits](/docs/billing/usage-limits) — MAU, responses, page views, tracked events, AI credits, and fair usage * [Plans & Pricing](/pricing) — Compare plans and features # Usage Limits (/docs/billing/usage-limits) This page explains how Encatch measures usage, what counts toward your limits, and what happens when you reach them. **How limits are scoped:** **MAU** is counted per **project** — the same person active in two projects counts as **2 MAU**. All other limits — **tracked events**, **page views**, **feedback responses**, and **AI credits** — are pooled at the **organization (account) level** across all projects in your workspace. **Sandbox projects** do not count toward the plan limits on this page. Usage in sandbox is measured separately — see [Sandbox Environment](/docs/sandbox-limits/sandbox-environment). These limits scale with your plan and are in place to prevent abuse, keep the platform reliable for all customers, and ensure pricing stays proportional to the value you get from Encatch. **Billing-cycle note:** Limits measured per billing cycle reset on your billing-cycle date. When you change from one paid plan to another paid plan, your billing cycle resets to the date of that plan change. MAU is different — it stays a rolling 30-day metric and does not reset with the billing cycle. *** ## Monthly Active Users (MAU) [#monthly-active-users-mau] **Monthly Active Users (MAU)** is how Encatch measures how many unique users engage with your feedback setup. It drives your plan limits and helps you understand your usage at a glance. MAU is counted **per project** — a user is unique within each project, not across your entire organization. The same person active in Project A and Project B counts as **2 MAU** toward your plan limit. MAU is based on a **rolling 30-day window** — the count always reflects unique users with meaningful activity in the past 30 days, not a fixed calendar month or billing period. A user counts toward your MAU when they do any of the following within a rolling 30-day period: * **Respond to a feedback form** — They partially or fully submit a response through any Encatch form (in-app or survey link) * **Are identified through the SDK** — You identify them in your app (e.g., when a user logs in) * **Trigger a tracked event** — They perform an action you record with **`trackEvent()`** through the SDK *(Growth plan and above)* * **Are ingested via the API** — You create or update a user profile through Encatch API calls (e.g., from your backend or a third-party integration) Each **unique user per project** is counted once within the rolling window, no matter how often they do these things. If someone submits 10 feedback forms in the same project, they still count as 1 MAU for that project. Passive events like form impressions or dismissals without any submission do **not** count toward MAU. For most in-app setups, MAU closely aligns with the number of users who logged into your product in the past 30 days. When you embed Encatch on a public website **without identifying users**, MAU works differently: A visitor counts toward MAU when **any** of the following occurs within the rolling 30-day window: * They **partially or fully submit** a feedback form * **Allow event tracking for visitors** is enabled in **Settings → User Data → Tracked Events** *(Growth plan and above)*, and the visitor triggers a **`trackEvent()`** call Passive traffic — pageviews, form impressions, or dismissals without a submission — does **not** count toward MAU unless a tracked event is recorded as above *(requires Growth plan and above)*. Anonymous page traffic is measured separately under your **page views** limit (see below). Unique anonymous visitors are recognized via a **browser cookie**, or in **cookieless mode** via a combination of **IP address and user agent**. One visitor can interact with multiple forms or events and still counts as **1 MAU** for the rolling window. If you run a single anonymous form and visitor event tracking is disabled, your MAU number will usually be close to the number of users who started or completed that form in the past 30 days. If you send user data to Encatch from external sources — your own backend, webhooks, or third-party tools — any user for whom we receive data within the rolling 30-day window is counted toward MAU. This includes: * User profiles created or updated via the **Encatch API** * User traits or events synced from integrations you connect to your workspace The same rolling-window and uniqueness rules apply: each user is counted once per 30 days, regardless of how many API calls or sync events they generate. MAU is a **gliding metric**: * It always represents activity from the **past 30 days** * It is updated every few minutes in your billing dashboard * It does **not** reset to zero when a new billing cycle or calendar month starts As user activity ages beyond 30 days, those users naturally drop out of the count — even mid-cycle. Your plan limit stays the same; only the measured usage window moves forward continuously. MAU is the only usage limit scoped to the **project level**. Users are unique **within each project**, not across your organization. The same person active in two different projects is counted as **two MAU** — for example, a user in Project A and Project B contributes **2 MAU** toward your plan limit. All other limits on this page — tracked events, page views, feedback responses, and AI credits — are pooled at the **organization (account) level** across all projects. There are no separate MAU categories — all users who respond, are identified, trigger events, or are ingested via the API count toward your plan’s MAU limit. When you reach your MAU limit: * **New users** who haven't been counted yet won't see or trigger feedback forms until capacity opens up — either because older users roll off the 30-day window or because you raise your limit. * Users already counted in the current rolling window can keep interacting as usual. * You won't be charged overage — access is simply limited until usage falls back within your plan or you upgrade. * To grow beyond your limit, you can upgrade your plan from the billing screen in your admin console. **Plan ahead:** If you expect a traffic spike, consider scaling your MAU limit in advance so new users can still access your feedback forms. *** ## Tracked Events [#tracked-events] **Tracked events** are behavioral signals you send through the SDK (using `trackEvent()`) — such as `purchase_completed`, `pricing_page_scrolled`, or `feature_used`. They power behavior-based segmentation, targeting, and **automatic form triggers based on events** (e.g. show a survey after `purchase_completed`). **Event tracking is available on the Growth plan and above** — it is not included on Free or Team. Upgrade to Growth to send `trackEvent()` calls, use behavior-based segments, and trigger forms on tracked events. Tracked events are counted at the **organization (account) level** — usage from all projects in your workspace shares one allowance. Event tracking is included on the **Growth plan and above** only. Free and Team plans do not include tracked events. On **Growth**, your plan includes a **tracked events limit** equal to **20× your MAU plan limit** — a fixed allowance tied to the MAU tier you select. Unlike MAU, this is a **plan limit** measured per billing cycle, not a rolling 30-day window. For example, a **1,000 MAU** plan includes **20,000** tracked events, a **10,000 MAU** plan includes **200,000**, and a **50,000 MAU** plan includes **1,000,000** per billing cycle. Form responses and form lifecycle signals — such as feedback shown, dismissed, started, or submitted — do **not** count toward the tracked events limit. Submissions are measured under **Feedback Responses** instead. Tracked events are a **separate limit from MAU and responses**. Hitting your MAU cap or responses fair usage cap does not automatically mean you have hit your tracked events limit, and vice versa. When you reach your tracked events limit: * **New tracked events** are not ingested until the next billing cycle, until you upgrade your plan, or until support adds more units to your account. * Existing data and features already built on tracked events continue to work for users and events already recorded. * You won't be charged overage — ingestion is paused until your allowance resets, support adds more units, or you upgrade. If you need more tracked events, choose the option that fits your situation: * **Temporary spike this cycle** — Contact our support team to request additional tracked event units for the current billing cycle. * **Regular, ongoing need** — Upgrade to **Growth** or a higher MAU tier on Growth. Because tracked events scale at **20× MAU**, a larger plan raises both limits together. **Plan ahead:** For a one-off rollout or short-term spike, contact support for additional units before usage peaks. If you consistently track more events every cycle, upgrading your plan is usually the better long-term fit. *** ## Page Views [#page-views] **Page views** measure anonymous traffic on public websites where the Encatch SDK is installed **without identifying users**. Counting begins after you call **`startSession()`** — each subsequent page load or navigation the SDK records counts toward your limit. Page views are the companion metric to MAU for anonymous setups. Page views are counted at the **organization (account) level** — usage from all projects in your workspace shares one allowance. Page views apply only to **unidentified (anonymous) visitors**: * After you call **`startSession()`**, each page load or navigation the SDK records for an anonymous session counts toward your page views limit * **Identified users are not counted toward page views** — once a user is identified through the SDK, navigation and behavior are measured through **MAU** and **tracked events** instead Your plan includes a **page views limit** equal to **20× your MAU plan limit** — a fixed allowance tied to the MAU tier you select. Unlike MAU, this is a **plan limit** measured per billing cycle, not a rolling 30-day window. For example, a **1,000 MAU** plan includes **20,000** page views, a **10,000 MAU** plan includes **200,000**, and a **50,000 MAU** plan includes **1,000,000** per billing cycle. Each anonymous page view — such as an initial load or SPA navigation tracked via `trackScreen()` after **`startSession()`** — counts as **one page view**. Form impressions, dismissals, and submissions do **not** count toward this limit. Page views are **separate from MAU and tracked events**. High anonymous traffic can consume page views without affecting how identified users are measured. When you reach your page views limit: * **Auto tracking stops** for anonymous visitors — the SDK stops sending **`trackScreen()`** updates and **ping** requests that check for eligible forms until your allowance resets, you upgrade, or support adds more units. * **New page views** are not ingested for the rest of the billing cycle (unless capacity is restored as above). * **Responses and data already collected** remain available in your dashboard, reports, and destinations. * You won't be charged overage — tracking and ingestion resume once capacity is available again. If you need more page views, choose the option that fits your situation: * **Temporary spike this cycle** — Contact our support team to request additional page view units as an add-on for the current billing cycle. * **Regular, ongoing need** — Upgrade your plan to a higher MAU tier. Because page views scale at **20× MAU**, a larger plan raises both limits together. **Plan ahead:** For a one-off traffic spike, contact support to add page view units before usage peaks. If anonymous traffic is consistently high every cycle, upgrading your plan is usually the better long-term fit. *** ## Feedback Responses [#feedback-responses] **Feedback responses** are **partial or fully submitted** form submissions from your in-app feedback forms and survey links. On the **Free** plan, responses are capped at **100 per month**. On **paid plans**, responses are **unlimited** — you can collect as much feedback as you need without a per-response fee, subject to fair usage (see below). Feedback responses are counted at the **organization (account) level** — submissions from all projects in your workspace share one allowance. Limits depend on your plan: * **Free plan** — **100 responses per month**. When you reach the cap, new submissions are not accepted until the next month or until you upgrade. * **Paid plans** — Responses are unlimited, with a **fair usage policy (FUP)** cap of **20× your MAU plan limit** per billing cycle. For example, a **1,000 MAU** plan includes up to **20,000** responses, a **10,000 MAU** plan includes **200,000**, and a **50,000 MAU** plan includes **1,000,000** per billing cycle under fair usage. A **response** is one **partial or fully submitted** form submission from an in-app feedback form or survey link tied to your workspace. Form impressions or dismissals without any submission do **not** count toward this limit. **Responses are not tracked events.** Form submissions are measured here — not under the tracked events meter (which covers `trackEvent()` calls and screen views only). Responses are a **separate limit from MAU**. One user can submit multiple forms and contribute multiple responses while still counting as a single MAU. **Free plan** — When you reach **100 responses** in a month, new submissions are paused until the next month or until you upgrade to a paid plan. **Paid plans** — When you reach the fair usage cap: * **New responses** are not accepted until the next billing cycle, until you upgrade your plan, or until support adds more units to your account. * Responses already collected remain available in your dashboard, reports, and destinations. * You won't be charged overage — collection is paused until your allowance resets, support adds more units, or you upgrade. If you need more response capacity, choose the option that fits your situation: * **Temporary spike this cycle** — Contact our support team to request additional response units as an add-on for the current billing cycle. * **Regular, ongoing need** — Upgrade your plan to a higher MAU tier. Because the fair usage cap scales at **20× MAU**, a larger plan raises both limits together. **Plan ahead:** For a one-off campaign or short-term spike, contact support to add response units before volume peaks. If you consistently collect more responses every cycle, upgrading your plan is usually the better long-term fit. *** ## AI Credits [#ai-credits] **AI credits** power Encatch’s AI features, such as AI-generated feedback forms, AI filters for destinations, and other AI-powered capabilities. AI credits are counted at the **organization (account) level** — usage from all projects in your workspace shares one allowance. Each AI action consumes credits according to the feature’s usage (e.g., form generation, filter execution). Your plan includes a fixed number of AI credits per month. * Usage is shown in your **billing** screen in the admin console. * When credits run out, AI features are paused until the next billing cycle or until you add more credits. * AI credits do **not** count toward MAU — they are a separate limit. *** ## Frequently Asked Questions [#frequently-asked-questions] Go to the **billing** menu in the left sidebar of your dashboard. You’ll see current usage for MAU, tracked events, page views, responses, AI credits, and other limits. MAU does not reset on a fixed schedule. It is a rolling 30-day count that updates continuously — users with activity older than 30 days drop off automatically. A new billing cycle or calendar month does not zero out your MAU number. Limits measured per billing cycle, such as tracked events, page views, and feedback responses on paid plans, follow your billing-cycle date. If you change from one paid plan to another paid plan, your new billing cycle starts on the plan-change date, and future billing-cycle allowance resets follow that date. MAU remains a rolling 30-day metric and does not reset with a plan change. Yes. Any user who **partially or fully submits** a feedback form — whether in-app or via a survey link — counts toward your MAU for the rolling 30-day window. Each unique respondent is counted once, even if they submit multiple forms. Yes, when they partially or fully submit a form, or — on **Growth plan and above** — when **Allow event tracking for visitors** is enabled in your project settings and they trigger a **`trackEvent()`** call. Visitors who only view a page, see a form, or dismiss it without submitting anything are not counted unless a tracked event is recorded *(Growth plan and above)*. Partial and full submissions both count — a user who starts but does not finish a form still contributes 1 MAU for that rolling window. Unique anonymous visitors are recognized via a **browser cookie**, or in **cookieless mode** via **IP address and user agent**. Anonymous page loads are counted toward your **page views** limit instead. Any user you create or update through the Encatch API — or sync in from a connected integration — counts toward MAU if we process that data within the rolling 30-day window. Each unique user is counted once, the same as SDK-identified users. You can often scale your MAU limit from the billing screen in your admin console without changing plans. If your plan doesn’t support that, [contact us](https://encatch.com/contact) to discuss options. **Event tracking** — including `trackEvent()`, behavior-based segmentation, and tracked-event form triggers — is available on the **Growth plan and above** only. It is not included on **Free** or **Team**. If you need event tracking, upgrade to Growth from the billing screen in your admin console. Event tracking is available on the **Growth plan and above**. On **Growth**, your tracked events allowance is **20× your MAU plan limit** — a fixed plan cap per billing cycle, not a rolling window. A 10,000 MAU plan includes up to 200,000 tracked events per billing cycle. Each **`trackEvent()`** call or **screen view** recorded for an identified user counts as one event. **Form responses are not tracked events** — submissions are measured under Feedback Responses. Form lifecycle signals (shown, dismissed, started) also do not count. Anonymous page loads are measured under **page views**, not tracked events. No. Form responses are a separate meter. Tracked events cover behavioral signals sent via **`trackEvent()`** and **screen views** for identified users. Partial or fully submitted form submissions are counted under **Feedback Responses**, not tracked events. New tracked events stop being ingested until the next billing cycle, until you upgrade your plan, or until support adds more units to your account. You are not charged overage fees. MAU and tracked events are independent limits — reaching one does not automatically mean you have reached the other. Yes, on **Growth**. For a **temporary spike** in the current cycle, contact our support team to request additional tracked event units. If you **regularly** need more events every cycle, upgrade to a higher MAU tier on Growth — tracked events scale at 20× MAU, so a larger tier increases both limits. Your page views allowance is **20× your plan’s MAU limit** — a fixed plan cap per billing cycle for anonymous website traffic, not a rolling window. A 10,000 MAU plan includes up to 200,000 page views. After **`startSession()`**, each page load or navigation the SDK records for an **unidentified visitor** counts as one page view. **Identified users are not counted toward page views** — their navigation is measured through MAU and tracked events instead. Form impressions, dismissals, and submissions do **not** count toward page views. No. Page views are counted for **anonymous visitors only**. Once a user is identified through the SDK, their navigation is not counted toward page views — it is measured through **MAU** and **tracked events** instead. No. Page views and MAU are separate meters. Page views track anonymous page loads and navigations recorded after **`startSession()`**. How a visitor counts toward MAU depends on whether they are identified and how they interact with your forms — see the **Anonymous website visitors** accordion under MAU above. Auto tracking stops for anonymous visitors — the SDK stops sending `trackScreen()` updates and ping requests that check for eligible forms. New page views are not ingested until the next billing cycle, until you upgrade your plan, or until support adds more units. You are not charged overage fees. Responses and data already collected remain fully accessible. Yes. For a **temporary spike** in the current cycle, contact our support team to request page view add-on units. If you **regularly** need more page views every cycle, upgrade to a higher MAU plan instead — page views scale at 20× MAU, so a larger tier increases both limits. On **paid plans**, yes — there is no per-response charge. Unlimited collection is subject to a **fair usage policy** cap of **20× your MAU plan limit** per billing cycle. On the **Free** plan, responses are capped at **100 per month** — upgrade to a paid plan for unlimited collection. The Free plan includes **100 responses per month**. Partial and fully submitted form submissions both count. When you reach the cap, new responses are not accepted until the next month or until you upgrade. A response is one partial or fully submitted form submission from an in-app feedback form or survey link. Impressions or dismissals without any submission do not count. Responses are **not tracked events** — they are measured separately under Feedback Responses. New responses stop being accepted until the next billing cycle, until you upgrade your plan, or until support adds more units to your account. You are not charged overage fees. Responses already collected remain fully accessible in your dashboard, reports, and destinations. When you reach **100 responses** in a month, new submissions are paused until the next month or until you upgrade to a paid plan. Responses already collected remain fully accessible. Yes. For a **temporary spike** in the current cycle, contact our support team to request response add-on units. If you **regularly** collect more responses every cycle, upgrade to a higher MAU plan instead — the fair usage cap scales at 20× MAU, so a larger tier increases both limits. **MAU** is the only limit scoped per **project**. The same user active in two projects counts as **2 MAU** toward your plan limit. **Tracked events**, **page views**, **feedback responses**, and **AI credits** are all pooled at the **organization (account) level** — every project in your workspace draws from the same allowance. Check the **billing** screen in your admin console for organization-wide usage. Yes. AI credits are applied at the **organization (account) level** and shared across all projects in your workspace. Check your billing screen for current usage and allocation. *** ## Next Steps [#next-steps] * [Plans & Pricing](/pricing) — Compare plans and limits * [Billing FAQ](/docs/billing/billing-faq) — Upgrade, downgrade, refunds, and more # AI Filters (/docs/destinations/ai-filters) ## Overview [#overview] The AI Filter feature allows you to intelligently filter feedback before it reaches your destination. Using natural language prompts, you can instruct an AI model to analyze feedback and decide whether it should be forwarded or blocked. AI Filters use AI Credits. Each execution consumes 1 AI Credit. ## How It Works [#how-it-works] **Configure Your Prompt** Write a clear instruction that tells the AI what feedback to forward or block. Be specific about your criteria. **Select Context Data** Choose which feedback data fields to include in the analysis: * Questions and answers * Device information * Geographic information * User information **Test Your Filter** Use the test feature to see how your filter responds to sample feedback. Review the decision, reason, and confidence level. **Save & Enable** Once satisfied with test results, save your configuration and enable the filter to start filtering feedback automatically. ## Key Features [#key-features] * **Natural Language Prompts**: Write instructions in plain English - no complex syntax required * **Context-Aware Analysis**: Include relevant feedback data for better filtering decisions * **Default Forward on Error**: Configure behavior when AI processing fails * **Test Before Deploy**: Preview filter decisions with sample feedback data ## Writing Effective Prompts [#writing-effective-prompts] To create effective prompts, follow these guidelines: * **Be Specific**: Clearly state what feedback should be forwarded or blocked * **Define Criteria**: Specify the criteria for your decision (sentiment, topic, quality, etc.) * **Use Examples**: Include examples of feedback that should be forwarded/blocked (optional but helpful) * **Reference Context**: Mention the available data fields in your prompt when relevant A well-structured prompt typically includes: 1. Clear instruction on what the AI should do 2. Specific criteria for forwarding/blocking 3. Examples or scenarios (optional) ## Example Prompts [#example-prompts] ### Example 1: Forward Only Positive Feedback [#example-1-forward-only-positive-feedback] Use this prompt to forward only positive or neutral feedback: ```text Analyze the feedback and determine if it should be forwarded to the destination. Forward the feedback ONLY if: - The overall sentiment is positive or neutral - The feedback contains constructive suggestions or praise - The rating (if available) is 3 stars or higher Do NOT forward if: - The feedback is primarily negative or critical - The feedback contains complaints without constructive elements - The rating is below 3 stars Respond with a clear decision: FORWARD or DO NOT FORWARD, along with a brief reason. ``` ### Example 2: Filter by Topic Relevance [#example-2-filter-by-topic-relevance] Use this prompt to filter feedback based on topic relevance: ```text Review the feedback and determine if it's relevant to our product features. Forward the feedback if it discusses: - Product features, functionality, or usability - User experience improvements - Feature requests or bug reports Do NOT forward if it discusses: - Pricing or billing questions - Account management issues - Spam or irrelevant content Provide your decision with a brief explanation. ``` ### Example 3: Quality-Based Filtering [#example-3-quality-based-filtering] Use this prompt to filter based on feedback quality: ```text Evaluate the feedback quality and completeness. Forward the feedback if: - It contains substantive content (not just "good" or "bad") - It includes specific details or examples - It provides actionable insights Do NOT forward if: - The feedback is too brief or lacks substance - It contains only generic responses - It appears to be spam or automated Explain your decision based on the quality and completeness of the feedback. ``` ## Context Data Fields [#context-data-fields] When configuring your filter, you can include these data fields in the analysis: * **Questions**: The questionnaire structure and questions asked * **Answers**: The user's responses to questions * **Device Info**: Device type, OS, browser, timezone, theme, etc. * **Geo Info**: Location data (country, region, city, postcode) * **User Info**: User-related information (if available) Select only relevant fields to optimize performance and reduce token usage. At least one field must be selected. ## Settings [#settings] ### Default Forward on AI Filter Error [#default-forward-on-ai-filter-error] When enabled, feedback will be automatically forwarded if AI filter processing fails. This ensures no feedback is lost due to technical issues. **Recommended**: Enable this setting to prevent data loss, unless you have strict requirements to block feedback when AI processing fails. ## Why AI Filters Fail [#why-ai-filters-fail] AI filters may fail to process feedback for several reasons. Understanding these scenarios helps you configure your settings appropriately and troubleshoot issues effectively. Your AI filter requires available AI Credits to process feedback. If your account has exhausted all AI Credits, the filter will fail to execute. **Solution**: Purchase additional AI Credits or wait for your credit limit to reset. Check your billing dashboard to monitor credit usage and set up alerts for low credit balances. The combined size of your prompt and selected context data fields may exceed the AI model's token limit. This happens when: * Your prompt is extremely long * You've selected too many context fields * The feedback data itself is very large **Solution**: Simplify your prompt, reduce the number of context fields selected, or break down complex filtering logic into multiple simpler filters. Occasionally, internal system errors or processing issues may cause the AI filter to fail. These are temporary issues that typically resolve automatically. **Solution**: Retry the operation after a few moments. If the issue persists, check system status or contact support. Enable "Default Forward on AI Filter Error" to ensure feedback isn't lost during these incidents. The underlying AI service provider may experience downtime or service interruptions, preventing the filter from processing feedback. **Solution**: Enable "Default Forward on AI Filter Error" to automatically forward feedback when the AI service is unavailable. Monitor service status and retry once the service is restored. To prevent data loss when AI filters fail, always enable "Default Forward on AI Filter Error" unless you have strict requirements to block feedback during failures. ## Testing Your Filter [#testing-your-filter] To test your AI filter: 1. Click **"Test AI Filter"** (always enabled by default) 2. Optionally check **"Save Configuration"** to save your changes 3. Optionally check **"Enable AI Filter"** to activate the filter 4. Click **"Execute Process"** to test with sample feedback The test results will show: * **Decision**: Whether the feedback would be FORWARDED or NOT FORWARDED * **Reason**: The AI's explanation for the decision * **Confidence**: How confident the AI is in its decision * **Token Usage**: How many tokens were consumed Each test execution consumes 1 AI Credit. ## Tips for Success [#tips-for-success] * **Start Simple**: Begin with a basic prompt and refine based on test results * **Test Thoroughly**: Test with various types of feedback to ensure it works as expected * **Be Specific**: Vague prompts lead to inconsistent results - be as specific as possible * **Use Context Wisely**: Only include context fields that are relevant to your filtering logic * **Iterate**: Adjust your prompt based on test results and real-world performance ## Common Use Cases [#common-use-cases] * **Quality Control**: Filter out low-quality or spam feedback * **Topic Filtering**: Only forward feedback relevant to specific topics * **Sentiment Analysis**: Forward only positive or constructive feedback * **Compliance**: Filter out inappropriate or non-compliant content ## Troubleshooting [#troubleshooting] Make your criteria less strict or add more conditions for forwarding. Review your prompt and ensure it's not blocking valid feedback. Add more specific criteria or tighten your requirements. Be more explicit about what should be blocked. Make your prompt more explicit with clear examples and criteria. Test with multiple feedback samples to identify patterns. Reduce the number of context fields selected or simplify your prompt. Only include fields that are essential for your filtering logic. The Execute button is disabled when the prompt is empty. Enter a prompt to enable execution. # Discord (/docs/destinations/discord) ## Overview [#overview] The **Discord** destination lets you send notifications to a Discord channel every time someone submits feedback through your forms. Whether you want your team to stay in the loop on customer sentiment, catch bug reports as they come in, or simply never miss a response—Discord triggers ensure feedback lands in your server the moment it arrives. This guide walks you through the full setup, from creating your first Discord destination to configuring the webhook and optional display settings. We'll keep things straightforward and explain each step along the way so you can get up and running without any guesswork. *** ## What You'll Need [#what-youll-need] Before you start, make sure you have: * **A feedback configuration** — The form or feedback stream you want to send to Discord * **A Discord server** — Where you want notifications to appear * **Manage Webhooks permission** — On the target server (or ask a server admin to create the webhook for you) * **A Discord webhook URL** — Created from your server's integration settings (format: `https://discord.com/api/webhooks/...`) If you're not sure how to create a webhook, open your Discord server → **Server Settings** → **Integrations** → **Webhooks** → **New Webhook**. Choose the channel, copy the webhook URL, and keep it secure—treat it like a password. *** ## Step 1: Open the Destinations Page [#step-1-open-the-destinations-page] Head to the **Destinations** section in your encatch dashboard. This is where you manage all your integration endpoints—Slack, Email, Jira, GitLab, GitHub, Discord, Webhooks, and more. On the Destinations page, you'll see a table showing any destinations you've already set up (or an empty table if you're starting fresh). In the top-right corner, look for the **Add Destination** button—that's your starting point. Click **Add Destination** to open the configuration flow. *** ## Step 2: Add a New Destination [#step-2-add-a-new-destination] A modal will appear for your new realtime destination. You'll notice fields for naming and describing what this destination is for. ### Feedback [#feedback] Choose the published feedback form this destination will listen to from the **Feedback** dropdown. ### Destination name and description [#destination-name-and-description] Give your destination a clear name—something like **"Discord product feedback"** or **"Notify #support on new responses"**. Optionally add a **Description** so your team can tell what this integration does at a glance. ### Select a connector [#select-a-connector] Scroll to the **Connector** section. Available connectors for realtime destinations are listed with their type, name, and description. Find **Discord Notification**: * **TYPE**: Discord (with the Discord icon) * **NAME**: Discord Notification * **DESCRIPTION**: Send Notifications to Discord * **VERSION**: v1 Click the connector row to select it. When selected, the row is highlighted and shows a checkmark. Add Destination modal with feedback configuration and connector selection Then click **Create Destination** at the bottom of the modal to proceed. *** ## Step 3: Configure Your Discord Destination [#step-3-configure-your-discord-destination] After creating the destination, you'll land on the **Edit Destination** page. This is where you set up all the details that control how and where your Discord notifications are sent. ### Destination Details (Left Column) [#destination-details-left-column] On the left, you'll see cards for: * **Destination Details** — Confirm the type (e.g., Realtime) and any high-level settings * **Feedback Configuration** — The feedback form you linked in the previous step * **Connector Configuration** — Shows **Discord Notification** and its description * **Destination Name** — Edit the name you gave earlier if needed * **Destination Description** — Edit the description if needed Click **Save Details** when you're done with these fields. ### Discord Configuration (Right Column) [#discord-configuration-right-column] The right side contains the Discord webhook setting encatch uses to post to your channel. #### Webhook URL [#webhook-url] Enter your **Discord webhook URL**. This is required. encatch uses it to post messages to the channel you configured in Discord. The URL typically looks like: `https://discord.com/api/webhooks/123456789012345678/abcdefghijklmnopqrstuvwxyz` Copy the full URL from Discord's webhook settings. The value is masked for security once saved. Click **Save Configuration** when you're done. *** ## Step 4: Configure Filters (Optional) [#step-4-configure-filters-optional] Use **Custom Filter** for exact field-based rules, or **AI Filter** for meaning-based routing. Matching events continue to Discord; non-matching events are not sent. Click **Test and Enable Custom Filter** to build and validate a deterministic rule. If a Custom Filter is already active, the card provides **Edit & Test** and **Disable Custom Filter** controls. If you want to filter which feedback triggers a Discord notification, you can enable the **AI Filter**. The AI Filter uses natural language prompts to decide which feedback should be forwarded to Discord. For example, you might only want to notify your team for negative feedback, or for feedback that mentions specific keywords like "bug" or "crash." To enable it: 1. In the **AI Filter** section, click **Test and Enable AI Filter** 2. Configure your prompt to define the criteria 3. Test the filter with sample feedback to ensure it behaves as expected If you prefer to receive every notification without filtering, you can leave the AI Filter disabled. AI Filters use AI Credits. Each execution consumes 1 AI Credit. See the [AI Filters](/docs/destinations/ai-filters) guide for more details. *** ## Step 5: Test and Enable [#step-5-test-and-enable] Before going live, test your setup. On the **Destination Status** card, click **Test & Enable Destination** to verify your webhook URL works and that encatch can successfully post a test message to your Discord channel. Once the test passes, the destination will be enabled and will start sending real notifications for every new feedback response that matches your configuration (and any AI filter you've set up). ## Summary [#summary] Here's a quick recap of the flow: **Go to Destinations** — Click **Add Destination** on the Destinations page. **Select Discord connector** — Choose your feedback configuration, name the destination, then select **Discord Notification** and click **Create Destination**. **Configure Discord webhook** — Enter the Discord Webhook URL and save the configuration. **Optional: Add a filter** — Use a Custom Filter for exact rules or an AI Filter for meaning-based routing. **Test and enable** — Click **Test & Enable Destination** to validate the webhook and activate delivery. *** ## Tips and Best Practices [#tips-and-best-practices] * **Use a dedicated channel** — Create a channel such as `#feedback-alerts` or `#customer-support` so notifications stay easy to find. * **Restrict webhook access** — Anyone with the webhook URL can post to that channel. Do not share it publicly; rotate the webhook in Discord if it is exposed. * **Test before enabling** — Always run a test to confirm the webhook URL is valid and messages appear in the right channel. * **Choose the right filter** — Use a Custom Filter for exact conditions and an AI Filter when the meaning of the response matters. *** ## Troubleshooting [#troubleshooting] Check your Webhook URL. Ensure you copied the full URL from Discord (including the ID and token segments). Verify the webhook was not deleted in Discord and that the channel still exists. If the webhook was regenerated, update the URL in encatch and save again. Click **Test & Enable Destination** to activate it. If the test fails, fix any configuration errors first (invalid or revoked webhook URL). Discord must be enabled for your project as a non-experimental realtime connector. Contact your encatch administrator if **Discord Notification** does not appear when adding a realtime destination. # Email (/docs/destinations/email) ## Overview [#overview] The **Email** destination lets you receive email notifications every time someone submits feedback through your forms. Whether you want to stay on top of customer sentiment, catch bug reports quickly, or simply never miss a response—email triggers ensure feedback lands in your inbox the moment it arrives. This guide walks you through the full setup, from creating your first email destination to customizing how those notifications look and when they're sent. We'll keep things straightforward and explain each step along the way. *** ## What You'll Need [#what-youll-need] Before you start, make sure you have: * **A feedback configuration** — The form or feedback stream you want to receive notifications for * **SMTP credentials** — Your email server details (host, port, username, password) from your email provider * **Recipient email address(es)** — Where you want the notifications to go If you're not sure about SMTP settings, your email provider (Gmail, Outlook, your company's IT team, etc.) can usually provide these. Many providers use port 587 with TLS for secure sending. *** ## Step 1: Open the Destinations Page [#step-1-open-the-destinations-page] Head to the **Destinations** section in your encatch dashboard. This is where you manage all your integration endpoints—Slack, Discord, Jira, webhooks, and of course, email. On the Destinations page, you'll see a table showing any destinations you've already set up (or an empty table if you're starting fresh). In the top-right corner, look for the **Add Destination** button—that's your starting point. Click **Add Destination** to open the configuration flow. *** ## Step 2: Add a New Destination [#step-2-add-a-new-destination] A modal titled **Add New Destination** opens with a **Realtime Destination** badge—this is the type you want for instant email alerts whenever feedback is submitted. The modal is divided into a few sections: ### Feedback [#feedback] Choose the published feedback form this destination will listen to from the **Feedback** dropdown. ### Destination Name and Description [#destination-name-and-description] Give your destination a clear, recognizable name—something like **"Destination Email"** or **"Feedback Alerts to Team"**. This helps you identify it later when you have multiple destinations. Optionally, add a **Description** such as *"Destination config for email alerts"* to document what this setup is for. These details are especially helpful when working in a team. Add New Destination modal with feedback configuration and connector selection *** ## Step 3: Select the Email Notification Connector [#step-3-select-the-email-notification-connector] In the **Connector** list, find **Email Notification**. Realtime connectors appear as selectable rows with their name, description, version, and connector tag. Find the **Email Notification** row: * **TYPE**: Email * **NAME**: Email Notification * **DESCRIPTION**: Send Notifications to email * **VERSION**: v1 Click the **Email Notification** row to choose it as your connector. Connector list with Email Notification selected The selected row is highlighted and shows a checkmark. Then click **Create Destination** at the bottom of the modal to proceed. *** ## Step 4: Configure Your Email Destination [#step-4-configure-your-email-destination] After creating the destination, you'll land on the **Edit Destination** page. This is where you configure all the details that control how and where your email notifications are sent. ### Destination Details (Left Column) [#destination-details-left-column] On the left, you'll see cards for: * **Destination Details** — Confirm the type (e.g., Realtime) and any high-level settings * **Feedback Configuration** — The feedback form you linked in the previous step * **Connector Configuration** — Shows "Email Notification" and its description * **Destination Name** — Edit the name you gave earlier if needed * **Destination Description** — Edit the description if needed Click **Save Details** when you're done with these fields. ### Configuration (Right Column) [#configuration-right-column] The right side contains the email delivery settings. #### To Address [#to-address] Enter the email address that should receive notifications. This field is required. The helper text in the editor indicates that comma-separated recipients are supported. The same card contains the SMTP settings encatch uses to send the notification: * **SMTP Host** — The hostname of your outgoing mail server * **SMTP Port** — The port used by your SMTP server for secure submission * **Username** — The username for authenticating with your SMTP server * **Password** — The password for the SMTP account * **From Email** — The default sender address shown in the "From" field Fill in these details according to your email provider's documentation. If you're unsure, check your provider's help pages for "SMTP settings" or "outgoing mail server." Email destination configuration with privacy-safe example SMTP values Click **Save Configuration** when you're done. *** ## Step 5: Configure Filters (Optional) [#step-5-configure-filters-optional] The **Custom Filter** and **AI Filter** cards sit below the destination details. * **Custom Filter** — Build deterministic conditions for which submissions continue to this destination. Click **Test and Enable Custom Filter** to configure and validate the rule. * **AI Filter** — Use a natural-language prompt when the decision depends on the meaning of the response. If you want to filter which feedback triggers an email, you can enable the **AI Filter**. The AI Filter uses natural language prompts to decide which feedback should be forwarded to your destination. You can instruct it to, for instance, only forward negative feedback or feedback containing specific keywords. To enable it: 1. Click **Test and Enable AI Filter** 2. Configure your prompt in the AI Filter section 3. Test the filter with sample feedback to ensure it behaves as expected If you prefer to receive every email without filtering, you can leave the AI Filter disabled. AI Filters use AI Credits. Each execution consumes 1 AI Credit. See the [AI Filters](/docs/destinations/ai-filters) guide for more details. *** ## Step 6: Test and Enable [#step-6-test-and-enable] Before going live, click **Test & Enable Destination** in the **Destination Status** card. encatch validates the SMTP configuration and enables the destination when the test succeeds. New submissions that match your Custom Filter or AI Filter are then sent to the configured recipient address. *** ## Summary [#summary] Here's a quick recap of the flow: **Go to Destinations** — Click **Add Destination** on the Destinations page. **Select feedback and connector** — Choose a published feedback form, add a destination name and optional description, then select **Email Notification** from the connector list. **Create the destination** — Click **Create Destination** to proceed. **Configure email delivery** — Set the To Address, SMTP host, port, username, password, and From Email. **Optional: Add a filter** — Configure a Custom Filter for exact rules or an AI Filter for meaning-based routing. **Test and enable** — Click **Test & Enable Destination** to validate the configuration and activate delivery. *** ## Tips and Best Practices [#tips-and-best-practices] * **Support multiple recipients** — Add comma-separated addresses for team notifications. * **Test before enabling** — Always run a test to ensure the SMTP credentials and sender settings work. * **Choose the right filter** — Use a Custom Filter for exact field rules and an AI Filter when meaning or intent matters. *** ## Troubleshooting [#troubleshooting] Check your SMTP settings—host, port, username, and password. Ensure your email provider allows SMTP access (some require "Less secure app access" or an app-specific password). Verify the To Address is correct and not blocked by spam filters. Confirm that the destination is linked to the intended published feedback form and that the response contains the fields you expect. Click **Test & Enable Destination** to activate it. If the test fails, fix any SMTP or configuration errors first. Enable a Custom Filter for exact conditions or an AI Filter for meaning-based criteria. This reduces noise while keeping important alerts. # GitHub (/docs/destinations/github) ## Overview [#overview] The **GitHub** destination lets you automatically create GitHub issues every time someone submits feedback through your forms. encatch uses a **Github App (Self Hosted)** connector so issues are created through a GitHub App installed on your repository—not a personal access token. This guide shows how to add a realtime destination, enter GitHub App credentials, configure issue details, add optional filters, and enable the destination. *** ## What You'll Need [#what-youll-need] Before you start, make sure you have: * **A published feedback form** — Only published feedback appears in the Add Destination dialog * **A GitHub App** — Created in your GitHub organization or user account * **GitHub App installed on the target repository** — With permission to create issues * **GitHub App ID** — From your app’s settings on GitHub * **Private key (.pem)** — The key file generated when the GitHub App was created * **Repository owner and name** — The GitHub user or organization plus the repo slug (for example, `octocat` and `hello-world`) *** ## Step 1: Open the Destinations Page [#step-1-open-the-destinations-page] Go to **Destinations** in your encatch dashboard. Click **+ Add Destination** in the top-right corner. *** ## Step 2: Add a New Destination [#step-2-add-a-new-destination] The **Add New Destination** dialog opens with a **Realtime Destination** badge. Complete these fields: ### Feedback [#feedback] Select **published feedback** that will be delivered to this destination. The dropdown shows each form’s title and description. If nothing appears, publish your feedback form first. ### Destination name (required) [#destination-name-required] Enter a name before you click **Create Destination**. Maximum **50 characters** at create time (character counter shown in the dialog). ### Description (optional) [#description-optional] Optional short description. It is only saved if you enter text here. ### Connector [#connector] In the connector list, click **Github App (Self Hosted)**: | Property | Value | | --------------- | ---------------------------------------------------- | | **Name** | Github App (Self Hosted) | | **Tag** | `GithubAppSelf-hosted` | | **Version** | v1 | | **Description** | Create Issue using github app for feedbacks received | Only non-experimental realtime connectors are listed. Click a connector once to select it (checkmark appears), then click **Create Destination**. You are taken to the **Edit Destination** page. Add New Destination modal with Github App connector selected *** ## Step 3: Configure Your GitHub Destination [#step-3-configure-your-github-destination] The **Edit Destination** page has two columns: **Destination Details** on the left and **Destination Status** / **Configuration** on the right. ### Destination Details (left column) [#destination-details-left-column] * **Type** — **Realtime** (shown in the type selector; not editable after create) * **Feedback Configuration** — The linked published form (read-only) * **Connector Configuration** — **Github App (Self Hosted)** with description *Create issue using github app for feedbacks received* * **Destination Name** — Edit if needed (up to 50 characters), then click **Save Details** * **Destination Description** — Optional (up to 100 characters) **Save Details** is enabled only after you change the name or description. ### GitHub App credentials (right column — Configuration) [#github-app-credentials-right-column--configuration] While the destination is **disabled**, fill in all required fields in the **Configuration** card: | Field | Required | Description | | ---------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- | | **GitHub App ID** | Yes | Unique identifier of your GitHub App (App settings on GitHub). Placeholder: `e.g., 123456` | | **Private Key (.pem)** | Yes | Full contents of the generated private key file, including `-----BEGIN RSA PRIVATE KEY-----` and `-----END RSA PRIVATE KEY-----` | | **Repository Owner** | Yes | GitHub username or organization name. Placeholder: `e.g., octocat` | | **Repository Name** | Yes | Repository slug only (not `owner/repo`). Placeholder: `e.g., hello-world` | | **Issue Title** | Yes | Title used for each GitHub issue. | | **Issue Labels** | No | Comma-separated labels assigned to created issues. | Click **Save Configuration** when all required fields are filled in. When the destination is **enabled**, the Configuration form is read-only. Use **Disable Destination** first, then edit credentials and click **Save Configuration** again. *** ## Step 4: Configure Filters (Optional) [#step-4-configure-filters-optional] The **Custom Filter** and **AI Filter** cards sit below the destination details. * **Custom Filter** — Build deterministic conditions for which submissions continue to GitHub. Click **Test and Enable Custom Filter** to configure and validate a rule. * **AI Filter** — Use natural language when the decision depends on the meaning of the response. On the left column **AI Filter** card: * **Current status** — Disabled or Enabled * **Test and Enable AI Filter** — Opens the filter setup dialog * When enabled, **Edit & Test** lets you change the prompt The AI Filter uses natural language to decide which feedback is forwarded—for example, only low ratings or messages mentioning “bug.” See [AI Filters](/docs/destinations/ai-filters). Each filter execution uses **1 AI Credit**. Leave the AI Filter disabled if every submission should create a GitHub issue. *** ## Step 5: Test and Enable [#step-5-test-and-enable] In the **Destination Status** card, click **Test & Enable Destination**. encatch validates the GitHub App credentials and repository access, then enables the destination when the test succeeds. *** ## Summary [#summary] **Add destination** — Destinations → **+ Add Destination** → **Realtime Destination** **Select connector** — Choose published feedback, enter a destination name (≤50 chars), select **Github App (Self Hosted)**, click **Create Destination** **Save app credentials** — Enter **GitHub App ID**, **Private Key (.pem)**, **Repository Owner**, and **Repository Name**, then **Save Configuration** **Set issue details** — Add the Issue Title and optional comma-separated Issue Labels. **Optional** — Configure a **Custom Filter** or **AI Filter** to limit which feedback creates issues. **Test and enable** — Click **Test & Enable Destination** to validate the GitHub App connection and activate the destination. *** ## Tips and Best Practices [#tips-and-best-practices] * **Install the GitHub App on the repo first** — encatch cannot create issues until the app is installed on the target repository with issue creation permission. * **Paste the full private key** — Include the `BEGIN` and `END` lines exactly as in your `.pem` file. * **Use owner and repo separately** — **Repository Owner** is the user or org; **Repository Name** is the repo slug without the owner prefix. * **Use consistent issue labels** — Apply labels that already exist in the repository so incoming feedback fits your triage workflow. * **Disable before editing config** — Saved credentials cannot be changed while the destination is enabled. *** ## Troubleshooting [#troubleshooting] Confirm **GitHub App ID**, **Private Key**, **Repository Owner**, and **Repository Name**. Verify the GitHub App is installed on the repository and can create issues, then run **Test & Enable Destination** again. The destination must be **Disabled** first. Click **Disable Destination**, update credentials, click **Save Configuration**, then **Test & Enable Destination** again. Select **published feedback**, a **connector**, and a **destination name** (1–50 characters). If no connectors appear, contact your administrator—connectors are loaded from your encatch integration configuration. Check **Repository Owner** and **Repository Name** separately. Confirm the GitHub App is installed on that repository and spelling matches GitHub exactly. # GitLab (/docs/destinations/gitlab) ## Overview [#overview] The **GitLab** destination lets you automatically create GitLab issues every time someone submits feedback through your forms. Whether you're tracking bug reports, feature requests, or general customer sentiment—GitLab triggers ensure that every piece of feedback gets turned into a trackable issue in your project, so nothing slips through the cracks. This guide walks you through the full setup, from creating your first GitLab destination to customizing how those issues look, what labels they get, and how the description is formatted. We'll keep things straightforward and explain each step along the way so you can get up and running without any guesswork. *** ## What You'll Need [#what-youll-need] Before you start, make sure you have: * **A feedback configuration** — The form or feedback stream you want to send to GitLab * **A GitLab account** — Access to GitLab.com or your self-hosted GitLab instance * **A Personal Access Token** — With API scope, so encatch can create issues on your behalf * **A GitLab project** — The project where you want issues to be created (you'll need its ID or full path, e.g., `group/subgroup/project`) If you're not sure how to create a Personal Access Token, go to your GitLab profile → **Access Tokens**, create a new token with `api` scope, and use it when configuring your GitLab destination. Keep it secure—treat it like a password. *** ## Step 1: Open the Destinations Page [#step-1-open-the-destinations-page] Head to the **Destinations** section in your encatch dashboard. This is where you manage all your integration endpoints—Slack, Discord, Email, Jira, GitLab, GitHub, Webhooks, and of course, GitLab. On the Destinations page, you'll see a table showing any destinations you've already set up (or an empty table if you're starting fresh). In the top-right corner, look for the **Add Destination** button—that's your starting point. Click **Add Destination** to open the configuration flow. *** ## Step 2: Add a New Destination [#step-2-add-a-new-destination] A modal titled **Add New Destination** opens with a **Realtime Destination** badge. Choose a published form from **Feedback**, enter a required **Destination name**, and optionally add a **Description** such as *"Create GitLab issues for product feedback"*. ### Select a connector [#select-a-connector] In the **Connector** list, find **Gitlab Notification**. Realtime connectors appear as selectable rows with their name, description, version, and connector tag. Find the **GitLab Notification** row: * **TYPE**: GitLab (with the GitLab icon) * **NAME**: Gitlab Notification * **DESCRIPTION**: Send Notifications to Gitlab as issues * **VERSION**: v1 Click the **Gitlab Notification** row. The selected row is highlighted and shows a checkmark. Add Destination modal with GitLab Notification selected Then click **Create Destination** at the bottom of the modal to proceed. *** ## Step 3: Configure Your GitLab Destination [#step-3-configure-your-gitlab-destination] After creating the destination, you'll land on the configuration page. This is where you set up all the details that control how and where your GitLab issues are created. ### Destination Details (Left Column) [#destination-details-left-column] On the left, you'll see cards for: * **Connector Configuration** — Shows "Gitlab Notification" and its description * **Destination Name** — Edit the name you gave earlier if needed (e.g., "Dest git") * **Destination Description** — Edit the description if needed * **Custom Filter** — Optional exact conditions for which feedback creates issues * **AI Filter** — Optional meaning-based routing for which feedback creates issues Click **Save Details** when you're done with these fields. ### GitLab Configuration (Right Column) [#gitlab-configuration-right-column] The right side is where the GitLab-specific settings live. These are the credentials and project details encatch needs to create issues in your GitLab instance. #### GitLab Host [#gitlab-host] Enter the base URL of your GitLab instance. For GitLab.com, use `https://gitlab.com`. For your organization's GitLab, use your GitLab URL (e.g., `https://gitlab.yourcompany.com`). This field is required. #### Access Token [#access-token] Enter your GitLab Personal Access Token with API scope. This is used for secure authentication—encatch never stores your GitLab password. Create one from your GitLab profile → **Access Tokens** if you haven't already. The value will be masked for security once saved. #### Project ID or Path [#project-id-or-path] Enter the GitLab project ID or full path to your project. For example: `group/subgroup/project` or a numeric project ID. You can find this in your project's settings or in the project URL. This field is required. *** ## Step 4: Configure Issue Fields [#step-4-configure-issue-fields] Below the connection settings, you'll find the fields that control *how* each GitLab issue is created when feedback arrives. These let you map feedback to the right content and structure. ### Issue Title [#issue-title] This is the main subject or headline of the GitLab issue. You can use a static value like *"Feedback response"* or use template variables to pull in dynamic content from the feedback (e.g., the user's summary or first response). This field is required. ### Issue Description [#issue-description] This is a large text area where you define the body of the GitLab issue. The description supports Markdown and uses a templating language (Jinja-style) to inject feedback data dynamically. A typical structure might look like: ```markdown ## Feedback Summary {% for question in questions %} ### **{{ question.title | default(value="Not filled") }}** {% if question.type == "rating" %} {% if question.value.selected is defined %} - Rating: **{{ question.value.selected | default(value="Not filled") }} / {{ question.value.numberOfRatings | default(value="Not filled") }}** {% else %} - Not filled {% endif %} {% elif question.type == "short_answer" or question.type == "long_text" %} - {{ question.value | default(value="Not filled") }} {% elif question.type == "single_choice" %} - {{ question.value.label | default(value="Not filled") }} {% elif question.type == "multiple_choice_multiple" %} {% if question.value is defined and question.value is iterable and question.value | length > 0 %} - Answers: {% for item in question.value %}{{ item.label }}{% if not loop.last %}, {% endif %}{% endfor %} {% else %} - Not filled {% endif %} {% endif %} {% endfor %} ``` This template loops over feedback questions and formats each one based on its type—ratings, short answers, long text, single choice, and multiple choice. Whatever you put here will become the content of the GitLab issue, so you can include feedback responses, device info, timestamps, and other metadata for full context. ### Issue Labels [#issue-labels] Add comma-separated labels to organize and categorize your feedback issues. For example: `feedback`, `urgent`, `customer-reported`. Use labels that already exist in your GitLab project so you can filter and search effectively. Click **Save Configuration** when you're done. *** ## Step 5: Configure Filters (Optional) [#step-5-configure-filters-optional] Use **Custom Filter** for exact field-based conditions, or **AI Filter** when routing depends on the meaning of the response. Matching events continue to GitLab; non-matching events are not sent. Click **Test and Enable Custom Filter** to build and validate a deterministic rule. If you want to filter which feedback triggers a GitLab issue, you can enable the **AI Filter**. The AI Filter uses natural language prompts to decide which feedback should be forwarded to GitLab. For example, you might only want to create issues for negative feedback, or for feedback that mentions specific keywords like "bug" or "crash." To enable it: 1. In the **AI Filter** section, click **Test and Enable AI Filter** 2. Configure your prompt to define the criteria 3. Test the filter with sample feedback to ensure it behaves as expected If you prefer to create a GitLab issue for every feedback response, you can leave the AI Filter disabled. AI Filters use AI Credits. Each execution consumes 1 AI Credit. See the [AI Filters](/docs/destinations/ai-filters) guide for more details. *** ## Step 6: Test and Enable [#step-6-test-and-enable] Before going live, test your setup. On the **Destination Status** card, click **Test & Enable Destination** to verify your GitLab credentials work and that encatch can successfully create a test issue. Once the test passes, the destination will be enabled and will start creating real issues for every new feedback response that matches your configuration (and any AI filter you've set up). ## Summary [#summary] Here's a quick recap of the flow: **Go to Destinations** — Click **Add Destination** on the Destinations page. **Select GitLab connector** — Choose a published feedback form, add a destination name and optional description, then select **Gitlab Notification** from the connector list and click **Create Destination**. **Configure GitLab credentials** — Enter your GitLab Host, Access Token, and Project ID or Path to connect encatch to your GitLab instance. **Set up issue fields** — Configure the Issue Title, Issue Description template, and Labels so each feedback response becomes a well-structured GitLab issue. **Optional: Add a filter** — Use a Custom Filter for exact rules or an AI Filter for meaning-based routing. **Test and enable** — Click **Test & Enable Destination** to validate the GitLab connection and activate the destination. *** ## Tips and Best Practices [#tips-and-best-practices] * **Use descriptive labels** — Labels like `feedback`, `in-app`, or `urgent` help your team triage and filter issues quickly. * **Leverage the description template** — Include device info, URL, and user context so developers have everything they need without digging for it. * **Test before enabling** — Always run a test to ensure credentials work and templates render correctly. * **Consider AI filters** — If you receive a lot of feedback, an AI Filter can reduce noise by only creating issues for feedback that meets your criteria. * **Use the full project path** — For nested groups, the full path (e.g., `group/subgroup/project`) is often clearer than a numeric ID. *** ## Troubleshooting [#troubleshooting] Check your GitLab Host, Access Token, and Project ID or Path. Ensure the token has `api` scope and hasn't expired. Verify that the project exists and that your account has permission to create issues in that project. Review the Issue Title and Issue Description fields and confirm that the linked feedback form contains the response data you expect. Click **Test & Enable Destination** to activate it. If the test fails, fix any credential or configuration errors first. Double-check the Project ID or Path. For paths, use the format `group/subgroup/project` with forward slashes. Make sure there are no extra spaces or typos. # Destinations (/docs/destinations) Destinations support two filtering approaches before an event is sent. Use a **Custom Filter** for exact field-based conditions, such as a rating of 3 or below. Use an **AI Filter** when routing depends on the meaning or intent of the response. ## Create a realtime destination [#create-a-realtime-destination] Select **Add Destination** to open **Add New Destination**. A realtime destination connects one published feedback form to one connector. Choose the feedback form, enter a **Destination name** (required, up to 50 characters), optionally enter a **Description** (up to 100 characters), then choose a connector and create the destination. ## Available destinations [#available-destinations] * [Email](/docs/destinations/email) * [Jira](/docs/destinations/jira) * [GitLab](/docs/destinations/gitlab) * [GitHub App (Self Hosted)](/docs/destinations/github) — Create GitHub issues from feedback submissions * [Slack](/docs/destinations/slack) * [Discord](/docs/destinations/discord) * [Webhooks](/docs/destinations/webhooks) — Send feedback to Zapier, n8n, Microsoft Power Automate, or your own custom webhook endpoint # Jira (/docs/destinations/jira) ## Overview [#overview] The **Jira** destination lets you automatically create Jira issues every time someone submits feedback through your forms. Whether you're tracking bug reports, feature requests, or general customer sentiment—Jira triggers ensure that every piece of feedback gets turned into a trackable issue in your project, so nothing slips through the cracks. This guide walks you through the full setup, from creating your first Jira destination to customizing how those issues look, what labels they get, and how the description is formatted. We'll keep things straightforward and explain each step along the way so you can get up and running without any guesswork. *** ## What You'll Need [#what-youll-need] Before you start, make sure you have: * **A feedback configuration** — The form or feedback stream you want to send to Jira * **A Jira account** — Access to a Jira instance (Cloud or Server) * **Jira API credentials** — Your Jira host URL, the email associated with your account, and an API token for authentication * **A Jira project** — The project where you want issues to be created (you'll need its project key, e.g., ENG, WEB, PRJ) If you're not sure how to create an API token, Atlassian provides clear instructions: go to your [Atlassian account settings](https://id.atlassian.com/manage-profile/security/api-tokens), create a new token, and use it when configuring your Jira destination. Keep it secure—treat it like a password. *** ## Step 1: Open the Destinations Page [#step-1-open-the-destinations-page] Head to the **Destinations** section in your encatch dashboard. This is where you manage all your integration endpoints—Slack, Discord, Email, GitLab, GitHub, Webhooks, and of course, Jira. On the Destinations page, you'll see a table showing any destinations you've already set up (or an empty table if you're starting fresh). In the top-right corner, look for the **Add Destination** button—that's your starting point. Click **Add Destination** to open the configuration flow. *** ## Step 2: Add a New Destination [#step-2-add-a-new-destination] A modal titled **Add New Destination** opens with a **Realtime Destination** badge. The modal is divided into a few sections: ### Feedback, destination name, and description [#feedback-destination-name-and-description] Choose a published form from **Feedback**, enter a required **Destination name**, and optionally add a **Description** such as *"Create Jira issues for product feedback"* or *"Bug reports from in-app feedback"*. ### Select a connector [#select-a-connector] In the **Connector** list, find **Jira Notification**. Realtime connectors appear as selectable rows with their name, description, version, and connector tag. Find the **Jira Notification** row: * **TYPE**: Jira (with the Jira icon) * **NAME**: Jira Notification * **DESCRIPTION**: Send Notifications to Jira as Issues * **VERSION**: v1 Click the **Jira Notification** row. The selected row is highlighted and shows a checkmark. Add Destination modal with Jira Notification selected Then click **Create Destination** at the bottom of the modal to proceed. *** ## Step 3: Configure Your Jira Destination [#step-3-configure-your-jira-destination] After creating the destination, you'll land on the **Configure your feedback destination settings** page. This is where you configure all the details that control how and where your Jira issues are created. ### Destination Details (Left Column) [#destination-details-left-column] On the left, you'll see cards for: * **Destination Details** — Confirm the type (e.g., Realtime) and any high-level settings * **Feedback Configuration** — The feedback form you linked in the previous step * **Connector Configuration** — Shows "Jira Notification" and its description * **Destination Name** — Edit the name you gave earlier if needed (e.g., "Destination Jira") * **Destination Description** — Edit the description if needed Click **Save Details** when you're done with these fields. ### Jira Configuration (Right Column) [#jira-configuration-right-column] The right side is where the Jira-specific settings live. These are the credentials and project details encatch needs to create issues in your Jira instance. #### Jira Host [#jira-host] Enter the base URL of your Jira instance. For Jira Cloud, this typically looks like `https://your-domain.atlassian.net`. For Jira Server or Data Center, use your organization's Jira URL. This field is required. #### Email [#email] Enter the email address associated with your Jira account. This is the account that will be used to authenticate with the Jira API. It must match the account that owns the API token you'll provide next. #### API Token [#api-token] Enter your Jira API token. This is used for secure authentication—encatch never stores your Jira password. Create one from your [Atlassian account settings](https://id.atlassian.com/manage-profile/security/api-tokens) if you haven't already. The value will be masked for security once saved. *** ## Step 4: Configure Issue Fields [#step-4-configure-issue-fields] Below the connection settings, you'll find the fields that control *how* each Jira issue is created when feedback arrives. These let you map feedback to the right project, issue type, and content. ### Project Key [#project-key] Enter the key of the Jira project where issues should be created. Project keys are short identifiers like `ENG`, `WEB`, or `PRJ`—you can find yours in your Jira project settings or in the project URL. This field is required. ### Issue Type [#issue-type] Choose the type of Jira issue to create—for example, **Task**, **Bug**, or **Epic**. Make sure the type you select exists and is available in your project. Jira projects can have different issue types enabled, so double-check that your choice matches your project's configuration. ### Labels [#labels] Add comma-separated labels to organize and categorize your feedback issues. For example: `frontend`, `urgent`, `customer-feedback`. For consistency, use labels that already exist in your Jira instance so you can filter and search effectively. ### Title / Summary [#title--summary] This is the main subject or headline of the Jira issue. You can use a static example like *"Unable to login from mobile app"* or use template variables to pull in dynamic content from the feedback (e.g., the user's summary or first response). This field is required. ### Description [#description] Use **Description** to add content before the feedback details in each Jira issue. The generated description can include response fields and context so the issue carries the information your team needs for triage. Click **Save Configuration** when you're done. *** ## Step 5: Configure Filters (Optional) [#step-5-configure-filters-optional] Use **Custom Filter** for exact field-based conditions, or **AI Filter** when routing depends on the meaning of the response. Matching events continue to Jira; non-matching events are not sent. Click **Test and Enable Custom Filter** to build and validate a deterministic rule. If you want to filter which feedback triggers a Jira issue, you can enable the **AI Filter**. The AI Filter uses natural language prompts to decide which feedback should be forwarded to Jira. For example, you might only want to create issues for negative feedback, or for feedback that mentions specific keywords like "bug" or "crash." To enable it: 1. In the **AI Filter** section, click **Test and Enable AI Filter** 2. Configure your prompt to define the criteria 3. Test the filter with sample feedback to ensure it behaves as expected If you prefer to create a Jira issue for every feedback response, you can leave the AI Filter disabled. AI Filters use AI Credits. Each execution consumes 1 AI Credit. See the [AI Filters](/docs/destinations/ai-filters) guide for more details. *** ## Step 6: Test and Enable [#step-6-test-and-enable] Before going live, test your setup. On the **Destination Status** card, click **Test & Enable Destination** to verify your Jira credentials work and that encatch can successfully create a test issue. Once the test passes, the destination will be enabled and will start creating real issues for every new feedback response that matches your configuration (and any AI filter you've set up). ## Summary [#summary] Here's a quick recap of the flow: **Go to Destinations** — Click **Add Destination** on the Destinations page. **Select Jira connector** — Choose a published feedback form, add a destination name and optional description, then select **Jira Notification** from the connector list and click **Create Destination**. **Configure Jira credentials** — Enter your Jira Host, Email, and API Token to connect encatch to your Jira instance. **Set up issue fields** — Configure the Project Key, Issue Type, Labels, Title/Summary, and Description template so each feedback response becomes a well-structured Jira issue. **Optional: Add a filter** — Use a Custom Filter for exact rules or an AI Filter for meaning-based routing. **Test and enable** — Click **Test & Enable Destination** to validate the Jira connection and activate the destination. *** ## Tips and Best Practices [#tips-and-best-practices] * **Use descriptive labels** — Labels like `feedback`, `in-app`, or `urgent` help your team triage and filter issues quickly. * **Match issue types to your workflow** — Use **Bug** for defect reports and **Task** for general feedback or feature requests. * **Leverage the description template** — Include device info, URL, and user context so developers have everything they need without digging for it. * **Test before enabling** — Always run a test to ensure credentials work and templates render correctly. * **Consider AI filters** — If you receive a lot of feedback, an AI Filter can reduce noise by only creating issues for feedback that meets your criteria. *** ## Troubleshooting [#troubleshooting] Check your Jira Host, Email, and API Token. Ensure the API token is valid and hasn't expired. Verify that the project key exists and that your account has permission to create issues in that project. Review the Title and Description fields and confirm that the linked feedback form contains the response data you expect. Click **Test & Enable Destination** to activate it. If the test fails, fix any credential or configuration errors first. Ensure the issue type you selected (e.g., Task, Bug) exists in your Jira project. Some projects restrict which issue types are available—check your project settings in Jira. # Slack (/docs/destinations/slack) ## Overview [#overview] The **Slack** destination lets you send notifications to a Slack channel every time someone submits feedback through your forms. Whether you want your team to stay in the loop on customer sentiment, catch bug reports as they come in, or simply never miss a response—Slack triggers ensure feedback lands in your workspace the moment it arrives. This guide walks you through the full setup, from creating your first Slack destination to customizing how those messages look. We'll keep things straightforward and explain each step along the way so you can get up and running without any guesswork. *** ## What You'll Need [#what-youll-need] Before you start, make sure you have: * **A feedback configuration** — The form or feedback stream you want to send to Slack * **A Slack workspace** — Where you want notifications to appear * **A Slack Bot Token** — A bot token that starts with `xoxb-` (you'll create this in your Slack app settings) * **A Channel ID** — The ID of the channel where messages should be posted (typically starts with `C`) If you're not sure how to create a bot token, go to [api.slack.com/apps](https://api.slack.com/apps), create or select an app, add the **chat:write** and **chat:write.public** scopes (if posting to public channels), install the app to your workspace, and copy the Bot User OAuth Token. Keep it secure—treat it like a password. *** ## Step 1: Open the Destinations Page [#step-1-open-the-destinations-page] Head to the **Destinations** section in your encatch dashboard. This is where you manage all your integration endpoints—Slack, Discord, Email, Jira, GitLab, GitHub, Webhooks, and more. On the Destinations page, you'll see a table showing any destinations you've already set up (or an empty table if you're starting fresh). In the top-right corner, look for the **Add Destination** button—that's your starting point. Click **Add Destination** to open the configuration flow. *** ## Step 2: Add a New Destination [#step-2-add-a-new-destination] A modal titled **Add New Destination** opens with a **Realtime Destination** badge. ### Feedback, destination name, and description [#feedback-destination-name-and-description] Choose a published form from **Feedback**, enter a required **Destination name**, and optionally add a **Description** such as *"Slack alerts for product feedback"* or *"Notify #support when users submit feedback"*. ### Select a connector [#select-a-connector] In the **Connector** list, find **Slack Notification**. Realtime connectors appear as selectable rows with their name, description, version, and connector tag. Find the **Slack Notification** row: * **TYPE**: Slack (with the Slack icon) * **NAME**: Slack Notification * **DESCRIPTION**: Send Notifications to Slack * **VERSION**: v1 Click the **Slack Notification** row. The selected row is highlighted and shows a checkmark. Add Destination modal with Slack Notification selected Then click **Create Destination** at the bottom of the modal to proceed. *** ## Step 3: Configure Your Slack Destination [#step-3-configure-your-slack-destination] After creating the destination, you'll land on the **Edit Destination** page (or **Configure your feedback destination settings**). This is where you set up all the details that control how and where your Slack notifications are sent. ### Destination Details (Left Column) [#destination-details-left-column] On the left, you'll see cards for: * **Destination Details** — Confirm the type (e.g., Realtime) and any high-level settings * **Feedback Configuration** — The feedback form you linked in the previous step * **Connector Configuration** — Shows "Slack Notification" and its description * **Destination Name** — Edit the name you gave earlier if needed (e.g., "Slack") * **Destination Description** — Edit the description if needed Click **Save Details** when you're done with these fields. ### Slack Configuration (Right Column) [#slack-configuration-right-column] The right side is where the Slack-specific settings live. These are the credentials and message details encatch needs to post to your Slack channel. #### Slack Bot Token [#slack-bot-token] Enter your Slack Bot Token. This is used for authentication—encatch never stores your Slack password. The token typically starts with `xoxb-`. Create one from your [Slack app settings](https://api.slack.com/apps) if you haven't already. The value will be masked for security once saved. #### Channel ID [#channel-id] Enter the ID of the Slack channel where you want notifications to appear. Channel IDs typically start with `C` (e.g., `C02L8XXXX`). You can find this by right-clicking the channel in Slack, selecting **View channel details**, and copying the channel ID from the bottom of the details panel. This field is required. #### Message [#message] This is a large text area where you define the content of the Slack message. Slack uses **Block Kit**—a JSON structure—so your message can include headers, sections, dividers, and formatted text. You can use a templating language (e.g., Jinja2-style syntax) to inject feedback data dynamically. A typical structure might look like: ```json { "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": " Feedback Summary" } }, { "type": "divider" } ] } ``` You can then use templating to loop over feedback questions and add sections dynamically. For example, for multiple-choice answers: ``` {%- for question in questions -%} {%- if question.value is defined and question.value | length > 0 %} { "type": "section", "text": { "type": "mrkdwn", "text": "✅ Answers:\n{% for choice in question.value %} {{ choice.label | default(value='Not filled') }}\n{% endfor %}" } } {%- endif %} {%- endfor -%} ``` This template lets you loop over feedback questions and format each one based on its type—ratings, short answers, long text, single choice, and multiple choice. Whatever you put here will become the content of the Slack message, so you can include feedback responses, device info, timestamps, and other metadata for full context. #### Notification Message [#notification-message] You can optionally set a **Notification Message** that appears as the main notification text (e.g., *"New feedback received"*). This is the short message shown before the full message body. #### Mention your message [#mention-your-message] If you want to mention specific users or channels in the notification (e.g., `@support` or `@channel`), use the **Mention your message** field. Add the Slack mention syntax you need. Click **Save Configuration** when you're done. *** ## Step 4: Configure Filters (Optional) [#step-4-configure-filters-optional] Use **Custom Filter** for exact field-based rules, or **AI Filter** when the decision depends on the meaning of the response. Matching events continue to Slack; non-matching events are not sent. Click **Test and Enable Custom Filter** to build and validate a deterministic rule. If you want to filter which feedback triggers a Slack notification, you can enable the **AI Filter**. The AI Filter uses natural language prompts to decide which feedback should be forwarded to Slack. For example, you might only want to notify your team for negative feedback, or for feedback that mentions specific keywords like "bug" or "crash." To enable it: 1. In the **AI Filter** section, click **Test and Enable AI Filter** 2. Configure your prompt to define the criteria 3. Test the filter with sample feedback to ensure it behaves as expected If you prefer to receive every notification without filtering, you can leave the AI Filter disabled. AI Filters use AI Credits. Each execution consumes 1 AI Credit. See the [AI Filters](/docs/destinations/ai-filters) guide for more details. *** ## Step 5: Test and Enable [#step-5-test-and-enable] Before going live, test your setup. On the **Destination Status** card, click **Test & Enable Destination** to verify your Slack credentials work and that encatch can successfully post a test message to your channel. Once the test passes, the destination will be enabled and will start sending real notifications for every new feedback response that matches your configuration (and any AI filter you've set up). ## Summary [#summary] Here's a quick recap of the flow: **Go to Destinations** — Click **Add Destination** on the Destinations page. **Select Slack connector** — Choose a published feedback form, add a destination name and optional description, then select **Slack Notification** from the connector list and click **Create Destination**. **Configure Slack credentials** — Enter your Slack Bot Token and Channel ID to connect encatch to your Slack workspace. **Set up the message template** — Configure the Message field with Block Kit JSON and templating so each feedback response becomes a well-structured Slack message. **Optional: Add a filter** — Use a Custom Filter for exact rules or an AI Filter for meaning-based routing. **Test and enable** — Click **Test & Enable Destination** to validate the configuration and activate delivery. *** ## Tips and Best Practices [#tips-and-best-practices] * **Use descriptive channel names** — Pick a channel that clearly indicates its purpose (e.g., `#feedback-alerts`, `#customer-support`). * **Leverage Block Kit** — Use headers, sections, dividers, and `mrkdwn` for rich formatting so messages are easy to scan. * **Include context** — Add device info, URL, and user context in your template so your team has everything they need without digging for it. * **Test before enabling** — Always run a test to ensure credentials work and templates render correctly. * **Consider AI filters** — If you receive a lot of feedback, an AI Filter can reduce noise by only notifying for feedback that meets your criteria. *** ## Troubleshooting [#troubleshooting] Check your Slack Bot Token and Channel ID. Ensure the token is valid and hasn't been revoked. Verify that the bot has been invited to the channel (for public channels, it needs `chat:write.public`; for private channels, invite the bot with `/invite @YourBot`). Review the Message template and confirm that the linked feedback form contains the response fields referenced by the template. Click **Test & Enable Destination** to activate it. If the test fails, fix any credential or configuration errors first. Ensure the Channel ID starts with `C` for public channels. Double-check that you copied the full ID correctly (no extra spaces or typos). For private channels, make sure the bot has been invited. # Webhooks (/docs/destinations/webhooks) ## Overview [#overview] The **Webhook** destination lets you send feedback data to any HTTP endpoint whenever someone submits a response through your forms. Whether you're piping feedback into Zapier, n8n, Microsoft Power Automate, or your own custom API—webhooks give you full flexibility to route feedback wherever you need it. This guide walks you through the setup, from creating your first webhook destination to configuring the URL, HTTP method, and optional headers. We'll keep things straightforward so you can get up and running without any guesswork. *** ## What You'll Need [#what-youll-need] Before you start, make sure you have: * **A feedback configuration** — The form or feedback stream you want to send to your webhook * **A webhook URL** — The endpoint that will receive the feedback (e.g., `https://api.yourservice.com/webhook`) * **Optional: HTTP headers** — Any custom headers your endpoint expects (e.g., for authentication) If you're using a no-code tool like Zapier or n8n, they'll provide you with a webhook URL when you add a "Webhook" trigger. Just copy that URL and paste it into encatch. *** ## Step 1: Open the Destinations Page [#step-1-open-the-destinations-page] Head to the **Destinations** section in your encatch dashboard. This is where you manage all your integration endpoints—Slack, Discord, Email, Jira, GitLab, GitHub, and Webhooks. On the Destinations page, you'll see a table showing any destinations you've already set up (or an empty table if you're starting fresh). In the top-right corner, look for the **Add Destination** button—that's your starting point. Click **Add Destination** to open the configuration flow. *** ## Step 2: Add a New Destination [#step-2-add-a-new-destination] A modal titled **Add New Destination** opens with a **Realtime Destination** badge. ### Feedback, destination name, and description [#feedback-destination-name-and-description] Choose a published form from **Feedback**, enter a required **Destination name**, and optionally add a **Description** such as *"Send feedback to Zapier"* or *"Webhook for internal API"*. ### Select a connector [#select-a-connector] In the **Connector** list, find **Webhook Notification**. Realtime connectors appear as selectable rows with their name, description, version, and connector tag. Find the **Webhook Notification** row: * **TYPE**: Webhook * **NAME**: Webhook Notification * **DESCRIPTION**: Send Notifications to webhook as multipart http * **VERSION**: v1 Click the **Webhook Notification** row. The selected row is highlighted and shows a checkmark. Add Destination modal with Webhook Notification selected Then click **Create Destination** at the bottom of the modal to proceed. *** ## Step 3: Configure Your Webhook Destination [#step-3-configure-your-webhook-destination] After creating the destination, you'll land on the **Edit Destination** page. This is where you set up all the details that control how and where your webhook requests are sent. ### Destination Details (Left Column) [#destination-details-left-column] On the left, you'll see cards for: * **Destination Details** — Confirm the type (e.g., Realtime) and any high-level settings * **Feedback Configuration** — The feedback form you linked in the previous step * **Connector Configuration** — Shows "Webhook Notification" and its description * **Destination Name** — Edit the name you gave earlier if needed (e.g., "Webhook") * **Destination Description** — Edit the description if needed Click **Save Details** when you're done with these fields. ### Webhook Configuration (Right Column) [#webhook-configuration-right-column] The right side is where the webhook-specific settings live. These are the settings encatch needs to send feedback to your endpoint. #### Webhook URL [#webhook-url] Enter the full URL of the endpoint that will receive the feedback. For example: `https://api.example.com/feedback`. encatch sends a POST request to this address whenever matching feedback is submitted. This field is required. The description below the field explains: *"The endpoint to which the webhook will be sent."* #### HTTP Method [#http-method] The webhook destination uses **POST** for delivery. #### Content Type [#content-type] Choose **application/json** for JSON payloads or **multipart/form-data** when the destination needs file attachments. The editor warns that `application/json` does not support attachments. #### HTTP Headers [#http-headers] If your endpoint requires custom headers (for example, an API key or authorization token), use the **Add Item** button to add key-value pairs. This section is optional—only add headers if your integration needs them. Common use cases include: * **Authorization** — `Authorization: Bearer your-api-key` * **Custom headers** — Any headers your Zapier, n8n, or custom API requires Webhook configuration with URL, HTTP method, and headers Click **Save Configuration** when you're done. *** ## Step 4: Configure Filters (Optional) [#step-4-configure-filters-optional] Use **Custom Filter** for exact field-based conditions, or **AI Filter** when routing depends on the meaning of the response. Matching events continue to the webhook; non-matching events are not sent. Click **Test and Enable Custom Filter** to build and validate a deterministic rule. If you want to filter which feedback triggers a webhook, you can enable the **AI Filter**. The AI Filter uses natural language prompts to decide which feedback should be forwarded. For example, you might only want to send webhooks for negative feedback, or for feedback that mentions specific keywords like "bug" or "urgent." To enable it: 1. In the **AI Filter** section, click **Test and Enable AI Filter** 2. Configure your prompt to define the criteria 3. Test the filter with sample feedback to ensure it behaves as expected If you prefer to send every feedback response to your webhook without filtering, you can leave the AI Filter disabled. AI Filters use AI Credits. Each execution consumes 1 AI Credit. See the [AI Filters](/docs/destinations/ai-filters) guide for more details. *** ## Step 5: Test and Enable [#step-5-test-and-enable] Before going live, test your setup. On the **Destination Status** card, click **Test & Enable Destination** to verify your webhook URL works and that encatch can successfully send a test request. Once the test passes, the destination will be enabled and will start sending real webhooks for every new feedback response that matches your configuration (and any AI filter you've set up). ## Summary [#summary] Here's a quick recap of the flow: **Go to Destinations** — Click **Add Destination** on the Destinations page. **Select Webhook connector** — Choose a published feedback form, add a destination name and optional description, then select **Webhook Notification** from the connector list and click **Create Destination**. **Configure webhook settings** — Enter the Webhook URL, choose the content type, and add any optional headers. Delivery uses POST. **Optional: Add a filter** — Use a Custom Filter for exact rules or an AI Filter for meaning-based routing. **Test and enable** — Click **Test & Enable Destination** to activate your webhook. *** ## Tips and Best Practices [#tips-and-best-practices] * **Use a descriptive destination name** — Names like "Zapier Feedback" or "n8n Webhook" make it easy to identify integrations later. * **Verify your endpoint accepts the payload** — Test with a tool like [webhook.site](https://webhook.site) or your service's test mode before enabling. * **Add auth headers when needed** — If your endpoint requires authentication, use the HTTP Headers section to add your API key or token. * **Choose the right filter** — Use a Custom Filter for exact conditions and an AI Filter when meaning or intent matters. *** ## Troubleshooting [#troubleshooting] Check your Webhook URL—ensure it's correct, uses HTTPS where possible, and is publicly reachable. Verify that your endpoint is listening and returns a 2xx response. If you're using Zapier or n8n, make sure the webhook trigger is active and waiting for data. Confirm that the endpoint accepts POST requests, then review the selected content type and any required authentication headers. Click **Test & Enable Destination** to activate it. If the test fails, fix any URL or configuration errors first. # Manage Forms (/docs/feedback-management/manage-forms) The **Forms** workspace is the central place to create, find, and organize feedback forms in a project. Forms workspace with collection filters, recently updated forms, and the grid view ## Find a form [#find-a-form] * Use **Active / Draft** and **Archived** to switch between current and archived forms. * Search by form name or description and narrow the result by status. * Switch between the **grid** and **list** views. * Change the sort order or choose which columns appear in the list view. The **Recently updated** row keeps the five forms changed most recently within reach. Select a card to reopen that form. ## Organize forms with collections [#organize-forms-with-collections] Collections are project-level groups. A form can belong to one collection, and forms without a collection remain available under **Uncategorized**. Use the collection pills above the results to filter the workspace. Select **New collection** to create a group. To rename, reorder, delete, or manage the forms inside a collection, open **Settings → Form Collections**. Collections organize the workspace without changing a form's publishing status, targeting, or responses. ## Create a form [#create-a-form] Select **New Form** to start with a [proven template](/docs/feedback-management/form-creation-methods/templates), [Encatch AI](/docs/feedback-management/form-creation-methods/generative-ai), or a blank form. # AI Assistant / MCP Server (/docs/feedback-management/mcp) The **Encatch MCP Server** connects Encatch to AI assistants such as Claude and ChatGPT. You can build feedback forms through conversation, review drafts in your browser, and ask the AI to open the right Encatch dashboard or settings page. MCP (Model Context Protocol) is the standard that lets the assistant use these Encatch features securely. You sign in with your normal Encatch account—no API key or developer setup is required. *** ## Security highlights [#security-highlights] * **Automatic sign-in is optional** — During connection, you decide whether Encatch may create automatic sign-in links for admin pages. If you do not allow it, you will be asked to sign in when opening a link—unless you already have an active Encatch browser session. * **Automatic sign-in links expire after 5 minutes** — After a link expires, open a new one from the assistant or sign in normally. * **Live Encatch actions remain human-controlled** — The assistant cannot publish forms or directly make destructive changes to your live Encatch account. Publishing, generating API keys, creating shareable links, and starting exports must be completed by you in the Encatch UI. The assistant can edit or permanently delete an **MCP working copy** when you ask it to. A working copy is separate from your live Encatch forms. *** ## What you can do [#what-you-can-do] Once connected, you can ask your AI assistant to: | Area | Examples | | ----------------------------- | ----------------------------------------------------------------------------------------------------------------- | | **Build forms** | Create a customer feedback form with NPS, CSAT, open text, and a thank-you page | | **Edit working copies** | Add pages, change questions, update colors and branding, or set up conditional logic | | **Review in browser** | Get a preview link to see how the form looks before publishing | | **Browse your workspace** | List organizations and projects, switch between them | | **See existing forms** | View published and paused feedback forms in the current project | | **Open admin pages** | Jump to the Overview dashboard, individual responses, form settings, shareable links, API keys, or export reports | | **Analyze completed exports** | Find available report exports and summarize their CSV data | When the assistant builds a form, it creates a temporary **working copy**. This is separate from your live Encatch forms until you choose to transfer or publish it. You can have up to **5 active working copies** at a time. *** ## Before you start [#before-you-start] * An **Encatch account** with access to the organization and project you want to work in * An **AI assistant and plan that support remote MCP connectors** * **Developer Mode** enabled if your ChatGPT plan requires it *** ## MCP server URL [#mcp-server-url] Use this URL when adding Encatch as a custom connector in your AI app: ``` https://mcp.encatch.dev/mcp ``` *** ## Connect your AI assistant [#connect-your-ai-assistant] Encatch MCP uses secure **OAuth sign-in**. Your browser opens so you can sign in to Encatch and approve access; you never enter your Encatch password into the AI assistant. ### Claude (web or desktop) [#claude-web-or-desktop] Open **Settings → Connectors** in [Claude on the web](https://claude.ai) or **Claude Desktop**. Click **Add custom connector** (the label may appear as **Add connector**). Enter the MCP server URL: `https://mcp.encatch.dev/mcp` Click **Add**, then **Connect**. Complete the Encatch sign-in in your browser when prompted. Start a new conversation and enable the Encatch connector for that chat. If the Encatch tools do not appear, check the **+** or connectors menu. Encatch MCP is a **remote** server on the internet. Add it through **Connectors** in Claude settings—not through the local `claude_desktop_config.json` file used for tools that run on your computer. ### ChatGPT [#chatgpt] ChatGPT connects to remote MCP servers through a custom connector. Menu names can vary by plan and ChatGPT version. Open **Settings**, then find **Connectors** or **Apps & Connectors**. If prompted, open **Advanced** and turn on **Developer Mode**. If this option is unavailable, your current plan or workspace may not support custom connectors. Click **Add custom connector**. Enter a name such as **Encatch**, and the MCP URL: `https://mcp.encatch.dev/mcp` Choose **OAuth** if ChatGPT asks for an authentication method, then create the connector. Complete the Encatch sign-in when ChatGPT redirects you. In a new chat, select your Encatch connector and approve tool calls when ChatGPT asks to use them. ### Cursor and other MCP clients [#cursor-and-other-mcp-clients] Other AI assistants can connect if they support remote MCP servers with OAuth. Use the same URL: ``` https://mcp.encatch.dev/mcp ``` In **Cursor**, open **Settings → Tools & MCP**, add a remote server with that URL, and complete the Encatch sign-in when prompted. *** ## Your first conversation [#your-first-conversation] After connecting, try a prompt like: > *"List my Encatch workspaces, switch to \[project name], and create a customer satisfaction survey with a welcome page, a CSAT question, an open-feedback question, and a thank-you page."* A typical workflow looks like this: **Select a workspace** — The AI lists your organizations and projects and switches to the one you want. **Build a working copy** — The assistant creates a separate draft and adds pages, questions, and styling based on your instructions. **Review the preview link** — The assistant shares a link, valid for **7 days**, so you can check the layout, wording, and logic in your browser. **Transfer or publish the form** — As the owner, sign in on the preview page and use **Next Actions**. The assistant cannot complete this step for you. *** ## Preview and publish [#preview-and-publish] The assistant provides a preview link after creating or updating a working copy. * **Viewing** — Anyone with the link can preview the form. * **Transferring or publishing** — Only the **working-copy owner** can complete this action from the preview page. * **Comments** — Sign in on the preview page to leave comments for your team. *** ## Open Encatch admin from the AI [#open-encatch-admin-from-the-ai] You can ask the AI to open specific areas of the Encatch admin—for example: * Overview dashboard * Individual responses for a form * Form settings or shareable link * Project API keys * Export reports The assistant returns a link that opens Encatch in your browser. If you allowed automatic sign-in when connecting, the link can sign you in for up to **5 minutes**. Otherwise, Encatch uses your existing browser session or asks you to sign in. The assistant can **open** these pages, but it cannot generate API keys, create shareable links, or start exports for you. Complete those actions yourself in the Encatch UI. *** ## What the AI can and cannot do [#what-the-ai-can-and-cannot-do] | The AI can | The AI cannot | | ---------------------------------------------------- | ---------------------------------------------------------------------- | | Create, edit, and delete MCP working copies | Publish or transfer a working copy into Encatch | | Share preview links for review | Modify or delete live Encatch forms | | List forms, workspaces, and available report exports | Generate API keys, create shareable links, or start exports | | Open relevant Encatch admin pages | Bypass your account permissions—you only see what your user can access | *** ## Troubleshooting [#troubleshooting] **Tools do not appear after connecting** * Confirm you added the connector in the correct place (Claude **Connectors**, not local MCP config). * Start a **new conversation** and enable the Encatch connector for that chat. * Disconnect and reconnect the connector, then sign in to Encatch again. **"Could not resolve the OAuth client\_id" or similar auth errors** * Remove the Encatch connector and add it again. * Complete the full browser sign-in flow when prompted. * Make sure you are using the production URL: `https://mcp.encatch.dev/mcp` **Preview link works but I cannot publish** * Sign in on the preview page with the Encatch account that **owns the working copy**. * Publishing is done from **Next Actions** on the preview page, not through the AI chat. **ChatGPT will not connect** * Confirm **Developer Mode** is on and your plan supports custom connectors. * Use OAuth (not API key) as the auth method. * The MCP URL must be reachable over HTTPS from the public internet. **Wrong organization or project** * Ask the AI to list workspaces and set the current workspace to the correct organization and project before creating or editing forms. *** ## Related [#related] * [Export Reports](/docs/feedback-management/reports-and-export/export-reports) — Download feedback data and analyze it with **Open with AI** * [Reports & Export overview](/docs/feedback-management/reports-and-export) — Dashboards, charts, and Feedback Studio For help with your Encatch account, contact your workspace administrator or visit [encatch.com](https://encatch.com). # Overview (/docs/framework-examples) hello world ss # Cookie Policy (/docs/legal/cookie-policy) # ENCATCH COOKIE POLICY [#encatch-cookie-policy] **Effective Date:** January 1, 2026 **Last Updated:** May 28, 2026 This Cookie Policy explains how Phyder Mobile Solutions Pvt. Ltd., a company incorporated in India with its registered office at 412/413, 4th Floor, Palmspring (Above Croma), Link Road, Malad West, Mumbai City, Mumbai, Maharashtra, India, 400064, operating under the brand name “Encatch” (“Encatch”, “we”, “us”, or “our”), uses cookies and similar technologies. ## SCOPE [#scope] This Cookie Policy applies to: * Our website ([encatch.com](https://encatch.com)) and any related pages, landing pages, and web content operated by Encatch (the “Website”); and * Where applicable, the Encatch Service, including web application surfaces and related functionality that may use similar technologies (such as local storage or device identifiers). **Relationship to Processor Services (DPA Guardrail).** For clarity, this Cookie Policy governs our use of cookies and similar technologies where Encatch acts as an independent Data Controller (for example, for Website visitors and Encatch account administrators). It does not expand, modify, or apply to Encatch’s obligations where Encatch acts as a Data Processor under the [Encatch Data Processing Addendum (DPA)](/docs/legal/data-processing-addendum), including Processor-side processing of Customer End-User Feedback Data and related Customer End User Identifiers on behalf of Customers. **Defined Terms; Interpretation.** Capitalized terms used but not defined in this Cookie Policy have the meanings given in the [Encatch Terms of Service](/docs/legal/terms-of-service), [Privacy Policy](/docs/legal/privacy-policy), and [Data Processing Addendum (DPA)](/docs/legal/data-processing-addendum) (as applicable). If there is any inconsistency, the [Privacy Policy](/docs/legal/privacy-policy) controls for questions relating to Personal Data and privacy rights, and the [DPA](/docs/legal/data-processing-addendum) controls solely for Processor-side Processing by Encatch on documented Customer instructions. This Cookie Policy should be read together with our [Privacy Policy](/docs/legal/privacy-policy), which explains in more detail how we collect, use, share, and protect Personal Data (including online identifiers). ## COOKIES AND SIMILAR TECHNOLOGIES [#cookies-and-similar-technologies] **What they are.** Cookies are small text files placed on your device by a website or service. We may also use similar technologies, such as local storage, pixels/tags, and device or SDK identifiers, that store or access information on your device or help us recognize a browser or device. **What they may collect.** These technologies may collect or use information such as browser and device details, IP address, unique identifiers, and usage/activity information. Some of this information may constitute Personal Data (for example, online identifiers) as described in our [Privacy Policy](/docs/legal/privacy-policy). **SDK/local storage identifiers (Service).** Where used in connection with the Service (including the Web SDK, where applicable), we may use local storage and technical identifiers to support functionality and reduce unnecessary network requests (for example, tokens/flags/timestamps used for reconnect logic and request throttling). Examples may include SDK parameters such as `identify_signature`, `ping_on_next_page_visit`, and `ping_again_after` (or similar fields). ## PURPOSES AND CATEGORIES [#purposes-and-categories] We use cookies and similar technologies for the following purposes: * **Strictly Necessary (Essential).** These are required to operate the Website and Service and support core functionality, security, and reliability (for example, session management, authentication, abuse prevention, fraud prevention, and troubleshooting). * **Preferences (where used).** These help remember certain settings or selections you make and provide enhanced functionality. Depending on the feature, some preference technologies may be essential. * **Analytics (consent-based where required).** These help us understand how users interact with the Website (and where applicable, certain Service surfaces) so we can improve performance and user experience. Where required by Applicable Law, analytics are enabled only based on the choices you make through our cookie preference controls. * **Marketing / Advertising.** We do not deploy marketing/advertising cookies unless we expressly describe them in this Cookie Policy and make them available through cookie settings. ## COOKIE CATEGORIES AND TECHNOLOGIES (TABLE) [#cookie-categories-and-technologies-table] **Important note on precision.** Cookie and identifier names, durations, and related technical details may vary based on configuration, environment, and updates. We describe categories and typical characteristics and avoid false precision unless verified. | Category | Provider | Examples / Tools | Purpose | Data types (examples) | Duration | Location / Region | Consent required (Y/N) | | ---------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------- | ---------------------- | | Strictly Necessary (Essential) | Encatch | Session/auth mechanisms; security controls; local storage identifiers (where used) | Core functionality, security, reliability | session identifiers; integrity signals; device/browser metadata; IP address (where needed) | Session / varies | India (primary ops) | No | | Strictly Necessary (Essential) | [Vercel](https://vercel.com) (Website hosting/delivery) | Website delivery, routing, and security controls | Delivery, performance, abuse prevention | IP address; request headers; device/browser metadata | Session / varies | Mumbai region (as stated) | No | | Strictly Necessary (Essential) | [Supabase](https://supabase.com) (Website data platform) | Website-related storage/processing (as implemented) | Website functionality, storage, operations | website usage data; forms/submissions (if collected) | Varies | Mumbai region (as stated) | No | | Strictly Necessary (Essential) | [Upstash](https://upstash.com) (Website infra/data store) | Website queues/storage (as implemented) | Website performance and reliability | website usage data (if collected) | Varies | Mumbai region (as stated) | No | | Analytics (consent-based where required) | [Google Analytics](https://marketingplatform.google.com/about/analytics/) | Website analytics (enabled only if consent is given, where required) | Usage analytics, performance measurement | analytics identifiers; website usage/events (as configured) | Persistent / varies | Provider-controlled / may be multi-region | Yes (where required) | | Analytics (consent-based where required) | [Microsoft Clarity](https://clarity.microsoft.com/) | Website analytics and behavior analysis (enabled only if consent is given, where required) | Session recordings, heatmaps, click/scroll behavior, anonymized usage analytics | analytics identifiers; session/clicks/scroll/interaction data (as configured) | Persistent / varies (for example, `_clck` up to 1 year; `_clsk` session-based; varies by cookie) | Provider-controlled / may be multi-region (`clarity.ms`) | Yes (where required) | **Vendor alignment.** Our customer-facing [Vendor/Subprocessor List](/docs/legal/privacy-policy) is the canonical inventory of vendors/subprocessors used for the Website and Service (as described in our [Privacy Policy](/docs/legal/privacy-policy)). ## CONSENT AND COOKIE SETTINGS [#consent-and-cookie-settings] **Cookie preference controls.** We use cookie preference controls on the Website to let you manage non-essential cookies and similar technologies. **Non-essential disabled by default (where required).** Where required by Applicable Law, non-essential cookies (including analytics cookies) are disabled by default and are enabled only after you provide consent through our cookie preference controls. In particular, [Google Analytics](https://marketingplatform.google.com/about/analytics/) and [Microsoft Clarity](https://clarity.microsoft.com/) are not enabled unless consent is given (where required). **Rejecting non-essential cookies.** You may choose to reject non-essential cookies through the cookie preference controls. If you reject non-essential cookies, we will not enable analytics cookies (including [Google Analytics](https://marketingplatform.google.com/about/analytics/) and [Microsoft Clarity](https://clarity.microsoft.com/)) (where required). **Changing preferences / withdrawing consent.** Where processing is based on consent, you may change your preferences or withdraw consent at any time through the cookie preference controls. Withdrawal does not affect the lawfulness of processing based on consent before withdrawal. ## BROWSER CONTROLS [#browser-controls] Most browsers allow you to manage cookies through your settings, including deleting existing cookies and blocking cookies from being set. Please note that if you block or delete Strictly Necessary (Essential) cookies or similar technologies, parts of the Website or Service may not function properly (for example, login/session stability, security controls, or reliability features). ## VENDOR-SPECIFIC DISCLOSURES [#vendor-specific-disclosures] **Website analytics tools (if enabled).** We use [Google Analytics](https://marketingplatform.google.com/about/analytics/) and [Microsoft Clarity](https://clarity.microsoft.com/) to understand how users interact with our Website through aggregated analytics, session behavior insights, heatmaps, and performance tracking. Analytics data is used to improve user experience and website performance. Where required by Applicable Law, these tools are enabled only after you provide consent through our cookie preference controls. **Google Analytics (if enabled).** Where enabled, [Google Analytics](https://marketingplatform.google.com/about/analytics/) helps us measure Website traffic and usage (for example, page visits, interactions, and usage events) to improve performance and user experience. Where required by Applicable Law, [Google Analytics](https://marketingplatform.google.com/about/analytics/) is enabled only after you provide consent through our cookie preference controls. **Microsoft Clarity (if enabled).** Where enabled, [Microsoft Clarity](https://clarity.microsoft.com/) helps us understand how users interact with the Website through session recordings, heatmaps, click interactions, scroll behavior, and anonymized usage analytics. We do not intentionally capture personally identifiable information through session recordings. Where required by Applicable Law, [Microsoft Clarity](https://clarity.microsoft.com/) is enabled only after you provide consent through our cookie preference controls. **Website delivery and infrastructure providers.** We use providers such as [Vercel](https://vercel.com) (Website hosting/delivery), [Supabase](https://supabase.com) (Website data platform), and [Upstash](https://upstash.com) (Website infrastructure/data store) to deliver and secure the Website and support performance and reliability. These providers may process online identifiers (such as IP address and device/browser metadata) as part of providing these services. **More information.** Our customer-facing [Vendor/Subprocessor List](/docs/legal/privacy-policy) describes our service providers and subprocessors (as further explained in our [Privacy Policy](/docs/legal/privacy-policy)). ## SIMILAR TECHNOLOGIES IN THE SERVICE / SDK [#similar-technologies-in-the-service--sdk] Where applicable, the Service (including the Web SDK) may store or read identifiers locally (for example, using local storage) and may transmit certain technical event parameters to support operation of the Service. These identifiers and parameters may include fields such as `identify_signature`, `ping_on_next_page_visit`, and `ping_again_after` (or similar fields), and are used for purposes such as reliability (including reconnect logic), request throttling/rate-limiting, retries/backoff, integrity and security controls, and diagnostics/analytics (only where enabled and, where required by Applicable Law, based on your consent choices). ## THIRD-PARTY LINKS AND THIRD-PARTY POLICIES [#third-party-links-and-third-party-policies] Our Website or Service may include links to third-party websites, services, or resources. Third parties may have their own cookies or similar technologies, governed by their own privacy and cookie policies. We do not control third-party websites or technologies, and we are not responsible for their privacy practices. ## INTERNATIONAL TRANSFERS [#international-transfers] For the Website, we use providers stated to operate in the Mumbai region for website delivery and storage (as implemented). However, some providers — particularly analytics providers (such as [Google Analytics](https://marketingplatform.google.com/about/analytics/) and [Microsoft Clarity](https://clarity.microsoft.com/), if enabled) — may process data in other regions depending on their infrastructure and your settings. For more detail on international processing, please refer to our [Privacy Policy](/docs/legal/privacy-policy). ## RETENTION [#retention] Cookies and similar technologies may be session-based (deleted when you close your browser) or persistent (remain until deleted or they expire). Retention periods vary by category, provider, and configuration. For clarity, cookie/storage retention described in this Cookie Policy is separate from any Customer Data retention or deletion obligations that may apply under the [DPA](/docs/legal/data-processing-addendum) for Processor-side Processing. ## UPDATES TO THIS COOKIE POLICY [#updates-to-this-cookie-policy] We may update this Cookie Policy from time to time. The “Last Updated” date at the top indicates when this Cookie Policy was last revised. If we make material changes, we will provide notice as required by Applicable Law. ## CONTACT [#contact] If you have questions about this Cookie Policy, please contact us at [privacy@encatch.com](mailto:privacy@encatch.com). # Data Processing Addendum (/docs/legal/data-processing-addendum) # ENCATCH DATA PROCESSING ADDENDUM (DPA) [#encatch-data-processing-addendum-dpa] **Effective Date:** January 1, 2026 **Last Updated:** May 28, 2026 This Data Processing Addendum (“DPA”) forms part of, and is incorporated into, the [Encatch Terms of Service](/docs/legal/terms-of-service) (or other Enterprise Agreement / Order Form) (the “Agreement”) between Phyder Mobile Solutions Pvt. Ltd., a company incorporated in India with its registered office at 412/413, 4th Floor, Palmspring (Above Croma), Link Road, Malad West, Mumbai City, Mumbai, Maharashtra, India, 400064, operating the business and brand name “Encatch” (“Encatch”, “we”, “us” or “our”), and the Customer (as defined in the Agreement). This DPA should be read together with the Agreement and [Encatch’s Privacy Policy](/docs/legal/privacy-policy) (as updated from time to time); however, in the event of any conflict, this DPA controls only with respect to Processor-side Processing of Personal Data covered by this DPA. ## PURPOSE AND SCOPE [#purpose-and-scope] * Purpose. This DPA sets out the parties’ respective obligations with respect to the Processing of Personal Data by Encatch on behalf of Customer in connection with Customer’s use of the Service, to the extent Encatch acts as a Processor (including a “data processor” under the DPDP Act) and Customer acts as a Controller (including a “data fiduciary” under the DPDP Act). * Applicability. This DPA applies only to Processor-side Processing of Personal Data, namely: * Customer End-User Feedback Data and related Customer End User Identifiers (each as defined in the Terms of Service), to the extent such data constitutes Personal Data; and * any other Customer Data only to the extent (and only for so long as) Encatch Processes such Customer Data as a Processor on Customer’s documented instructions under the Agreement. * For clarity, Encatch may process certain data as an independent Controller (for example, account, billing, payment administration, support, sales/marketing, and Website-related data), as described in the Privacy Policy; such Controller-side processing is not governed by this DPA; and this DPA does not apply to Usage Data or other aggregated/de-identified data to the extent it does not constitute Personal Data. * Term. This DPA remains in effect for the duration of Encatch’s Processing of Personal Data on behalf of Customer under the Agreement, and will terminate upon completion of such Processing, subject to Clause 13 and any provisions that are expressly stated to survive. ## INCORPORATION; ORDER OF PRECEDENCE [#incorporation-order-of-precedence] * Incorporation. This DPA is incorporated by reference into, and forms part of, the Agreement and should be read together with Encatch’s Privacy Policy. Capitalized terms not defined in this DPA have the meanings given in the Agreement and/or the Privacy Policy, as applicable. * Precedence. If there is any conflict between this DPA and the Agreement or the Privacy Policy, this DPA will control only with respect to Processor-side Processing of Personal Data to which this DPA applies. For clarity, the Agreement and the Privacy Policy continue to govern (among other things) Encatch’s Controller-side Processing. If Customer has entered into an Enterprise Agreement / Order Form with Encatch that includes data processing terms that expressly override this DPA, those expressly overriding terms will control to the extent of the conflict. * No Expansion of Scope. This DPA does not require either party to Process Personal Data in a manner that is inconsistent with Applicable Data Protection Law. This DPA does not expand Encatch’s obligations beyond the scope of: (a) the Service; (b) Customer’s documented instructions; and (c) Applicable Data Protection Law. ## DEFINED TERMS; INTERPRETATION [#defined-terms-interpretation] * Defined Terms. * Capitalized terms used but not defined in this DPA have the meanings given in the Agreement and/or Encatch’s Privacy Policy, as applicable. Without limiting the foregoing, the terms “Customer Data,” “Customer End-User Feedback Data,” “Customer End User Identifier,” “Service,” and related product/technical terms have the meanings given in the Agreement. * “Personal Data Breach” means any Security Incident (as defined in the Agreement) to the extent it results in the accidental or unlawful destruction, loss, alteration, unauthorized disclosure of, or unauthorized access to, Personal Data Processed under this DPA. * GDPR and DPDP Bridge. For purposes of this DPA, and solely to align terminology across Applicable Data Protection Law: * “Controller” includes “data fiduciary” under the DPDP Act; * “Processor” includes “data processor” under the DPDP Act; and * “Data Subject” includes “Data Principal” under the DPDP Act. * Scope-Limited Use of Privacy Policy Definitions. Where the Privacy Policy defines “Personal Data,” “Processing,” “Controller,” “Processor,” or “Applicable Law” (or similar terms), those definitions apply for purposes of this DPA to the extent relevant to Processor-side Processing covered by this DPA. * Interpretation. In this DPA, unless the context otherwise requires: * references to “include” or “including” mean “include without limitation” / “including without limitation”; * references to “Applicable Data Protection Law” mean the laws and binding regulatory requirements applicable to the Processing of Personal Data under this DPA (including, where applicable, the GDPR and the DPDP Act); and * headings are for convenience only and do not affect interpretation. ## PROCESSING DETAILS (SUBJECT MATTER, DURATION, DATA SUBJECTS AND CATEGORIES) [#processing-details-subject-matter-duration-data-subjects-and-categories] * Subject Matter. The subject matter of Processing under this DPA is Encatch’s provision of the Service to Customer under the Agreement, to the extent Encatch Processes Personal Data as a Processor on Customer’s documented instructions (as described in Clause 5). * Duration. The duration of Processor-side Processing under this DPA is the period described in Clause 1.3, together with any post-termination retention/export periods expressly permitted under the Agreement, the Privacy Policy, and this DPA (including any Retention/Deletion clause), and subject to Applicable Data Protection Law and legal hold. * Nature and Purpose of Processing. The nature and purpose of Processing under this DPA are as described in Clause 1.1 and Clause 1.2, and as further implemented through Customer’s configuration and documented instructions under the Agreement and consistent with the Agreement and Privacy Policy, in each case to the extent applicable to Processor-side Processing. * Categories of Data Subjects. Personal Data processed under this DPA may relate to: * Customer End Users; and * Customer’s Authorized Users and other individuals whose Personal Data is included in Customer Data submitted to the Service, in each case, to the extent such data constitutes Personal Data and is Processed by Encatch as a Processor under this DPA. * Categories of Personal Data. The categories of Personal Data processed under this DPA may include, to the extent configured and provided by Customer: * Customer End-User Feedback Data (including survey responses, ratings, selections, free-text inputs, bug reports, and similar submissions); * Customer End User Identifiers (for example, user IDs, email addresses, phone numbers, or hashed identifiers) and related workspace/project identifiers; * metadata associated with submissions and events (for example, timestamps and device/app/session context to the extent enabled by Customer); and * attachments or files submitted through feedback flows, only if enabled by Customer. * Special Categories / Sensitive Data. Customer will not (and will not permit Customer End Users or Authorized Users to) submit, upload, transmit, or otherwise make available through the Service any Sensitive Data. Encatch does not monitor, screen, or filter Customer Data processed on Customer instruction to detect or prevent submission of Sensitive Data. Customer is responsible for configuring its feedback flows, forms, fields/prompts, and SDK/API implementations (and for providing required notices and obtaining required consents/authorizations) to minimize and avoid the collection of Sensitive Data through the Service. If Customer anticipates that Sensitive Data may be processed through the Service (whether intentionally or inadvertently), Customer must promptly notify Encatch, and any such Processing (if any) will be subject to Applicable Data Protection Law and any additional written agreement between the parties. ## ROLES AND DOCUMENTED INSTRUCTIONS [#roles-and-documented-instructions] * Roles of the Parties. For purposes of Processor-side Processing under this DPA: * Customer acts as a Controller (including a “Data Fiduciary” under the DPDP Act) with respect to Personal Data; and * Encatch acts as a Processor (including a “Data Processor” under the DPDP Act) with respect to such Personal Data. Nothing in this DPA modifies the parties’ respective roles where Encatch Processes data as an independent Controller, as described in the Privacy Policy. * Documented Instructions. Encatch will Process Personal Data only on Customer’s documented instructions, which consist of: * the Agreement; * this DPA; * Customer’s configuration and use of the Service (including settings, integrations, workflows, identifiers, and AI feature usage); and * any additional written instructions provided by Customer and agreed by Encatch, to the extent consistent with the Agreement and Applicable Data Protection Law. Encatch will inform Customer if, in its reasonable opinion, an instruction infringes Applicable Data Protection Law. * Compliance with Law. Notwithstanding the foregoing, Encatch may Process Personal Data to the extent required by Applicable Data Protection Law to which Encatch is subject. In such case, Encatch will (unless legally prohibited) inform Customer of that legal requirement before Processing. * Customer Responsibility for Instructions. Customer is solely responsible for: * determining the lawfulness, scope, and appropriateness of its instructions; * ensuring that it has provided all required notices and obtained all required consents or other lawful bases under Applicable Data Protection Law; and * ensuring that its configuration and use of the Service (including the submission of identifiers, integrations, attachments, and any use of AI Features) complies with Applicable Data Protection Law. ## CUSTOMER OBLIGATIONS [#customer-obligations] * Compliance as Controller / Data Fiduciary. Customer is responsible for complying with Applicable Data Protection Law in its capacity as Controller (including as a Data Fiduciary under the DPDP Act) with respect to Personal Data Processed under this DPA, including by: * establishing and maintaining a valid lawful basis (and, where required, providing notices and obtaining consents/authorizations) for the collection, use, and disclosure of such Personal Data to Encatch for Processing under the Agreement and this DPA; * providing all required disclosures to, and enabling the exercise of rights by, the relevant Data Subjects / Data Principals (including Customer End Users), and maintaining appropriate records and policies as required by Applicable Data Protection Law; and * responding to Data Subject / Data Principal requests, complaints, or inquiries in the first instance (with Encatch assistance only as set out in this DPA). * Configuration, Data Minimization, and Content Controls. Customer is solely responsible for its configuration and use of the Service, including the design and operation of its feedback flows, forms, fields/prompts, SDK/API implementations, integrations, workflows, identifiers, and any attachment/file enablement. Customer will: * limit the Personal Data submitted to the Service to what is necessary for Customer’s intended purposes (data minimization); and * ensure that any identifiers, tags, custom fields, prompts, and integrations used by Customer do not cause Customer End Users or Authorized Users to submit Sensitive Data or other prohibited content through the Service, except as expressly permitted under the Agreement and this DPA (and only where Customer has satisfied all requirements under Applicable Data Protection Law). * Sensitive Data. Customer will comply with the Sensitive Data restrictions set out in Clause 4.6 (Special Categories / Sensitive Data). * Accuracy; Authority for Disclosures. Customer is responsible for the accuracy, quality, and legality of Personal Data and other Customer Data submitted to the Service and for ensuring that it has the necessary rights, permissions, and authority to disclose such data to Encatch for Processing under the Agreement and this DPA (including where Customer imports data via integrations or SDK/API implementations). * Customer Security Responsibilities. Customer will implement and maintain appropriate technical and organizational measures on its side to protect Personal Data, including: * maintaining appropriate access controls and credential hygiene for Customer accounts and Authorized Users; * limiting access to the Service to Authorized Users with a need-to-know; and * taking reasonable steps to secure end-user collection points, devices, and environments that interact with the Service (including SDK/API implementations and any integrated systems), and promptly notifying Encatch of any unauthorized access to Customer’s credentials or workspace that may impact Personal Data processed under this DPA. ## ENCATCH OBLIGATIONS AS PROCESSOR [#encatch-obligations-as-processor] * Processing on Instructions. Encatch will Process Personal Data only in accordance with Customer’s documented instructions as set out in Clause 5.2, unless Processing is required by Applicable Data Protection Law as set out in Clause 5.3. * Confidentiality of Personnel. Encatch will ensure that its personnel and any persons authorized to Process Personal Data on its behalf (including contractors) are subject to appropriate confidentiality obligations (contractual or statutory) and access controls, and are permitted to Process Personal Data only to the extent necessary to provide the Service and perform Encatch’s obligations under the Agreement and this DPA. * Appropriate Technical and Organisational Measures. Encatch will implement and maintain appropriate technical and organisational measures to protect Personal Data against accidental or unlawful destruction, loss, alteration, unauthorized disclosure, or access, as further set out in the Security Measures clause (and any related Annex) of this DPA. * Assistance With Data Subject / Data Principal Rights. Taking into account the nature of the Processing and the information available to Encatch, Encatch will provide reasonable assistance to Customer to enable Customer to respond to Data Subject / Data Principal requests in relation to Personal Data Processed under this DPA, to the extent required by Applicable Data Protection Law and subject to: (a) verification of the request; (b) Customer providing sufficient information to locate the relevant data; (c) security and confidentiality requirements; and (d) reasonable limitations and/or costs and fees for excessive or disproportionate requests (including by scope or frequency). * Assistance With Compliance. To the extent required by Applicable Data Protection Law and reasonably feasible, Encatch will provide reasonable assistance to Customer with Customer’s compliance obligations relating to: (a) security of Processing; (b) notification of Personal Data Breaches; and (c) data protection impact/risk assessments and prior consultations with a supervisory authority, in each case solely to the extent the underlying Processing is Processor-side Processing under this DPA. * Inability to Comply. If Encatch becomes aware that it cannot comply with Customer’s documented instructions or its obligations under this DPA due to Applicable Data Protection Law, legal requirements, or technical limitations of the Service, Encatch will promptly inform Customer and, where applicable, work with Customer in good faith to identify a compliant alternative within the Service (without committing to any feature, routing, or provider alternatives unless expressly agreed in writing). * No Modification of Controller-Side Processing. Nothing in this Clause 7 modifies Encatch’s Controller-side Processing described in the Privacy Policy, which remains governed by the Agreement and the Privacy Policy (and not by this DPA). ## SECURITY MEASURES (TECHNICAL AND ORGANISATIONAL MEASURES) [#security-measures-technical-and-organisational-measures] * Security Measures. Encatch will implement and maintain appropriate technical and organisational measures designed to protect Personal Data Processed under this DPA against accidental or unlawful destruction, loss, alteration, unauthorized disclosure, or unauthorized access (the “Security Measures”), taking into account: (a) the nature, scope, context, and purposes of Processing; (b) the risks to Data Subjects / Data Principals; and (c) the state of the art, implementation costs, and the nature of the Service. * Minimum Controls. Without limiting Clause 8.1, Encatch’s Security Measures include controls reasonably designed to address, as applicable: * access controls and authentication (including role-based access and least-privilege principles for personnel access); * logical separation and environment controls appropriate to the Service architecture; * encryption and/or other protections for data in transit and at rest, as appropriate to the risk and the Service; * logging and monitoring to support security, auditing, troubleshooting, and incident response; * vulnerability management and patching practices consistent with reasonable industry standards; * backup and recovery practices to support availability and resilience, consistent with the Agreement, Privacy Policy, and this DPA; * secure development and change management practices appropriate to the Service; and * personnel security (including confidentiality obligations and security awareness measures appropriate to roles). * Security Annex. Additional details of the Security Measures may be described in Annex 2 (Security Measures) to this DPA and/or in security documentation made available by Encatch from time to time. Annex 2 and such documentation are incorporated into this DPA to the extent they describe Encatch’s Security Measures for Processor-side Processing under this DPA. * Updates and Improvement. Encatch may update or modify the Security Measures from time to time, provided that such updates do not materially reduce the overall level of protection for Personal Data Processed under this DPA, taking into account the nature of the Service and the risks presented by the Processing. * Customer Responsibilities; Shared Security. Customer acknowledges that security is a shared responsibility. Customer remains responsible for implementing and maintaining appropriate technical and organisational measures on its side (including as described in Clause 6.5), and for securing its environments, devices, SDK/API implementations, integrations, and Authorized User access credentials. Encatch is not responsible for security incidents caused by Customer’s acts or omissions, Customer’s configuration choices, or Customer-controlled systems, except to the extent caused by Encatch’s failure to implement or maintain the Security Measures required under this DPA. * No Guarantee. Customer acknowledges that no security measures are perfect or impenetrable. Encatch does not guarantee that unauthorized access, loss, or alteration will never occur, but Encatch will maintain the Security Measures in accordance with this Clause 8 and will respond to Security Incidents in accordance with the Security Incident / Breach Notification clause of this DPA. ## SECURITY INCIDENT / PERSONAL DATA BREACH NOTIFICATION [#security-incident--personal-data-breach-notification] * Notification of Confirmed Security Incident. Encatch will notify Customer without undue delay, and where feasible within seventy-two (72) hours after confirmation of a Security Incident (as defined in the Agreement) to the extent it constitutes a Personal Data Breach (as defined in Clause 3.1(b)). * Content in Notice. Encatch’s notice will include, to the extent known and reasonably available at the time (and may be provided in phases as information becomes available): * the nature of the Personal Data Breach (including, where feasible, the categories and approximate number of Data Subjects / Data Principals concerned and the categories and approximate number of Personal Data records concerned); * the likely consequences of the Personal Data Breach; and * the measures taken or proposed to be taken by Encatch to address the Personal Data Breach, including (where appropriate) measures to mitigate its possible adverse effects. * Investigation and Mitigation. Encatch will take reasonable steps to investigate, contain, remediate, and mitigate the effects of the Personal Data Breach and to restore the security of the affected systems, consistent with the nature of the Service and the risks presented. * Customer Notifications and Regulatory Reporting. Customer is responsible for determining whether, and to what extent, any notification to Data Subjects / Data Principals, regulators, or other third parties is required under Applicable Data Protection Law, and for making any such notifications. Encatch will provide reasonable cooperation to Customer in connection with such notifications to the extent the Personal Data Breach relates to Processor-side Processing under this DPA. * Legal Restrictions. Encatch’s notification obligations under this Clause 9 will not apply (or may be delayed) to the extent Encatch is legally prohibited from providing notice (including where a law enforcement request requires delay). In such case, Encatch will provide notice as soon as it is legally permitted to do so. * No Admission. Encatch’s notification of a Security Incident / Personal Data Breach under this Clause 9 will not be construed as an acknowledgment of fault or liability by Encatch. ## SUBPROCESSORS [#subprocessors] * General Authorisation. Customer provides Encatch with a general authorisation to engage Subprocessors to Process Personal Data on Customer’s behalf for the purpose of providing, securing, supporting, and operating the Service, subject to the terms of this DPA. * Subprocessor List (Annex 3). The Subprocessors authorised under this DPA as of the Effective Date are listed in Annex 3 (Subprocessors). Customer acknowledges and agrees that Encatch may update Annex 3 from time to time and will provide notice where required under Clause 10.4 and/or Applicable Data Protection Law. Encatch will make the then-current Annex 3 available to Customer on request (and/or via a DPA portal or within the Service, where Encatch maintains such a list). * Subprocessor Obligations. Where Encatch engages a Subprocessor to Process Personal Data under this DPA, Encatch will: (a) enter into a written agreement with such Subprocessor that imposes data protection obligations that are no less protective than those set out in this DPA (to the extent applicable to the Subprocessor’s Processing); and (b) remain responsible for the performance of the Subprocessor’s obligations to the extent required under Applicable Data Protection Law. * Customer Objection; Resolution; Integral Subprocessors. * Where Applicable Data Protection Law provides Customer a right to object to a new Subprocessor, Customer may submit a written objection on reasonable grounds relating to data protection (an “Objection”) within the objection period specified in Encatch’s notice (or, if no period is specified, within a reasonable period after such notice). * If Customer raises an Objection, the parties will discuss in good faith a commercially reasonable resolution. Without limiting the foregoing, Encatch may, at its option: (i) take reasonable steps to address Customer’s Objection (including by providing additional information about the Subprocessor and the safeguards in place); or (ii) where reasonably feasible within the Service, refrain from using the relevant Subprocessor for Customer’s Personal Data. * Integral Subprocessors. If Customer objects to a Subprocessor that is integral to a specific feature or functionality of the Service (including an AI model provider used to provide an AI Feature), and Encatch cannot reasonably accommodate the Objection within the Service without materially impairing such feature or functionality, Encatch may, at its option: (i) disable or terminate the affected feature, functionality, plan component, Order Form, or impacted portion of the Service for Customer; and only if neither of the foregoing is reasonably feasible, (ii) terminate the Agreement in accordance with its termination provisions. ## INTERNATIONAL TRANSFERS [#international-transfers] * Transfers Generally. Customer acknowledges that, depending on the configuration and use of the Service, Personal Data Processed under this DPA may be transferred to, accessed from, or otherwise Processed in jurisdictions other than the jurisdiction where Customer or the relevant Data Subjects / Data Principals are located, including due to: (a) hosting or infrastructure locations; (b) support and maintenance access; and/or (c) Subprocessors engaged under Clause 10. * Standard Contractual Clauses; UK Addendum (Deemed Incorporated). * EEA Transfers. To the extent Encatch Processes Personal Data subject to the GDPR and such Processing involves a transfer of that Personal Data to a country that is not subject to an adequacy decision under applicable law, the EU Standard Contractual Clauses (Commission Implementing Decision (EU) 2021/914) (the “EU SCCs”) are incorporated by reference into this DPA and are deemed entered into by the Parties, and will apply automatically to the relevant transfer(s), as follows: (i) where Customer is a Controller and Encatch is a Processor, Module Two (Controller to Processor) applies; and (ii) where Customer is a Processor and Encatch is a Processor, Module Three (Processor to Processor) applies, in each case as further completed in Annex 4. * UK Transfers. To the extent Encatch Processes Personal Data subject to UK GDPR and such Processing involves a restricted transfer, the UK Addendum to the EU SCCs (the “UK Addendum”) is incorporated by reference into this DPA and is deemed entered into by the Parties, and will apply automatically to the relevant transfer(s), as further completed in Annex 4. * Order of Precedence. If there is any conflict or inconsistency between the EU SCCs / UK Addendum and this DPA, the EU SCCs / UK Addendum (as applicable) will prevail solely to the extent of that conflict for the relevant transfer(s). Otherwise, this DPA remains in full force and effect. * Operationalization. The Parties agree that the information required to complete the Annexes to the EU SCCs / UK Addendum is set out in Annex 4 to this DPA, and that Customer’s acceptance of this DPA (including by clickwrap or electronic acceptance) constitutes Customer’s execution of the EU SCCs and/or UK Addendum (as applicable) to the extent they apply. * Other international transfers (including DPDP Act). Where Encatch Processes Personal Data subject to Applicable Data Protection Laws other than GDPR/UK GDPR (including the Digital Personal Data Protection Act, 2023 (India), where applicable) and such Processing involves cross-border transfers, the Parties will comply with any applicable cross-border transfer requirements under such laws, including implementing any lawful transfer mechanism or safeguards required under those laws, to the extent applicable. * Deemed / Documented Instructions for Feature-Driven Transfers (Including AI). Customer’s configuration and use of the Service (including use of any AI Features) constitutes Customer’s documented instruction for Encatch and its Subprocessors to Process and, where applicable, transfer AI Inputs and other Customer Data submitted for such features in the jurisdictions where the relevant Subprocessors operate, subject to any transfer safeguards required by Applicable Data Protection Law. * Customer Responsibilities. Customer is responsible for assessing and ensuring that its own instructions, configuration, and use of the Service (including enabling integrations, selecting data fields/prompts, submitting identifiers, and using AI Features) comply with Applicable Data Protection Law, including any restrictions or conditions relating to cross-border transfers that apply to Customer as Controller / Data Fiduciary. ## AI PROCESSING (PROCESSOR-SIDE) [#ai-processing-processor-side] * Scope. To the extent Encatch Processes Personal Data as a Processor through or in connection with AI Features (as defined in the Agreement) and AI Inputs (as defined in Encatch’s Privacy Policy), such Processing is subject to this Clause 12 and the other terms of this DPA. * No Training by Encatch. Encatch will not use Personal Data Processed under this DPA (including AI Inputs to the extent they constitute Personal Data) to train, fine-tune, or improve Encatch’s models, except where Customer has expressly agreed in writing. * Third-Party AI Providers. Where Encatch uses Subprocessors (including AI model providers) to provide AI Features, Encatch will (a) contractually restrict such Subprocessors to Processing Personal Data only as necessary to provide the AI Features and related support, and (b) where available, use provider settings and/or contractual terms intended to restrict the Subprocessor’s use of Customer Data for model training or improvement. * Customer Control Posture. Customer controls what Customer Data (if any) is submitted, routed, or otherwise made available for AI-assisted Processing within the Service through Customer’s configuration and use of the Service (including workflows, integrations, prompts/fields, identifiers, attachment settings, and user permissions). Customer is responsible for ensuring that its configuration and use of AI Features complies with Applicable Data Protection Law, including providing required notices and obtaining required consents/authorizations. * Outputs and Responsibility. Customer acknowledges that AI Features may generate outputs based on AI Inputs and other data made available through Customer’s configuration and use of the Service. Customer remains responsible for reviewing outputs for accuracy, appropriateness, and compliance with Applicable Data Protection Law and Customer’s obligations to Data Subjects / Data Principals. ## RETENTION, DELETION, AND RETURN [#retention-deletion-and-return] * Termination; Deletion Requests. Upon termination or expiry of the Agreement, and subject to Customer’s documented instructions, Encatch will (within a reasonable period) delete or return Customer Data containing Personal Data Processed under this DPA, except to the extent Encatch is permitted or required to retain such data under the Agreement, the Privacy Policy, this DPA, Applicable Data Protection Law, or legal hold. * Post-Termination Retention (Customer Data). During the term of the Agreement, retention of Customer Data containing Personal Data within the Service follows Customer’s documented instructions and configuration choices, including any Plan-based retention settings permitted under the Agreement. Following termination or expiration of the Agreement, Encatch may retain Customer Data for up to sixty (60) days (or such other period expressly permitted under the Agreement and/or Privacy Policy) to allow Customer to export or retrieve Customer Data, after which Encatch will delete or de-identify Customer Data from active systems in accordance with its standard deletion practices, subject to Clause 13.3 (Backups) and Clause 13.5 (Legal Hold and Residual Retention). For clarity, this Clause 13 applies only to Customer Data to the extent it constitutes Personal Data and is Processed by Encatch as a Processor under this DPA. * Backups. Customer Data containing Personal Data Processed under this DPA that is deleted from active systems may remain in backups for up to forty-five (45) days, after which it will be deleted in accordance with Encatch’s backup deletion cycles, except to the extent required by Applicable Data Protection Law or legal hold. * Operational Logs (Including AI Invocation Logs). Customer acknowledges that Encatch may generate and retain operational logs for security, auditing, troubleshooting, fraud prevention, and service integrity. To the extent such logs contain Personal Data Processed under this DPA: * Encatch will generally discard such log data from active records within approximately one (1) month; and * such log data may remain in backups for up to ninety (90) days, in each case subject to Clause 13.5 and Applicable Data Protection Law. * Legal Hold and Residual Retention. Notwithstanding the foregoing, Encatch may retain Personal Data to the extent required by Applicable Data Protection Law or a valid legal process, or as necessary to establish, exercise, or defend legal claims, and will isolate and protect such retained data from further Processing except as required for the applicable legal purpose. * Deletion Method; Residual Copies. Deletion under this Clause 13 means rendering Personal Data irretrievable from active systems in accordance with Encatch’s standard deletion practices, and does not require deletion from backups until completion of the applicable backup purge cycle described above. Encatch is not required to delete residual copies of Personal Data from archives or disaster recovery systems earlier than those cycles, provided such data is not accessed or used except for restoration/testing, legal compliance, or security purposes. * Deletion of Sensitive Data. If Customer becomes aware that Sensitive Data has been submitted through the Service in breach of Clause 4.6, Customer will promptly notify Encatch. Encatch will use commercially reasonable efforts to assist Customer in deleting such Sensitive Data from active systems, subject to the technical limitations of the Service and backup deletion cycles, and subject to Applicable Data Protection Law and legal hold. * Certification (On Request). On Customer’s reasonable written request and only where required by the Applicable Data Protection Law, Encatch will provide a written confirmation that deletion and/or return under this Clause 13 has been completed in accordance with this DPA, subject to reasonable confidentiality and security restrictions. ## AUDIT / COMPLIANCE DEMONSTRATION [#audit--compliance-demonstration] * Compliance Information. Upon Customer’s reasonable written request, Encatch will make available to Customer information reasonably necessary to demonstrate Encatch’s compliance with this DPA with respect to Processor-side Processing, which may include: (a) written responses to reasonable security and privacy questionnaires; (b) summaries of Encatch’s Security Measures and policies relevant to Processor-side Processing; and (c) where available, independent audit reports, attestations, or certifications (if any), in each case subject to confidentiality restrictions and appropriate redactions. * Audit Rights; Conditions. To the extent required by Applicable Data Protection Law, Customer (or an independent third-party auditor appointed by Customer) may conduct an audit of Encatch’s Processor-side Processing under this DPA, subject to all of the following conditions: * Scope. The audit must be limited to Processor-side Processing of Personal Data under this DPA and must not unreasonably interfere with Encatch’s business or compromise the security of other customers’ data or Encatch systems. * Notice and Timing. Customer must provide at least thirty (30) days’ prior written notice (unless a shorter period is required by Applicable Data Protection Law or a competent supervisory authority), and audits will be conducted during normal business hours. * Frequency. No more than one (1) audit in any twelve (12) month period, unless (i) required by Applicable Data Protection Law; or (ii) a confirmed Personal Data Breach has occurred and the audit is limited to matters reasonably related to that breach. * Auditor Requirements. Any third-party auditor must be independent, bound by confidentiality obligations no less protective than those in the Agreement/DPA, and must not be a competitor of Encatch. * Confidentiality and Security. Audit activities and results are Confidential Information. Encatch may require reasonable security controls for the audit, including access limitations, identity verification, and restrictions on copying, scanning, or recording. * Costs. Customer will bear its own audit costs and will reimburse Encatch for reasonable time and expenses incurred in supporting the audit (including for personnel time), except to the extent Applicable Data Protection Law requires otherwise. * Alternative to On-Site Audits. Before conducting any on-site audit, Customer will first use the mechanisms in Clause 14.1 (documentation, security summaries, written responses, and available third-party reports). Where those mechanisms reasonably demonstrate compliance, Customer will not require an on-site audit. * Supervisory Authority Requests. Nothing in this Clause 14 limits Encatch’s ability to cooperate with a competent supervisory authority or regulator. Where Encatch is legally permitted, Encatch will notify Customer of any supervisory authority audit or request relating specifically to Customer’s Processor-side Processing under this DPA. ## LIABILITY; RELATIONSHIP TO AGREEMENT [#liability-relationship-to-agreement] * Relationship to Agreement; No Expansion. This DPA is subject to the Agreement. Nothing in this DPA: (a) expands Encatch’s obligations beyond the scope of the Service, Customer’s documented instructions, and Applicable Data Protection Law; or (b) creates any obligation for Encatch to provide features, configurations, routing, or alternative providers beyond what is provided under the Service and the Agreement, unless expressly agreed in writing. * Liability Limits Apply. To the maximum extent permitted by Applicable Data Protection Law, all claims, damages, liabilities, costs, and expenses arising out of or relating to this DPA (including any Personal Data Breach or other claim relating to Processor-side Processing under this DPA) are subject to the exclusions, limitations of liability, and caps set out in the Agreement, unless an Enterprise Agreement / Order Form expressly overrides those limitations for the Customer. * No DPA “Backdoor”. Customer agrees that this DPA does not create any separate or additional right to recover damages, compensation, or other remedies beyond those available under the Agreement. For clarity, Customer may not avoid or circumvent the liability limitations in the Agreement by bringing a claim under this DPA. * Allocation of Responsibility. Customer remains responsible for: (a) the lawfulness of its instructions and configuration; (b) providing required notices and obtaining required consents/authorizations; and (c) Customer-controlled systems, integrations, SDK/API implementations, and end-user collection points. Encatch is responsible for implementing and maintaining the Security Measures and meeting its Processor obligations under this DPA to the extent applicable to Processor-side Processing. * No Limitation Where Prohibited. Nothing in this DPA limits liability to the extent such limitation is prohibited by Applicable Data Protection Law. ## GENERAL [#general] * Governing Law; Venue. This DPA is governed by, and will be interpreted in accordance with, the governing law and dispute resolution provisions set out in the Agreement. * Notices. Notices under this DPA will be given in accordance with the notices provisions in the Agreement. * Assignment. This DPA may not be assigned except as permitted under the Agreement. Any permitted assignment of the Agreement will include assignment of this DPA. * Severability. If any provision of this DPA is held invalid or unenforceable, the remaining provisions will remain in full force and effect, and the parties will substitute a valid and enforceable provision that most closely reflects the original intent. * Survival. Clauses that by their nature should survive termination or expiry of the Agreement (including Clauses 10–16 and any provisions relating to confidentiality, security, retention/deletion, audit, liability, and interpretation) will survive. * Acceptance; Electronic Assent. This DPA is incorporated into the Agreement and becomes binding on Customer when: (a) Customer (or an Authorized User acting on Customer’s behalf) clicks to accept the Agreement (or an Order Form / Enterprise Agreement that incorporates this DPA); (b) Customer accesses or uses the Service in a manner that indicates acceptance of the Agreement; or (c) the parties otherwise agree in writing that this DPA applies. Where this DPA applies, Customer’s continued access to or use of the Service after any update to this DPA constitutes acceptance of the updated DPA as of its effective date, subject to the Agreement’s modification and notice terms. * Entire Agreement (Processor-Side). This DPA, together with the Agreement and the Privacy Policy (as applicable), constitutes the entire agreement between the parties with respect to Processor-side Processing of Personal Data covered by this DPA, and supersedes any prior or contemporaneous understandings on that subject matter. ## ANNEX 1 DETAILS OF PROCESSING [#annex-1-details-of-processing] This Annex 1 forms part of the Encatch Data Processing Addendum (DPA) and describes the Processing of Personal Data by Encatch as a Processor on behalf of Customer in connection with the Service. * Subject Matter of Processing Encatch’s provision of the Service to Customer under the Agreement, only to the extent Encatch Processes Personal Data as a Processor on Customer’s documented instructions (as described in Clause 5) and such Processing constitutes Processor-side Processing covered by the DPA. * Duration of Processing Processing will continue for the term of the Agreement and, where applicable, for any post-termination retention, deletion, backup, or export periods permitted under the Agreement, the DPA (including the Retention/Deletion clause), and the Privacy Policy, subject to Applicable Data Protection Law and legal hold requirements. * Nature and Purpose of Processing * The nature and purpose of Processing is to host, store, transmit, organize, analyze, route, tag, troubleshoot, and otherwise Process Personal Data as necessary to provide, maintain, secure, and support the Service in accordance with Customer’s configuration and documented instructions. * This may include the generation of analytics, dashboards, automations, and (where invoked through Customer’s configuration and use of the Service) AI-assisted outputs, in each case as described in the Agreement and Privacy Policy and limited to Processor-side Processing under the DPA. * Categories of Data Subjects Personal Data Processed under the DPA may relate to: * Customer End Users; * Customer’s Authorized Users (as defined in the Agreement); and * other individuals whose Personal Data is included in Customer Data submitted to the Service, in each case to the extent such data constitutes Personal Data and is Processed by Encatch as a Processor. * Categories of Personal Data Depending on Customer’s configuration and the Customer Data submitted to the Service, Personal Data Processed may include: * Customer End-User Feedback Data (including survey responses, ratings, selections, free-text inputs, bug reports, and similar submissions); * Customer End User Identifiers (such as user IDs, email addresses, phone numbers, or hashed identifiers) and related workspace/project identifiers; * metadata associated with submissions and events (including timestamps, device/app/session context, and similar properties to the extent enabled by Customer); and * attachments or files submitted through feedback flows, if enabled by Customer, in each case, to the extent such data constitutes Personal Data and is Processed by Encatch as a Processor under the DPA. * Sensitive Data Customer will not submit (and will not permit Customer End Users or Authorized Users to submit) Sensitive Data through the Service. Encatch does not monitor or filter Customer Data for Sensitive Data. If Customer anticipates that Sensitive Data may be Processed, Customer must notify Encatch and any such Processing (if any) will be subject to Applicable Data Protection Law and any additional written agreement between the parties, in each case only to the extent such Processing constitutes Processor-side Processing covered by the DPA. * Processing Locations and Transfers Processing may be carried out by Encatch and its authorized Subprocessors in jurisdictions in which they operate, in each case in accordance with Clause 11 (International Transfers), the safeguards described in the DPA, and Applicable Data Protection Law. ## ANNEX 2 SECURITY MEASURES (TECHNICAL AND ORGANISATIONAL MEASURES) [#annex-2-security-measures-technical-and-organisational-measures] This Annex 2 forms part of the Encatch Data Processing Addendum (DPA) and describes Encatch’s technical and organisational measures (“Security Measures”) designed to protect Personal Data Processed under the DPA against accidental or unlawful destruction, loss, alteration, unauthorized disclosure, or unauthorized access. These Security Measures reflect Encatch’s current practices as of the Effective Date and may be updated from time to time in accordance with Clause 8.4 of the DPA, provided that updates do not materially reduce the overall level of protection for Personal Data Processed under the DPA. * Information Security Governance * Encatch maintains internal security policies and procedures designed to address confidentiality, integrity, and availability of systems and data. * Access to Personal Data is limited to personnel with a legitimate business need, subject to role-based access controls and least-privilege principles. * Encatch maintains an incident response process for detection, investigation, containment, remediation, and post-incident review of security incidents. * Access Controls and Authentication * Administrative access to systems that Process Personal Data is restricted to authorized personnel only. * Strong authentication controls are implemented for privileged access (for example, multi-factor authentication where supported). * Logical access is managed through role-based access control and access provisioning/deprovisioning processes. * Access rights are reviewed periodically and adjusted as needed based on role changes and operational needs. * Encryption and Key Management * Personal Data is protected in transit using industry-standard encryption protocols (for example, TLS). * Personal Data stored in production systems is protected using encryption at rest where appropriate to the risk and architecture. * Encryption keys are managed using reasonable security controls to limit access and reduce risk of unauthorized disclosure. * Network Security and Perimeter Controls * Encatch uses network security controls appropriate to the Service architecture (for example, firewalling, security groups, and segmentation where applicable). * Administrative interfaces and sensitive endpoints are restricted and protected against unauthorized access. * Remote administrative access (where used) is protected using secure methods and access restrictions. * Logging, Monitoring, and Detection * Encatch maintains logging for key security-relevant events to support troubleshooting, auditing, and incident response. * Monitoring controls are used to detect anomalous behavior and security events where reasonable for the Service. * Logs are protected from unauthorized access and modification and retained in accordance with the DPA’s Retention/Deletion provisions where applicable. * Vulnerability Management and Patching * Encatch maintains processes to identify and remediate security vulnerabilities in systems used to provide the Service. * Patches and updates are applied on a risk-based basis, taking into account severity and operational impact. * Encatch uses reasonable practices to reduce exposure to known vulnerabilities, consistent with industry norms for SaaS services. * Secure Development and Change Management * Encatch maintains development and change management practices intended to support secure software delivery (for example, peer review or approvals for material changes, environment separation where applicable). * Production deployments are controlled and restricted to authorized personnel. * Where appropriate, Encatch uses testing and validation practices to reduce the risk of introducing security regressions. * Data Segregation and Tenant Controls * Encatch maintains logical controls designed to prevent unauthorized access across customer workspaces/tenants. * Access to customer environments is restricted based on authorization and operational need. * Backup, Recovery, and Resilience * Encatch maintains backup and recovery practices intended to support availability and restore data after certain operational failures, consistent with the Service architecture. * Backup retention and purge cycles are handled in accordance with the DPA’s Retention/Deletion clause and operational constraints. * Physical and Environmental Security * Where Encatch uses third-party hosting or cloud infrastructure providers, physical and environmental security controls are provided by those providers within their managed facilities. * Encatch limits physical access to any Encatch-controlled work environments used to access production systems through reasonable controls. * Personnel Security and Confidentiality * Encatch ensures personnel with access to Personal Data are subject to confidentiality obligations (contractual or statutory). * Encatch uses reasonable onboarding and offboarding procedures to manage access to systems and data. * Security awareness practices are implemented in a manner appropriate to personnel roles and responsibilities. * Subprocessor Security Flow-Down Where Encatch engages Subprocessors to Process Personal Data, Encatch requires Subprocessors to implement security measures that are no less protective than those set out in the DPA, to the extent applicable to their Processing. * Customer Responsibilities (Shared Security) Customer acknowledges that security is a shared responsibility. Customer is responsible for implementing and maintaining appropriate security measures on its side, including securing Authorized User credentials, endpoint devices, integrations, SDK/API implementations, and end-user collection points, and for configuring the Service to minimize risk (including avoiding collection of Sensitive Data). * Limitations These Security Measures are designed to reduce risk, but no system can be guaranteed to be fully secure. Encatch does not warrant or guarantee that unauthorized access, loss, or alteration will never occur. ## ANNEX 3 SUBPROCESSORS [#annex-3-subprocessors] This Annex 3 forms part of the Encatch Data Processing Addendum (DPA) and identifies Subprocessors authorised to Process Personal Data on behalf of Customer under the DPA. * Subprocessor List Available on Request Encatch maintains a list of its then-current Subprocessors authorised to Process Personal Data under the DPA (including, where applicable, categories of Subprocessors and the nature/purpose of their Processing). Encatch will make the then-current Subprocessor list available to Customer on request. * How to Request the List Customer may request the then-current Subprocessor list by contacting: [privacy@encatch.com](mailto:privacy@encatch.com) * Updates. Encatch may update its Subprocessors from time to time in accordance with the DPA (including Clause 10). Where required under the DPA and/or Applicable Data Protection Law, Encatch will provide notice of material Subprocessor changes and permit objections in accordance with Clause 10.4 of the DPA. ## ANNEX 4 INTERNATIONAL TRANSFERS (EU SCCs & UK ADDENDUM) [#annex-4-international-transfers-eu-sccs--uk-addendum] This Annex 4 forms part of the Encatch Data Processing Addendum (“DPA”). It describes the transfer safeguards that apply where required for Restricted Transfers under Applicable Data Protection Laws. * Incorporation and deemed execution * Incorporation by reference. Where required for a Restricted Transfer, the EU Standard Contractual Clauses (Commission Implementing Decision (EU) 2021/914) (“EU SCCs”) and, where applicable, the UK Addendum to the EU SCCs (“UK Addendum”) are incorporated into this DPA by reference and are deemed entered into by the Parties solely for the relevant Restricted Transfer(s). * Deemed signature / clickwrap. Customer’s acceptance of the DPA (including by clickwrap or electronic acceptance) is deemed to constitute Customer’s execution of the EU SCCs and/or the UK Addendum (as applicable), without requiring any separate signature. * Exporter identity. For purposes of the EU SCCs/UK Addendum, the data exporter is Customer as identified in the Customer account, Order Form, or other ordering record associated with Customer’s use of the Service. * Importer identity. The data importer is: Phyder Mobile Solutions Pvt. Ltd. (Encatch). * Precedence (transfer-only). If there is a conflict between the EU SCCs/UK Addendum and this DPA, the EU SCCs/UK Addendum will prevail solely to the extent required for the relevant transfer(s). Otherwise, this DPA remains in effect. * EU SCCs (2021/914) — Completion Information * Module selection. * Default: Module Two (Controller → Processor) applies where Customer is a Controller and Encatch is a Processor. * Alternative: Module Three (Processor → Processor) applies where Customer is a Processor and Encatch is a Processor. * Rule: Module Two applies unless Customer is acting as a Processor for another Controller in respect of the Personal Data being transferred, in which case Module Three applies. * Parties (Appendix I.A). * Data Exporter: Customer (as identified under Section 1.3). Contact details: Customer’s primary account administrator email as on file (or as otherwise provided in the Order Form/account). * Data Importer: Phyder Mobile Solutions Pvt. Ltd. (Encatch) Address: 412/413, 4th Floor, Palmspring (Above Croma), Link Road, Malad West, Mumbai City, Mumbai, Maharashtra, India, 400064 Contact: [privacy@encatch.com](mailto:privacy@encatch.com) * Description of transfer (Appendix I.B). * Categories of data subjects: Customer End Users; Customer account administrators and authorized users (as applicable). * Categories of Personal Data: Customer End User Identifiers (as provided/configured by Customer); feedback/survey responses and related content (to the extent it contains Personal Data); device/browser metadata, IP address (where applicable), timestamps, and usage/activity signals required to operate the Service/SDK; workspace/project identifiers and configuration metadata (where applicable). * Special categories of data: Not intended as a standard feature; if processed, only to the extent submitted by Customer and as permitted by Applicable Law. * Frequency of transfer: Continuous or intermittent, depending on Customer implementation and use of the Service/SDK. * Nature of processing: Collection, transmission, hosting, storage, retrieval, use, disclosure to Subprocessors, and deletion, as necessary to provide the Service. * Purpose(s): Provide and operate the Service and SDK functionality; security, fraud/abuse prevention, reliability, diagnostics, and performance monitoring; Customer support/troubleshooting (as applicable); analytics/diagnostics where enabled and permitted by Applicable Law. * Retention: As described in the DPA/Terms of Service and Customer’s documented instructions (Processor-side), subject to applicable legal requirements. * Supervisory authority (Appendix I.C). The competent supervisory authority is determined under GDPR rules based on Customer’s establishment and the circumstances of the Processing. * Technical and organisational measures (Appendix II). Appendix II is satisfied by Annex 2 (Security Measures) to this DPA, incorporated by reference. * Subprocessors (Appendix III). Appendix III is satisfied by Annex 3 (Subprocessors) to this DPA, incorporated by reference. * UK Addendum — Completion Information (UK GDPR) * Parties. Same exporter/importer as Section 2.2. * Which agreement the Addendum is appended to. The EU SCCs (2021/914), as incorporated by reference under this Annex 4. * Effective date. The effective date is the date Customer accepts the DPA (including via clickwrap), unless otherwise stated in an Order Form. * Appendices. The UK Addendum tables/appendices are completed by reference to: (i) Appendix I.B in Section 2.3 above; (ii) Annex 2 (Security Measures); and (iii) Annex 3 (Subprocessors). * Governing law and jurisdiction (for the Addendum). As required under the UK Addendum framework for UK restricted transfers; otherwise, the governing law and dispute provisions of the Terms of Service continue to apply to the remainder of the relationship. * Availability of SCC Text * The full text of (i) the EU Standard Contractual Clauses (2021/914) and (ii) the UK International Data Transfer Addendum is incorporated by reference into this DPA as described above. * Customers may request copies of the applicable SCCs and UK Addendum documents by contacting Encatch at [privacy@encatch.com](mailto:privacy@encatch.com). # Privacy Policy (/docs/legal/privacy-policy) # ENCATCH PRIVACY POLICY [#encatch-privacy-policy] **Effective Date:** January 1, 2026 **Last Updated:** May 28, 2026 This Privacy Policy explains how Phyder Mobile Solutions Pvt. Ltd., a company incorporated in India with its registered office at 412/413, 4th Floor, Palmspring (Above Croma), Link Road, Malad West, Mumbai City, Mumbai, Maharashtra, India, 400064 (the "Company"), operating the business and brand name "Encatch" ("Encatch," "we," "us," or "our"), collects, uses, discloses, and otherwise processes Personal Data in connection with (a) our website located at [https://encatch.com](https://encatch.com) (the "Website") and (b) the Encatch platform, including its dashboard, SDKs, APIs, integrations, and AI-enabled features. ## 1. INTRODUCTION, SCOPE AND APPLICATION [#1-introduction-scope-and-application] ### 1.1. Defined Terms and Related Documents [#11-defined-terms-and-related-documents] Capitalized terms not defined in this Privacy Policy have the meanings given in our [Terms of Service](/docs/legal/terms-of-service) and, where applicable, the [Data Processing Addendum](/docs/legal/data-processing-addendum) ("DPA"), the [SDK End User License Agreement](/docs/legal/sdk-eula) ("SDK EULA"), and other documents referenced in this Privacy Policy. ### 1.2. Customer End-User Notices [#12-customer-end-user-notices] Where a Customer uses the SDKs or APIs to collect feedback, surveys, bug reports, or similar inputs from the end users of the Customer's own applications or websites, the Customer is responsible for providing its own privacy notice and obtaining any required consents or authorizations. This Privacy Policy does not replace a Customer's privacy notice to its end users. ### 1.3. Cookies [#13-cookies] Our use of cookies and similar technologies on the Website is described in our [Cookie Policy](/docs/legal/cookie-policy). Non-essential cookies (including analytics cookies for Google Analytics and Microsoft Clarity) are disabled by default and are enabled only after you provide consent through our cookie preference controls. ### 1.4. Processing on Customer Instructions; DPA Controls [#14-processing-on-customer-instructions-dpa-controls] To the extent Encatch processes certain Personal Data on behalf of a Customer as a Processor (for example, feedback data collected via the SDKs) under a DPA, the DPA governs that processing and will control in the event of any conflict with this Privacy Policy for that processing. ### 1.5. Who this Privacy Policy Applies to [#15-who-this-privacy-policy-applies-to] This Privacy Policy applies to individuals who: a. visit or interact with the Website; b. engage with us in a business context (including sales inquiries, marketing communications, events, demos, and similar interactions); c. create, administer, or use an account to access or use the Service on behalf of a Customer; and/or d. contact us for support or otherwise communicate with us. ### 1.6. Updates [#16-updates] We may update this Privacy Policy from time to time. The "Last Updated" date at the top indicates when this Privacy Policy was last revised. If we make material changes, we will provide notice as required by Applicable Law (for example, by posting an updated version on the Website or through the Service). ## 2. DEFINITIONS [#2-definitions] ### 2.1. "Personal Data" [#21-personal-data] means any information relating to an identified or identifiable natural person and includes "personal data" as defined under (a) the General Data Protection Regulation (EU) 2016/679 ("GDPR") and (b) the Digital Personal Data Protection Act, 2023 (India) ("DPDP Act"), as applicable. ### 2.2. "Controller" [#22-controller] means the person or entity that determines the purposes and means of processing Personal Data and includes a "controller" under the GDPR and a "data fiduciary" under the DPDP Act, as applicable. ### 2.3. "Processor" [#23-processor] means the person or entity that processes Personal Data on behalf of a Controller and in accordance with the Controller's documented instructions and includes a "processor" under the GDPR and a "data processor" under the DPDP Act, as applicable. ### 2.4. "Processing" [#24-processing] means any operation or set of operations performed on Personal Data, whether or not by automated means, including collection, recording, organization, structuring, storage, adaptation, retrieval, use, disclosure, transfer, combination, restriction, erasure, or destruction. ### 2.5. "Applicable Law" [#25-applicable-law] means all laws, regulations, and legally binding requirements applicable to the Processing of Personal Data under this Privacy Policy, including, where relevant, the GDPR and the DPDP Act. ## 3. CONTROLLER VS PROCESSOR (OUR ROLE) [#3-controller-vs-processor-our-role] ### 3.1. When Encatch Acts as a Controller [#31-when-encatch-acts-as-a-controller] Encatch acts as a Controller with respect to Personal Data that we collect and process directly in connection with: a. visits to and interactions with the Website; b. sales, marketing, events, demos, and other business communications; c. creation and administration of Customer accounts, including Authorized Users; d. billing, invoicing, and payment-related activities; e. support requests and communications; and f. security, compliance, and internal business operations. In these circumstances, Encatch determines the purposes and means of processing such Personal Data. ### 3.2. When Encatch Acts as a Processor [#32-when-encatch-acts-as-a-processor] Encatch acts as a Processor where we process Personal Data on behalf of a Customer, for example, where a Customer uses the Service (such as SDKs or APIs) to collect feedback, surveys, bug reports, or similar inputs from individuals interacting with the Customer's own applications or websites. In such cases: a. the Customer acts as the Controller (or data fiduciary under the DPDP Act); b. Encatch processes Personal Data only in accordance with the Customer's documented instructions and the applicable DPA; and c. requests from Customer End Users relating to such Personal Data should be directed to the relevant Customer, subject to Encatch's assistance obligations under the DPA. ## 4. INFORMATION WE COLLECT (CONTROLLER-SIDE) [#4-information-we-collect-controller-side] ### 4.1. Website Interactions [#41-website-interactions] When you visit or interact with the Website, we may collect Personal Data such as IP address, device and browser information, pages viewed, referring/exit pages, approximate location derived from IP address, and similar usage information. ### 4.2. Business Communications [#42-business-communications] If you contact us or engage with us for sales, marketing, events, demos, or other business communications, we may collect Personal Data such as your name, work email address, company name, job title/role, and the content of your communications. ### 4.3. Account and Workspace Information [#43-account-and-workspace-information] If you create, administer, or use an account to access or use the Service on behalf of a Customer, we may collect Personal Data such as name, work email address, account authentication information (such as hashed passwords or similar credentials), user roles/permissions, workspace settings/configurations, and related account metadata. ### 4.4. Billing and Payment Administration [#44-billing-and-payment-administration] If you subscribe to a paid Plan or otherwise transact with us, we may collect billing contact details, invoicing information, payment status, and related transaction metadata. We typically do not receive full payment card details where payments are handled by a payment processor. ### 4.5. Support and Communications [#45-support-and-communications] If you contact us for support or otherwise communicate with us, we may collect Personal Data contained in your messages and any attachments you choose to provide. ### 4.6. Usage, Telemetry, and Logs [#46-usage-telemetry-and-logs] We may collect technical and usage information generated when Authorized Users access or use the Service, such as feature usage events, diagnostics, performance logs, and security logs. ## 5. INFORMATION PROCESSED ON CUSTOMER INSTRUCTIONS (PROCESSOR-SIDE) [#5-information-processed-on-customer-instructions-processor-side] ### 5.1. Customer End-User Data Processed on Instructions [#51-customer-end-user-data-processed-on-instructions] Where a Customer uses the Service (including the SDKs or APIs) to collect feedback, surveys, bug reports, or similar inputs from its Customer End Users, Encatch processes only such Personal Data that the Customer (through its configuration and use of the Service) elects to submit or transmit to Encatch for processing on the Customer's behalf, and does so in accordance with the Customer's documented instructions and the applicable DPA. ### 5.2. Customer Control and Configuration [#52-customer-control-and-configuration] The Customer determines what end-user data is collected, the fields or prompts shown to Customer End Users, whether identifiers (such as user IDs, email addresses, phone numbers, or hashed identifiers) are provided to Encatch, and which integrations or workflows are enabled. The Customer is responsible for providing appropriate notices and obtaining any required consents or authorizations from its end users. ### 5.3. Sensitive Data [#53-sensitive-data] Customer will not (and will not permit Customer End Users to) submit, upload, transmit, or otherwise make available through the Service any Sensitive Data. Encatch does not monitor, screen, or filter Personal Data processed on Customer instruction to detect or prevent submission of Sensitive Data. Customer is responsible for configuring its feedback flows, forms, and SDK/API implementations and for providing appropriate end-user notices and obtaining any required consents or authorizations to minimize and avoid the collection of Sensitive Data through the Service. Customer represents and warrants that it has implemented appropriate notices, consents, and safeguards designed to minimize and avoid the collection of Sensitive Data through the Service. Customer will promptly notify Encatch if Customer anticipates that Sensitive Data will be processed through the Service (whether intentionally or inadvertently), and any such processing will be governed by the DPA's Sensitive Data terms. ### 5.4. Customer End-User Rights Requests [#54-customer-end-user-rights-requests] Requests from Customer End Users relating to Personal Data processed by Encatch on Customer instruction should be directed to the relevant Customer. Encatch will assist the Customer in responding to such requests as required under the applicable DPA and Applicable Law. ## 6. HOW WE USE PERSONAL DATA (PURPOSES) [#6-how-we-use-personal-data-purposes] ### 6.1. Controller-Side Purposes (When Encatch Acts as a Controller) [#61-controller-side-purposes-when-encatch-acts-as-a-controller] Where Encatch acts as a Controller (as described in Clause 3.1), we may use Personal Data for the following purposes: a. to operate, maintain, and provide the Website and Service (including account creation, authentication, access management, and workspace administration); b. to respond to inquiries, provide customer support, troubleshoot issues, and communicate with you (including service-related notices and administrative messages); c. to manage subscriptions, billing, invoicing, and payment administration, and to maintain related records; d. to monitor, prevent, detect, and address security issues, fraud, abuse, and unauthorized access, and to enforce our Terms of Service and other applicable policies; e. to analyze usage of the Website and Service and improve their functionality, performance, and user experience (including through analytics and service optimization); f. to conduct internal business operations, reporting, audits, and recordkeeping; and g. to comply with Applicable Law, respond to lawful requests, and protect our rights, property, and safety (and those of our Customers, users, and others). ### 6.2. Processor-Side Purposes (When Encatch Acts as a Processor) [#62-processor-side-purposes-when-encatch-acts-as-a-processor] Where Encatch acts as a Processor (as described in Clause 3.2), we process Personal Data solely on behalf of the relevant Customer and in accordance with the Customer's documented instructions and the applicable DPA, including to: a. provide, operate, and support the Service for the Customer (including routing, tagging, organizing, and otherwise processing Customer End-User Feedback Data as configured by the Customer); b. maintain the security and integrity of the Service, prevent or address technical issues, and perform troubleshooting and support; and c. comply with Applicable Law to the extent applicable to Encatch as a Processor. ### 6.3. No Independent Use [#63-no-independent-use] Encatch does not use Personal Data processed on Customer instruction for its own independent purposes, except to the extent such data has been aggregated and/or de-identified so that it no longer constitutes Personal Data, or as otherwise expressly permitted under the DPA and Applicable Law. ## 7. LEGAL BASES (GDPR + DPDP POSTURE) [#7-legal-bases-gdpr--dpdp-posture] ### 7.1. GDPR Lawful Bases (where GDPR applies) [#71-gdpr-lawful-bases-where-gdpr-applies] Where the GDPR applies to our Processing of Personal Data as a Controller, we rely on one or more of the following lawful bases, depending on the context: a. **Contract.** Processing is necessary to perform a contract with you (or to take steps at your request before entering into a contract), including to provide the Website and Service, administer accounts, manage subscriptions, and provide support. b. **Legitimate Interests.** Processing is necessary for our legitimate interests (or those of a third party), including to operate, secure, and improve the Website and Service; prevent fraud, abuse, and unauthorized access; maintain service performance; conduct internal business operations; and communicate with Customers and Authorized Users about service-related matters, provided such interests are not overridden by your rights and interests. c. **Consent.** Processing is based on your consent, where required (for example, for certain marketing communications or the use of non-essential cookies and similar technologies on the Website). You may withdraw your consent at any time. Withdrawal will not affect the lawfulness of Processing based on consent before its withdrawal. d. **Legal Obligation.** Processing is necessary to comply with our legal obligations (for example, responding to lawful requests or maintaining records required by Applicable Law). ### 7.2. DPDP Act Notice and Consent Posture (where DPDP Act applies) [#72-dpdp-act-notice-and-consent-posture-where-dpdp-act-applies] Where the DPDP Act applies to our Processing of Personal Data, we process Personal Data with appropriate notice and consent where required, and as otherwise permitted under Applicable Law. Where we act as a Processor on behalf of a Customer, the Customer is responsible for providing required notices and obtaining any required consents or other lawful basis/authorizations from Customer End Users for the Customer's collection and provision of such Personal Data to Encatch, subject to the applicable DPA. ### 7.3. Processor-Side Processing (Customer-controlled) [#73-processor-side-processing-customer-controlled] Where Encatch acts as a Processor (as described in Clause 3.2), we process Personal Data on behalf of the relevant Customer and in accordance with the Customer's documented instructions and the applicable DPA. In such cases, the Customer (as Controller/data fiduciary) is responsible for determining the lawful basis for Processing and providing required notices to Customer End Users. Encatch's Processing is limited to the Customer's documented instructions, the DPA, and Applicable Law. ### 7.4. Other Data Protection Laws (where applicable) [#74-other-data-protection-laws-where-applicable] Where any other data protection or privacy law applies to our Processing of Personal Data, we will process such Personal Data in accordance with that law's requirements, including (as applicable) by providing required notices, obtaining required consents or authorizations, honoring applicable rights requests, and implementing appropriate safeguards. Where Encatch processes Personal Data as a Processor on behalf of a Customer, the Customer remains responsible for compliance with such laws for its collection and use of that Personal Data, subject to the applicable DPA. ### 7.5. Cookie-Related Legal Basis [#75-cookie-related-legal-basis] Our use of cookies and similar technologies on the Website is described in the Cookie Policy. Where required by Applicable Law, non-essential cookies (including analytics cookies) are used only based on appropriate consent choices made through our cookie preference controls. Consistent with our current configuration, analytics (including Google Analytics and Microsoft Clarity) is disabled by default and is enabled only after consent is provided; if a user rejects non-essential cookies, Google Analytics and Microsoft Clarity remain disabled. Essential cookies may be used without consent where permitted by Applicable Law. ### 7.6. Marketing Choices (where applicable) [#76-marketing-choices-where-applicable] Where we send marketing communications, you may opt out at any time by using the unsubscribe mechanism in the message or by contacting us using the details in Clause 18. If you opt out of marketing communications, we may still send you non-promotional, service-related messages (for example, security notices, billing notices, or administrative updates). ## 8. AI FEATURES & AI PROCESSING [#8-ai-features--ai-processing] ### 8.1. AI Processing Inputs and Outputs [#81-ai-processing-inputs-and-outputs] Depending on the Customer's configuration and configured workflows, AI Features may process (a) Customer End-User Feedback Data and related identifiers provided by the Customer, (b) other Customer Data submitted through the Service, and (c) usage and context necessary to generate AI Outputs (collectively, "AI Inputs"). AI Features may generate AI Outputs such as summaries, classifications, tags, suggested actions, and other results. ### 8.2. Third-Party Model Providers [#82-third-party-model-providers] AI Features may rely on third-party model providers and routing layers to process AI Inputs and generate AI Outputs. When AI Features are used (for example, when an Authorized User invokes an AI workflow or an AI-enabled function runs as part of the configured workflow), AI Inputs may be transmitted to and processed by such providers as part of providing the Service. We take reasonable steps to ensure that such providers process AI Inputs only for the purpose of providing the AI Features (including hosting, support, and security), and subject to applicable contractual terms and safeguards. ### 8.3. No Training by Default [#83-no-training-by-default] Encatch's intended configuration is that Customer Data submitted through AI Features is not used to train or improve third-party providers' general-purpose models. Where AI Features rely on third-party model providers, Encatch's approach is to use providers/settings that offer "no training"/restricted-use options (where available) and to rely on applicable contractual terms and safeguards. If a Customer requests or enables any such broader-use configuration, to the extent that capability is made available, it will be subject to Customer agreement and, where applicable, the DPA and Applicable Law. ### 8.4. International Processing [#84-international-processing] AI processing may involve cross-border data transfers or processing outside the country where the Customer or Customer End Users are located (including, depending on configuration, in the United States or other jurisdictions). Where required by Applicable Law, Encatch will implement appropriate safeguards for such transfers. ### 8.5. Customer Responsibilities [#85-customer-responsibilities] Depending on the Plan, Service configuration, and the capabilities made available in the Service from time to time, AI Features may be enabled by default and may run as part of configured workflows. Customers are responsible for (a) deciding how to configure and use AI Features within their workflows and (b) determining what information they submit, input, route, or otherwise make available for AI processing through their use of the Service (including through prompts, workflow design, and any integrations the Customer enables). Customers are responsible for providing any required notices and obtaining any required consents or authorizations for such AI processing, including where AI Inputs include Personal Data of Customer End Users. ## 9. SHARING & DISCLOSURES [#9-sharing--disclosures] ### 9.1. Sharing When Encatch Acts as a Controller [#91-sharing-when-encatch-acts-as-a-controller] Where Encatch acts as a Controller, we may share Personal Data with: a. **Service Providers.** Vendors and service providers that help us operate the Website and Service and perform business functions on our behalf (for example, hosting and infrastructure, analytics, customer support, email/communications, and billing, invoicing, and payment processing). These providers are authorized to process Personal Data only as necessary to provide services to us and in accordance with applicable contractual terms and safeguards. b. **Professional Advisers.** Our professional advisers (such as lawyers, auditors, and accountants) where necessary for advice, compliance, or protection of our legal interests. c. **Compliance and Protection.** Government authorities, regulators, law enforcement, courts, or other third parties where we believe disclosure is necessary to comply with Applicable Law, respond to lawful requests, protect rights and safety, prevent fraud or abuse, or enforce our Terms of Service and other policies. d. **Business Transfers.** In connection with a merger, acquisition, financing, reorganization, sale of assets, or similar transaction (including due diligence), subject to appropriate confidentiality and data protection safeguards. ### 9.2. Sharing When Encatch Acts as a Processor [#92-sharing-when-encatch-acts-as-a-processor] Where Encatch acts as a Processor, we may share Personal Data processed on Customer instruction with: a. **Subprocessors.** Vendors engaged to help us provide the Service (including hosting, infrastructure, support, and security providers). Subprocessors are engaged and managed in accordance with the DPA. b. **Customer-Directed Disclosures.** Third-Party Services or integrations enabled or configured by the Customer (for example, webhooks, workflow tools, or external systems), in accordance with the Customer's configuration and instructions. Third-Party Services are governed by their own terms and privacy policies, and the Customer is responsible for evaluating and enabling such Third-Party Services. For clarity, Encatch does not control, and is not responsible for, how Third-Party Services process data once transmitted to them. c. **Legal Requirements.** Authorities or third parties where required by Applicable Law, in which case we will take reasonable steps to notify the Customer where permitted. ### 9.3. No Sale or Sharing for Behavioral Advertising [#93-no-sale-or-sharing-for-behavioral-advertising] Encatch does not sell Personal Data, and we do not share Personal Data for cross-context behavioral advertising. ## 10. INTERNATIONAL TRANSFERS [#10-international-transfers] ### 10.1. Cross-Border Processing [#101-cross-border-processing] The Website and Service are operated from India, and Personal Data may be processed, accessed (including through remote access), or stored in countries other than the country where you are located, including where we use service providers, subprocessors, or AI model providers that operate in other jurisdictions. ### 10.2. Safeguards (where required) [#102-safeguards-where-required] Where Applicable Law requires safeguards for international transfers (for example, under the GDPR), we take appropriate measures to protect Personal Data, which may include entering into appropriate contractual safeguards and implementing supplementary technical and organizational measures, as applicable. Where Encatch processes Personal Data on behalf of a Customer as a Processor, transfer mechanisms and safeguards are addressed in the applicable DPA. ### 10.3. Customer-Directed Transfers [#103-customer-directed-transfers] Where a Customer enables integrations or Third-Party Services, Personal Data may be transmitted to those third parties as configured by the Customer, and may be subject to international processing by those third parties. The Customer is responsible for evaluating and enabling such Third-Party Services and for ensuring required notices and lawful bases are in place for such transfers. ## 11. RETENTION [#11-retention] ### 11.1. Retention During the Term [#111-retention-during-the-term] We retain Personal Data for as long as necessary to provide the Website and Service, administer accounts, provide support, and carry out the purposes described in this Privacy Policy, unless a longer retention period is required or permitted by Applicable Law, including for security and audit logs. For Service data stored within the Service (including Customer Data), retention during the subscription term may vary based on the applicable Plan and the Customer's configuration choices (for example, selecting a feedback data retention window such as 3 months up to 2 years). ### 11.2. Post-Termination Retention (Service Data) [#112-post-termination-retention-service-data] Where a Customer terminates the Service, we retain Customer Data (including Personal Data contained in such Customer Data) for up to 60 days following termination, unless otherwise required by Applicable Law or subject to a legal hold. ### 11.3. Backups [#113-backups] Customer Data (including Personal Data contained in such Customer Data) may remain in backups for up to 45 days after deletion or termination, after which it is deleted or overwritten in the ordinary course, unless otherwise required by Applicable Law or subject to a legal hold. ### 11.4. Operational Logs [#114-operational-logs] Certain security, diagnostic, and operational logs (including logs indicating when AI Features are invoked or triggered at a workspace/dataset level) may be retained for security, troubleshooting, and audit purposes. Where retained, we generally discard such logs from active records within one (1) month, and such logs may remain in backups for up to ninety (90) days, unless a longer period is required by Applicable Law or subject to a legal hold. ### 11.5. Legal Hold and Disputes [#115-legal-hold-and-disputes] Notwithstanding the above, we may retain Personal Data for longer periods where necessary to comply with Applicable Law, respond to lawful requests, enforce our agreements, resolve disputes, or protect our rights, property, and safety (and those of our Customers, users, and others). ### 11.6. Processor-Side Retention [#116-processor-side-retention] Where Encatch processes Personal Data on behalf of a Customer as a Processor, retention and deletion obligations are governed by the applicable DPA and the Customer's documented instructions, subject to Applicable Law. ## 12. SECURITY [#12-security] ### 12.1. Safeguards [#121-safeguards] We implement commercially reasonable technical and organizational measures designed to protect Personal Data against accidental or unlawful destruction, loss, alteration, unauthorized disclosure, or access. ### 12.2. No Absolute Guarantee [#122-no-absolute-guarantee] While we take reasonable steps to protect Personal Data, no method of transmission over the internet or electronic storage is completely secure, and we cannot guarantee absolute security. ### 12.3. Shared Responsibility [#123-shared-responsibility] Security is a shared responsibility. Customers are responsible for maintaining the confidentiality of account credentials and API Keys, controlling Authorized User access, and securely configuring their deployments (including SDK/API implementations, fields/prompts, integrations, and AI workflows). ### 12.4. Processor-Side Security [#124-processor-side-security] Where Encatch processes Personal Data on behalf of a Customer as a Processor, we will implement appropriate security measures as required under the applicable DPA and Applicable Law. ### 12.5. Security Incidents [#125-security-incidents] Our security incident handling and notification obligations (including applicable timelines and delivery methods) are addressed in the Terms of Service and, where relevant, the DPA. Where Encatch processes Personal Data as a Processor, incident handling and notifications are governed by the DPA. Customers remain responsible for any end-user or regulator notifications required under Applicable Law. ## 13. YOUR RIGHTS & CHOICES [#13-your-rights--choices] ### 13.1. Rights When Encatch Acts as a Controller [#131-rights-when-encatch-acts-as-a-controller] Where Encatch acts as a Controller (as described in Clause 3.1), you may have certain rights in relation to your Personal Data under Applicable Law. The specific rights available to you depend on where you are located and the laws that apply (including, where applicable, the GDPR and the DPDP Act), and may be subject to conditions and exceptions. ### 13.2. GDPR Rights (where GDPR applies and Encatch acts as a Controller) [#132-gdpr-rights-where-gdpr-applies-and-encatch-acts-as-a-controller] Where the GDPR applies, and subject to applicable conditions and exceptions, you may have the right to: a. request access to and a copy of your Personal Data; b. request rectification of inaccurate Personal Data; c. request erasure of your Personal Data; d. request restriction of Processing; e. request data portability; f. object to Processing (including where we rely on legitimate interests, and for direct marketing); and g. lodge a complaint with a supervisory authority in the EU/EEA (or the UK supervisory authority (ICO), where applicable). ### 13.3. DPDP Act Rights (where DPDP Act applies) [#133-dpdp-act-rights-where-dpdp-act-applies] Where the DPDP Act applies, and subject to applicable conditions and exceptions, you may have the right to: a. access information about the Personal Data we process about you; b. request correction and updating of your Personal Data; c. request deletion/erasure of your Personal Data; d. withdraw consent (where consent is the basis of Processing); and e. submit grievances using the contact details in Clause 18. ### 13.4. Requests Relating to Processor-Side Data (Customer End Users) [#134-requests-relating-to-processor-side-data-customer-end-users] Where Encatch processes Personal Data on behalf of a Customer as a Processor (as described in Clause 3.2), requests from Customer End Users relating to such Personal Data should be directed to the relevant Customer. Encatch will assist the Customer in responding to such requests as required under the applicable DPA and Applicable Law. ### 13.5. How to Exercise Your Rights [#135-how-to-exercise-your-rights] You may submit requests by contacting us using the details in Clause 18. We may need to verify your identity before fulfilling a request. If you are an Authorized User acting on behalf of a Customer, we may refer your request to the relevant Customer where appropriate. ## 14. COOKIES [#14-cookies] ### 14.1. Cookie Policy [#141-cookie-policy] Our use of cookies and similar technologies on the Website is described in our [Cookie Policy](/docs/legal/cookie-policy). ### 14.2. Cookie Preferences and Consent [#142-cookie-preferences-and-consent] You can manage your cookie preferences through our cookie preference controls. Non-essential cookies (including analytics cookies) are disabled by default and are enabled only after you provide consent through those controls. Where permitted by Applicable Law, essential cookies may be used without consent. ## 15. THIRD-PARTY SERVICES [#15-third-party-services] ### 15.1. Third-Party Services and Links [#151-third-party-services-and-links] The Website and Service may contain links to, or enable connections with, third-party websites, applications, services, or integrations (including Third-Party Services enabled by a Customer through configurations, webhooks, or other workflows). ### 15.2. Independent Third Parties [#152-independent-third-parties] Third-Party Services are operated by independent third parties and are governed by their own terms and privacy policies. If you access or use a Third-Party Service, you should review the third party's privacy practices. ### 15.3. No Control After Transfer [#153-no-control-after-transfer] To the extent Personal Data is transmitted to a Third-Party Service (including through Customer-enabled integrations), Encatch does not control and is not responsible for the Third-Party Service's processing of that data once transmitted. ### 15.4. Customer Responsibility for Integrations [#154-customer-responsibility-for-integrations] Where a Customer enables or configures Third-Party Services, the Customer is responsible for evaluating those Third-Party Services and for ensuring appropriate notices, consents, and lawful bases are in place for any related data sharing or transfers, subject to Applicable Law. ## 16. CHILDREN [#16-children] ### 16.1. Not Intended for Children [#161-not-intended-for-children] The Website and Service are not directed to children and are not intended for use by individuals under 18 years of age. ### 16.2. No Knowing Collection [#162-no-knowing-collection] We do not knowingly collect Personal Data from individuals under 18. If we become aware that we have collected Personal Data from an individual under 18, we will take reasonable steps to delete it. ### 16.3. Parent/Guardian Requests [#163-parentguardian-requests] If you are a parent or guardian and believe that a child has provided Personal Data to us, please contact us using the details in Clause 18 so we can take appropriate action. ## 17. CHANGES TO THIS PRIVACY POLICY [#17-changes-to-this-privacy-policy] ### 17.1. Updates [#171-updates] We may update this Privacy Policy from time to time to reflect changes in our practices, the Website or Service, or Applicable Law. The "Last Updated" date at the top indicates when this Privacy Policy was last revised. ### 17.2. Notice of Material Changes [#172-notice-of-material-changes] If we make material changes to this Privacy Policy, we will provide notice as required by Applicable Law. Notice may be provided by posting an updated version on the Website, through the Service, or by other reasonable means. ### 17.3. Continued Use [#173-continued-use] To the extent permitted by Applicable Law, your continued use of the Website or Service after an updated Privacy Policy becomes effective indicates your acknowledgement of the updated Privacy Policy. ## 18. CONTACT US / GRIEVANCE REDRESSAL [#18-contact-us--grievance-redressal] ### 18.1. Contact [#181-contact] If you have questions about this Privacy Policy or our privacy practices, or if you wish to exercise your rights under Applicable Law, you may contact us at: a. **Privacy / Data Protection / Grievances:** [privacy@encatch.com](mailto:privacy@encatch.com) (managed by Encatch's Data Protection Officer). b. **General Support:** [support@encatch.com](mailto:support@encatch.com). c. **Postal Address:** Phyder Mobile Solutions Pvt. Ltd. 412/413, 4th Floor, Palmspring (Above Croma), Link Road, Malad West, Mumbai City, Mumbai, Maharashtra, India – 400064. ### 18.2. Response [#182-response] We will review and respond to privacy requests and grievances in accordance with Applicable Law. # SDK End User License Agreement (/docs/legal/sdk-eula) # ENCATCH SDK END USER LICENSE AGREEMENT (SDK EULA) [#encatch-sdk-end-user-license-agreement-sdk-eula] **Effective Date:** January 1, 2026 **Last Updated:** May 28, 2026 This Encatch SDK End User License Agreement (the "SDK EULA") is entered into by and between Phyder Mobile Solutions Pvt. Ltd., a company incorporated in India with its registered office at 412/413, 4th Floor, Palmspring (Above Croma), Link Road, Malad West, Mumbai City, Mumbai, Maharashtra, India, 400064, operating under the brand name "Encatch" ("Encatch," "we," "us," or "our"), and the entity or individual that installs, accesses, or uses the SDK ("Customer" (as defined in the [Terms of Service](/docs/legal/terms-of-service)), "you," or "your"). ## 1. SCOPE AND INTERPRETATION [#1-scope-and-interpretation] ### 1.1. Scope of SDK EULA [#11-scope-of-sdk-eula] This SDK EULA governs your access to and use of the SDK and related materials made available by Encatch, including any accompanying documentation, sample code, updates, and modifications. ### 1.2. Read Together [#12-read-together] This SDK EULA should be read together with (and is in addition to) the [Encatch Terms of Service](/docs/legal/terms-of-service), [Privacy Policy](/docs/legal/privacy-policy), and [Data Processing Addendum (DPA)](/docs/legal/data-processing-addendum) (each as updated from time to time). Capitalized terms used but not defined in this SDK EULA have the meanings given in the Terms of Service, Privacy Policy, and DPA (as applicable). ### 1.3. Order of Precedence [#13-order-of-precedence] If there is any inconsistency: a. an applicable enterprise agreement, order form, statement of work, or other written agreement between Encatch and Customer will control, but only to the extent of the conflict; b. the DPA will control only with respect to Processor-side Processing by Encatch on documented Customer instructions; c. this SDK EULA will control only with respect to SDK/API/license-specific terms (including permitted use, restrictions, and licensing); and d. otherwise, the Encatch Terms of Service will control. ## 2. LICENSE GRANT [#2-license-grant] ### 2.1. License [#21-license] Subject to your ongoing compliance with this SDK EULA and the Terms of Service, Encatch grants Customer a limited, non-exclusive, non-transferable, non-sublicensable, and revocable license to use, copy, and integrate the SDK solely to implement Encatch's feedback widgets, surveys, and related functionality in and into Customer's applications and websites. ### 2.2. Permitted Copies [#22-permitted-copies] Customer may make a reasonable number of copies of the SDK solely as necessary for development, testing, staging, and production deployment of Customer's integration. ### 2.3. Distribution [#23-distribution] Customer may distribute the SDK only as incorporated into Customer's applications and websites (and not on a standalone basis), and only in object code or otherwise compiled/minified form where applicable. ### 2.4. Reservation of Rights [#24-reservation-of-rights] Encatch and its licensors reserve all rights not expressly granted to Customer under this SDK EULA. ## 3. PERMITTED USE AND DISTRIBUTION [#3-permitted-use-and-distribution] ### 3.1. Authorized Users [#31-authorized-users] Customer may permit its employees and contractors to use the SDK solely on Customer's behalf for Customer's internal development and implementation purposes, provided Customer remains responsible for their compliance with this SDK EULA. ### 3.2. Integration Purpose Only [#32-integration-purpose-only] Customer may use the SDK only to integrate Encatch functionality into Customer's applications and websites and may not use the SDK for any other purpose. ### 3.3. Environment Use [#33-environment-use] Customer may use the SDK in development, testing, staging, and production environments, provided Customer safeguards any API keys or credentials and follows Encatch's documentation. ### 3.4. No Standalone Distribution [#34-no-standalone-distribution] Customer may not distribute, sublicense, sell, rent, lease, or otherwise make the SDK available on a standalone basis, except as incorporated into Customer's applications and websites as permitted under Clause 2.3. ## 4. RESTRICTIONS [#4-restrictions] ### 4.1. No Reverse Engineering [#41-no-reverse-engineering] Customer will not (and will not permit any third party to) reverse engineer, decompile, disassemble, or otherwise attempt to derive the source code of the SDK, except to the extent such restriction is prohibited by Applicable Law. ### 4.2. No Circumvention or Interference [#42-no-circumvention-or-interference] Customer will not bypass, disable, or interfere with security, integrity, access controls, rate limits, or other protections in or relating to the SDK or the Service. ### 4.3. No Unlawful or Harmful Use [#43-no-unlawful-or-harmful-use] Customer will not use the SDK in a manner that violates Applicable Law, infringes third-party rights, or is abusive, fraudulent, deceptive, or harmful. ### 4.4. No Competing Use [#44-no-competing-use] Customer will not use the SDK to develop, train, or improve a product or service that competes with Encatch. ### 4.5. No Removal of Notices [#45-no-removal-of-notices] Customer will not remove, obscure, or alter any proprietary notices, labels, or branding included in the SDK or Documentation. ### 4.6. No Export Violations [#46-no-export-violations] Customer will not use or export the SDK in violation of applicable export control or sanctions laws. ## 5. IMPLEMENTATION REQUIREMENTS AND CUSTOMER RESPONSIBILITIES [#5-implementation-requirements-and-customer-responsibilities] ### 5.1. Follow Documentation [#51-follow-documentation] Customer will implement and use the SDK in accordance with Encatch's then-current documentation and integration instructions. ### 5.2. API Keys and Credentials [#52-api-keys-and-credentials] Customer is responsible for maintaining the confidentiality and security of any API keys, tokens, credentials, or other access mechanisms used with the SDK and will not embed secrets in publicly accessible code repositories or otherwise expose them. ### 5.3. Environment and Testing [#53-environment-and-testing] Customer is responsible for testing the SDK integration in its development and staging environments prior to production deployment and for ensuring the SDK is integrated in a manner that does not materially degrade Customer's applications or websites. ### 5.4. Customer Systems and Compliance [#54-customer-systems-and-compliance] Customer is solely responsible for (a) Customer's applications and websites in which the SDK is integrated, (b) the accuracy, legality, and appropriateness of Customer's configuration choices, and (c) Customer's compliance with Applicable Law in connection with its use of the SDK. ## 6. SDK DATA FLOWS AND SIMILAR TECHNOLOGIES [#6-sdk-data-flows-and-similar-technologies] ### 6.1. Local Storage and Technical Identifiers [#61-local-storage-and-technical-identifiers] Where applicable, the SDK may store or read identifiers locally (for example, using local storage or session storage) and may transmit certain technical parameters and event metadata to support operation of the SDK and the Service. ### 6.2. Examples [#62-examples] Such identifiers and parameters may include fields such as identify\_signature, ping\_on\_next\_page\_visit, and ping\_again\_after (or similar fields), used for purposes such as reliability (including reconnect logic), request throttling/rate-limiting, retries/backoff, integrity and security controls, and diagnostics/analytics (only where enabled and, where required by Applicable Law, based on applicable consent choices). ### 6.3. Data Categories [#63-data-categories] Depending on Customer's implementation and configuration, the SDK may process (a) device and browser information, (b) IP address and timestamps, and (c) usage/activity signals relating to the SDK's operation. Customer is responsible for determining what data it chooses to send to Encatch through or in connection with the SDK. ### 6.4. DPA Cross-Reference [#64-dpa-cross-reference] To the extent the SDK is used to transmit Customer End-User Feedback Data and related Customer End User Identifiers for Processor-side Processing on Customer instructions, such processing is governed by the [DPA](/docs/legal/data-processing-addendum) and this SDK EULA does not expand Encatch's processor obligations. ## 7. TRIGGER-BASED IDENTIFIERS; CUSTOMER CONSENT OBLIGATIONS [#7-trigger-based-identifiers-customer-consent-obligations] ### 7.1. SDK Identifiers Created Upon Customer Action [#71-sdk-identifiers-created-upon-customer-action] By default, the SDK does not create local identifiers unless and until Customer invokes methods such as identifyUser() and/or startSession() (or similar methods) as part of Customer's implementation. ### 7.2. Customer Controls When Identifiers Are Created [#72-customer-controls-when-identifiers-are-created] Customer is solely responsible for deciding when to invoke such methods and for configuring the SDK (including any page-visit triggers or similar settings). ### 7.3. Notices and Consents [#73-notices-and-consents] Customer is responsible for providing required notices and obtaining any Customer End User consents required by Applicable Law before enabling the SDK to create identifiers or collect/process data that is not strictly necessary for the operation of Customer's requested integration (including before invoking identifyUser() or startSession(), where required). ### 7.4. Risk Allocation [#74-risk-allocation] Customer will defend, indemnify, and hold harmless Encatch from and against any third-party claims arising from Customer's implementation or configuration of the SDK, including any failure to provide required notices or obtain required consents. ## 8. PRIVACY; CONTROLLER/PROCESSOR SPLIT; DPA [#8-privacy-controllerprocessor-split-dpa] ### 8.1. Privacy Policy [#81-privacy-policy] Encatch's collection and use of Personal Data in connection with the Service is described in the [Privacy Policy](/docs/legal/privacy-policy). ### 8.2. Processor-Side Processing Governed by DPA [#82-processor-side-processing-governed-by-dpa] To the extent Encatch processes Customer End-User Feedback Data and related Customer End User Identifiers on behalf of Customer as a Data Processor on documented Customer instructions, such Processor-side Processing is governed by the [DPA](/docs/legal/data-processing-addendum). ### 8.3. No Expansion of DPA Obligations [#83-no-expansion-of-dpa-obligations] This SDK EULA does not expand, modify, or limit Encatch's obligations under the DPA, and nothing in this SDK EULA should be interpreted to create processor obligations beyond those set out in the DPA. ### 8.4. Customer Responsibilities [#84-customer-responsibilities] Customer is responsible for its own privacy and cookie disclosures to Customer End Users regarding Customer's use of the SDK and for complying with Applicable Law in connection with Customer's implementation and configuration of the SDK. ## 9. CONSENT AND LEGAL COMPLIANCE [#9-consent-and-legal-compliance] ### 9.1. Customer Compliance [#91-customer-compliance] Customer is responsible for complying with Applicable Law in connection with Customer's implementation, configuration, and use of the SDK, including any requirements to provide notices and obtain consents from Customer End Users. ### 9.2. Consent Gating [#92-consent-gating] Where required by Applicable Law, Customer will ensure that the SDK is not initialized or used in a manner that enables collection or processing of non-essential data (including analytics/diagnostics where enabled) until Customer End Users have been provided the required notices and have provided the required consents. ### 9.3. Customer Policies [#93-customer-policies] Customer will maintain and make available to Customer End Users an appropriate privacy policy and cookie notice describing Customer's use of the SDK and any related data collection and processing. ## 10. SUPPORT; MAINTENANCE; NO SLA [#10-support-maintenance-no-sla] ### 10.1. As-Is [#101-as-is] The SDK is provided on an "as is" and "as available" basis. ### 10.2. No SLA [#102-no-sla] Encatch does not provide any service level agreement, uptime commitment, or guaranteed response times for the SDK unless expressly agreed in a separate written enterprise agreement or order form. ### 10.3. Support (If Any) [#103-support-if-any] If Encatch provides support or guidance regarding the SDK, it will be on a reasonable efforts basis and may be provided, modified, or discontinued at Encatch's discretion. ## 11. UPDATES; DEPRECATIONS; SUSPENSION [#11-updates-deprecations-suspension] ### 11.1. Updates [#111-updates] Encatch may modify, update, or replace the SDK from time to time, including to improve performance, security, or functionality. ### 11.2. Deprecation [#112-deprecation] Encatch may deprecate or discontinue versions or features of the SDK. Where practicable, Encatch will provide reasonable notice of material deprecations that may affect Customer's integration. ### 11.3. Suspension or Revocation [#113-suspension-or-revocation] Encatch may suspend, restrict, or revoke Customer's access to the SDK or related credentials (including API keys) if Encatch reasonably believes that (a) Customer's use of the SDK poses a security risk, (b) Customer is using the SDK in violation of this SDK EULA or Applicable Law, or (c) suspension is necessary to prevent abuse, fraud, or harm to Encatch, its systems, or third parties. ## 12. SECURITY [#12-security] ### 12.1. Customer Security Obligations [#121-customer-security-obligations] Customer will implement reasonable technical and organizational measures to secure its implementation and use of the SDK, including safeguarding API keys, tokens, and credentials and restricting access to authorized personnel only. ### 12.2. No Secrets Exposure [#122-no-secrets-exposure] Customer will not embed secrets in publicly accessible code repositories or otherwise expose API keys or credentials used with the SDK. ### 12.3. Incident Notification [#123-incident-notification] Customer will notify Encatch without undue delay after becoming aware of any unauthorized access to or misuse of the SDK, related credentials, or Customer's integration that could reasonably impact the security of the Service or Customer End Users. ## 13. INTELLECTUAL PROPERTY; FEEDBACK [#13-intellectual-property-feedback] ### 13.1. Encatch IP [#131-encatch-ip] The SDK and Documentation, and all intellectual property rights therein, are and will remain the exclusive property of Encatch and its licensors. No rights are granted to Customer other than as expressly set out in this SDK EULA. ### 13.2. Customer Materials [#132-customer-materials] Customer retains all rights in Customer's applications, websites, and content. ### 13.3. Feedback [#133-feedback] If Customer provides suggestions, ideas, or feedback regarding the SDK or the Service ("Feedback"), Customer grants Encatch a perpetual, irrevocable, worldwide, royalty-free license to use, reproduce, modify, create derivative works from, and otherwise exploit such Feedback for any purpose, without obligation to Customer. ## 14. THIRD-PARTY COMPONENTS; OPEN SOURCE [#14-third-party-components-open-source] ### 14.1. Third-Party Components [#141-third-party-components] The SDK may include or depend on third-party components, services, or libraries. Customer's use of such third-party components may be subject to additional terms provided by the applicable third party. ### 14.2. Open Source Software [#142-open-source-software] To the extent the SDK includes open source software, such open source software is licensed under the applicable open source license terms, which will control over this SDK EULA with respect to that open source software. ### 14.3. No Responsibility for Third Parties [#143-no-responsibility-for-third-parties] Encatch is not responsible for third-party components or services, including their availability, security, or functionality. ## 15. DISCLAIMERS [#15-disclaimers] ### 15.1. Disclaimer of Warranties [#151-disclaimer-of-warranties] To the maximum extent permitted by Applicable Law, the SDK and Documentation are provided "as is" and "as available" and Encatch disclaims all warranties of any kind, whether express, implied, statutory, or otherwise, including any implied warranties of merchantability, fitness for a particular purpose, title, and non-infringement. ### 15.2. No Guarantee [#152-no-guarantee] Encatch does not warrant that the SDK will be uninterrupted, error-free, secure, or compatible with Customer's systems, or that defects will be corrected. ### 15.3. Third-Party Services [#153-third-party-services] Encatch makes no warranties regarding third-party components or services used in connection with the SDK. ## 16. LIMITATION OF LIABILITY [#16-limitation-of-liability] ### 16.1. Exclusion of Damages [#161-exclusion-of-damages] To the maximum extent permitted by Applicable Law, in no event will Encatch be liable for any indirect, incidental, special, consequential, exemplary, or punitive damages, or for any loss of profits, revenues, data, goodwill, business interruption, or other intangible losses, arising out of or relating to the SDK or this SDK EULA, even if Encatch has been advised of the possibility of such damages. ### 16.2. Liability Cap [#162-liability-cap] To the maximum extent permitted by Applicable Law, Encatch's total aggregate liability arising out of or relating to the SDK or this SDK EULA will not exceed the amounts paid by Customer to Encatch for the Service in the six (6) months immediately preceding the event giving rise to the claim, or USD $100, whichever is greater. ### 16.3. Basis of Bargain [#163-basis-of-bargain] The parties acknowledge that the limitations in this Clause 16 are an essential basis of the bargain and reflect the allocation of risk between the parties. ## 17. INDEMNITIES [#17-indemnities] ### 17.1. Customer Indemnity [#171-customer-indemnity] Customer will defend, indemnify, and hold harmless Encatch and its affiliates, and their respective directors, officers, employees, and agents, from and against any third-party claims, damages, liabilities, costs, and expenses (including reasonable attorneys' fees) arising out of or relating to: (a) Customer's implementation, configuration, or use of the SDK; (b) Customer's applications, websites, or content; (c) Customer's breach of this SDK EULA or Applicable Law; or (d) Customer's failure to provide required notices or obtain required consents from Customer End Users. ### 17.2. Indemnification Process [#172-indemnification-process] Encatch will promptly notify Customer of any claim for which it seeks indemnification. Customer will have sole control of the defense and settlement of the claim, provided that Customer may not settle any claim in a manner that admits fault on behalf of Encatch or imposes any obligation on Encatch without Encatch's prior written consent (not to be unreasonably withheld). Encatch may participate in the defense with counsel of its choosing at its own expense. ## 18. TERM; TERMINATION; EFFECTS [#18-term-termination-effects] ### 18.1. Term [#181-term] This SDK EULA remains in effect for so long as Customer has a valid, active right to use the Service under the Terms of Service, unless terminated earlier in accordance with this Clause 18. ### 18.2. Automatic Termination [#182-automatic-termination] This SDK EULA will automatically terminate upon termination of the Terms of Service. ### 18.3. Termination by Encatch [#183-termination-by-encatch] Encatch may terminate this SDK EULA immediately upon notice if Customer materially breaches this SDK EULA or the Terms of Service and fails to cure such breach within a reasonable period after notice (if curable), or if Encatch reasonably determines that Customer's use of the SDK poses a security, legal, or abuse risk. ### 18.4. Termination by Customer [#184-termination-by-customer] Customer may terminate this SDK EULA at any time by ceasing all use of the SDK and uninstalling/removing the SDK from Customer's applications and websites. ### 18.5. Effect of Termination [#185-effect-of-termination] Upon termination, Customer will promptly cease all use of the SDK, delete or destroy all copies of the SDK and Documentation in Customer's possession or control, and cease distribution of the SDK. ### 18.6. Survival [#186-survival] Clauses that by their nature should survive termination will survive, including Clauses 4 (Restrictions), 13 (Intellectual Property; Feedback), 14 (Third-Party Components; Open Source), 15 (Disclaimers), 16 (Limitation of Liability), 17 (Indemnities), and 18 (Term; Termination; Effects). ## 19. GENERAL [#19-general] ### 19.1. Compliance with Laws [#191-compliance-with-laws] Customer will comply with Applicable Law in connection with its use of the SDK, including applicable export control and sanctions laws. ### 19.2. Assignment [#192-assignment] Customer may not assign or transfer this SDK EULA, in whole or in part, without Encatch's prior written consent. Any attempted assignment in violation of this Clause 19.2 is void. Encatch may assign this SDK EULA to an affiliate or in connection with a merger, acquisition, corporate reorganization, or sale of all or substantially all of its assets. ### 19.3. Severability [#193-severability] If any provision of this SDK EULA is held to be invalid or unenforceable, the remaining provisions will remain in full force and effect. ### 19.4. Waiver [#194-waiver] No failure or delay by either party in exercising any right under this SDK EULA will operate as a waiver of that right. ### 19.5. Force Majeure [#195-force-majeure] Neither party will be liable for any failure or delay in performance due to causes beyond its reasonable control. ### 19.6. Notices [#196-notices] Notices under this SDK EULA will be provided in accordance with the notice provisions in the [Terms of Service](/docs/legal/terms-of-service). ### 19.7. Governing Law; Disputes [#197-governing-law-disputes] Governing law and dispute resolution for this SDK EULA will be as set out in the [Terms of Service](/docs/legal/terms-of-service). # Terms of Service (/docs/legal/terms-of-service) # ENCATCH TERMS OF SERVICE [#encatch-terms-of-service] **Effective Date:** January 1, 2026 **Last Updated:** May 28, 2026 These Terms of Service (the "Terms") govern access to and use of the Encatch platform, including its dashboard, website ([https://encatch.com](https://encatch.com)), software development kits, APIs, integrations, and AI-enabled features, made available by Phyder Mobile Solutions Pvt. Ltd., a company incorporated in India with its registered office at 412/413, 4th Floor, Palmspring Above Croma, Link Road, Malad West, Mumbai City, Mumbai, Maharashtra, India, 400064 ("Encatch," "we," "us," or "our"). By clicking "I agree," creating an account, accessing, or using the Service, you confirm that you have read, understood, and agree to be bound by these Terms. If you are using the Service on behalf of an entity, you represent that you have authority to bind that entity, and "Customer," "you," and "your" refer to that entity. ## 1. INCORPORATED TERMS AND ORDER OF PRECEDENCE [#1-incorporated-terms-and-order-of-precedence] ### 1.1. Incorporated Terms [#11-incorporated-terms] These Terms incorporate by reference, and should be read together with, the following documents (each as updated from time to time): a. **Privacy Policy.** Our Privacy Policy (describing how we collect, use, and disclose personal data) available at: [Privacy Policy](/docs/legal/privacy-policy). b. **Data Processing Addendum (DPA).** Our Data Processing Addendum (the "DPA"), which applies where Encatch processes Customer End-User Feedback Data (and related Customer End User Identifiers) as a processor on behalf of the Customer, available at: [Data Processing Addendum](/docs/legal/data-processing-addendum) or provided upon request. c. **SDK License / EULA.** The Encatch SDK License / End User License Agreement (the "SDK EULA"), governing use of Encatch SDKs, code snippets, APIs and API Keys, available at: [SDK End User License Agreement](/docs/legal/sdk-eula). d. **Enterprise Agreement / Order Form.** Any separately executed enterprise agreement, order form, statement of work, or other written agreement between Encatch and the Customer (an "Enterprise Agreement"). ### 1.2. Order of Precedence [#12-order-of-precedence] In the event of any conflict or inconsistency between these Terms and any Incorporated Terms: a. An applicable Enterprise Agreement will control for that Customer, but only to the extent of the conflict. b. The DPA will control only with respect to data protection and processing terms (including any annexes) for Customer End-User Feedback Data (and related Customer End User Identifiers). c. The [SDK EULA](/docs/legal/sdk-eula) will control only with respect to SDK/API/license-specific terms (including permitted use, restrictions, and licensing). d. Otherwise, these Terms will control. ### 1.3. Document Updates [#13-document-updates] The Privacy Policy, DPA, and [SDK EULA](/docs/legal/sdk-eula) may be updated from time to time. Unless an Enterprise Agreement states otherwise, the versions posted or provided by Encatch at the time of use will apply; provided that Encatch will not apply changes retroactively to a then-current paid subscription term in a manner that materially reduces the Customer's rights or increases the Customer's obligations with respect to previously purchased subscriptions without notice. ## 2. DEFINITIONS [#2-definitions] For purposes of these Terms, the following definitions apply: **2.1. "Affiliate"** means, with respect to a party, any entity that directly or indirectly controls, is controlled by, or is under common control with that party. "Control" means the direct or indirect ownership of more than fifty percent (50%) of the voting interests of an entity, or the power to direct the management and policies of an entity (whether through ownership of voting securities, contract, or otherwise). **2.2. "AI Credits"** means units of consumption allocated under a Plan that are required to access certain AI Features. Unless otherwise specified in the applicable Plan, AI Credits reset on a monthly basis and do not carry forward. **2.3. "AI Features"** means AI-enabled features or functionalities made available within the Service that process inputs to generate AI Outputs, whether processed through Encatch systems and/or through third-party model providers (depending on configuration and compatibility). **2.4. "AI Outputs"** means any results, outputs, responses, classifications, summaries, tags, recommendations, suggested actions, generated content, or other materials produced by or through the AI Features. **2.5. "API"** means any application programming interface made available by Encatch as part of the Service, including associated endpoints, documentation, and access credentials. **2.6. "API Keys"** means the keys, tokens, credentials, identifiers, or other access mechanisms issued by or on behalf of Encatch to enable access to the SDKs and/or APIs. **2.7. "Authorized Users"** means the individuals authorized by Customer to access and use the Service on Customer's behalf (for example, Customer's employees and contractors), subject to these Terms and any usage limits under the applicable Plan. **2.8. "Content"** means any data, text, files, information, feedback, prompts, messages, materials, identifiers, or other content submitted, uploaded, transmitted, displayed, or otherwise made available by or on behalf of Customer or Customer End Users through the Service, including Customer End User Identifiers and Customer End-User Feedback Data. **2.9. "Customer"** means the entity or individual that accepts these Terms and on whose behalf the Service is accessed or used. If an individual accepts these Terms on behalf of an entity, then that entity is the Customer (and the individual represents they have authority to bind it). **2.10. "Customer Data"** means Content and other data that Customer or its Authorized Users provide to the Service, or that is collected or generated through Customer's use of the Service. Customer Data includes Customer End-User Feedback Data (and related Customer End User Identifiers), but excludes Usage Data. **2.11. "Customer End Users"** means end users of Customer's mobile application(s) and/or website(s) in which Customer deploys the SDKs or otherwise uses the Service to collect feedback, surveys, bug reports, or related data. **2.12. "Customer End User Identifier"** means an identifier provided by Customer (or Customer's application) to identify Customer End Users within the Service (for example, a user ID, email address, phone number, or hashed identifier), as configured by Customer. **2.13. "Customer End-User Feedback Data"** means the feedback content and submissions collected from or about Customer End Users via the SDKs (including survey responses, free-text inputs, ratings, selections, bug reports, and attachments if enabled), together with metadata associated with such submissions (for example, timestamps, project/workspace identifiers, and device/session context to the extent configured by Customer), and processed by Encatch as a processor on behalf of Customer under the DPA (where applicable). **2.14. "DPA"** has the meaning given in Clause 1.1(b). **2.15. "Encatch UUID"** means an internal unique identifier generated by Encatch to associate Customer End-User Feedback Data and related events within a Customer workspace or project, including by linking such data to a device identifier and/or to a Customer End User Identifier (if provided through an identifyUser (or similar) SDK/API call by Customer's application). **2.16. "Enterprise Agreement"** has the meaning given in Clause 1.1(d). **2.17. "Plan"** means the subscription tier or plan selected by Customer (including any free tier, trial, paid tier, add-ons, or enterprise plan), as described on Encatch's [pricing page](/pricing) or in an Enterprise Agreement, together with any applicable usage limits. **2.18. "SDK"** means the Encatch software development kits, snippets, libraries, scripts, and related integration artifacts (including any updates) made available to enable Customer to integrate feedback widgets, surveys, or related functionality into Customer's applications and websites. **2.19. "SDK EULA"** has the meaning given in Clause 1.1(c) ([SDK End User License Agreement](/docs/legal/sdk-eula)). **2.20. "Security Incident"** means a confirmed unauthorized access to, or unauthorized acquisition, use, disclosure, alteration, or destruction of, Customer Data (including Customer End User Identifiers) and/or Customer End-User Feedback Data within Encatch's systems, excluding unsuccessful attempts and events resulting from Customer's or Customer End Users' actions, credentials compromise, or Third-Party Services outside Encatch's reasonable control. **2.21. "Sensitive Data"** means any information that is subject to heightened protection or restrictions under applicable data protection laws, including (without limitation): (a) special category or sensitive personal data (such as data revealing health or medical information, biometric identifiers, genetic data, or information concerning an individual's sex life or sexual orientation); (b) government-issued identification numbers (such as Aadhaar, passport, driver's license, or similar identifiers); (c) financial information, including payment card data, bank account numbers, or other financial account credentials; (d) precise location data; and (e) any other information that applicable law requires to be handled with additional safeguards or consent requirements. **2.22. "Service"** has the meaning given in the introductory paragraph of these Terms. **2.23. "Third-Party Services"** means third-party websites, services, applications, integrations, tools, or platforms that interoperate with the Service or that Customer elects to use in connection with the Service (for example, integrations, webhooks, or external model providers), and any content or services provided by such third parties. **2.24. "Usage Data"** means aggregated and/or de-identified data relating to the use, performance, and operation of the Service (including usage metrics, feature adoption, and diagnostics), which does not identify Customer or Customer End Users in a manner that can reasonably be used to identify them. **2.25. "Usage Limits"** means any limits, caps, quotas, or restrictions applicable to Customer's Plan (for example, responses, active users, AI Credits, event volume, rate limits, storage, or other plan-based limits). ## 3. ACCEPTANCE, ELIGIBILITY, AND AUTHORITY [#3-acceptance-eligibility-and-authority] ### 3.1. Acceptance [#31-acceptance] These Terms are accepted, and become binding, when Customer (a) clicks "I agree" (or similar), (b) creates an account, or (c) accesses or uses the Service. Continued use of the Service constitutes continued acceptance of these Terms, as updated in accordance with Clause 1.3. ### 3.2. Authority [#32-authority] If you access or use the Service on behalf of an entity, you represent and warrant that you have the authority to bind that entity to these Terms. ### 3.3. Eligibility [#33-eligibility] You must be legally capable of entering into a binding contract to use the Service. The Service is not intended for use by individuals who are under the age of 18. ### 3.4. Compliance [#34-compliance] Customer will ensure that its Authorized Users comply with these Terms and is responsible for their acts and omissions in connection with the Service. ## 4. ACCOUNTS, ACCESS, AND AUTHORIZED USERS [#4-accounts-access-and-authorized-users] ### 4.1. Account Registration [#41-account-registration] To access the Service, Customer may be required to create an account and provide registration information. Customer will ensure that all information provided is accurate and kept up to date. ### 4.2. Admins; Workspace Control [#42-admins-workspace-control] Customer may designate one or more Authorized Users as administrators of Customer's workspace/account ("Admins"). Admins may manage Authorized Users, projects/workspaces, access permissions, configurations (including SDK/API settings), and integrations. Customer is responsible for Admin actions and for maintaining appropriate internal controls over admin access. ### 4.3. Authorized Users [#43-authorized-users] Customer may permit Authorized Users to access and use the Service on Customer's behalf and for Customer's internal operations and subject to these Terms and applicable Usage Limits. Customer will ensure that Authorized Users comply with these Terms and is responsible for their acts and omissions. ### 4.4. Credentials and Security [#44-credentials-and-security] Customer is responsible for maintaining the confidentiality of usernames, passwords, API Keys, and other access credentials, and for all activities that occur under Customer's account (including those of Authorized Users). Customer will promptly notify Encatch if it becomes aware of any unauthorized access to or use of Customer's account or credentials. ### 4.5. Account Sharing; Seat Integrity; Enforcement [#45-account-sharing-seat-integrity-enforcement] Customer will not (and will not permit any Authorized User to): (a) share, resell, rent, lease, sublicense, or otherwise make available any account, login credentials, or access rights to any person other than the specific Authorized User for whom such access was provisioned; (b) allow multiple individuals to use the same login credentials or account (including via shared inboxes, shared devices, or "generic" logins); or (c) use the Service for or on behalf of any third party, or permit access by any third party, except as expressly permitted in writing by Encatch. Encatch may use reasonable technical measures to detect unauthorized sharing or concurrent usage inconsistent with the applicable Plan and may suspend or restrict access pending verification. Customer remains responsible for all activity under its accounts and credentials. ### 4.6. Access Restrictions [#46-access-restrictions] Encatch may suspend, restrict, or terminate access to the Service in accordance with Clause 13 (Suspension and Termination), including where Encatch reasonably believes Customer's account has been compromised or is being used in violation of these Terms. ## 5. SCOPE OF SERVICE [#5-scope-of-service] ### 5.1. Service Overview [#51-service-overview] The "Service" is a software and technology platform that enables Customers to collect, ingest, transmit, store, organize, and manage feedback and related experience data from or about Customer End Users and Customer systems, and to generate insights, analytics, dashboards, visualizations, automations, and AI-assisted outputs to help Customers review, categorize, prioritize, route, and act on such data. The Service may be delivered through one or more components, which may include, without limitation: (a) a web-based dashboard and administrative console; (b) SDKs, APIs, widgets, scripts, code snippets, libraries, and related integration tools; (c) analytics, reporting, dashboards, and visualizations; (d) automations, workflows, alerts, routing, tagging, and data enrichment; (e) AI Features and AI Outputs; (f) integrations, webhooks, connectors, or other interoperability features with Third-Party Services; and (g) any updates, upgrades, modifications, or additional features or services that Encatch may make available from time to time. The Service may be provided through Encatch systems, third-party infrastructure, and/or a combination of local/on-device and cloud processing, depending on configuration, compatibility, and availability. ### 5.2. License Grant [#52-license-grant] Subject to these Terms, applicable Usage Limits, and payment of applicable fees, Encatch grants Customer a limited, non-exclusive, non-transferable, non-sublicensable, revocable right during the applicable subscription term to: a. access and use the Service (including the dashboard and any enabled AI Features) solely for Customer's own use and operations in connection with Customer's mobile application(s) and/or website(s) and Customer End Users, and not for the benefit of any third party; and b. integrate and distribute the SDK solely as an embedded component of Customer's mobile application(s) and/or website(s) to collect Customer End-User Feedback Data for Customer's own use and operations, and not for the benefit of any third party. ### 5.3. SDK Terms [#53-sdk-terms] Customer's use, integration, and distribution of the SDK (including any SDK code, snippets, libraries, and APIs/API Keys) is subject to the [SDK EULA](/docs/legal/sdk-eula). Customer will comply with the [SDK EULA](/docs/legal/sdk-eula) in addition to these Terms. ### 5.4. Configuration and Customer Control [#54-configuration-and-customer-control] Customer is responsible for selecting and configuring how it uses the Service (including which SDK/API settings, fields, prompts, integrations, and AI Features are enabled) and for ensuring its configuration complies with applicable laws and Customer's own policies. ### 5.5. Changes; Updates [#55-changes-updates] Encatch may modify, update, add, or remove features or functionality of the Service from time to time (including for security, compliance, performance, or product improvement). Encatch will use commercially reasonable efforts to avoid material adverse impacts to core Service functionality during a then-current paid subscription term. ### 5.6. Beta / Preview / "Coming Soon" Features [#56-beta--preview--coming-soon-features] Encatch may make certain features available in beta, preview, early access, pilot, "coming soon," or similar form. Such features may be subject to additional terms, may be modified or discontinued at any time, and are provided "as is" and "as available" without warranties or commitments regarding availability, performance, or continued support. ### 5.7. No Guaranteed Outcomes [#57-no-guaranteed-outcomes] The Service (including any AI Features) is intended to assist Customer's internal workflows and feedback operations. Encatch does not guarantee any specific business outcomes, accuracy, completeness, or results from use of the Service. ## 6. SDK AND API KEY USE [#6-sdk-and-api-key-use] ### 6.1. SDK EULA Governs [#61-sdk-eula-governs] Customer's access to, integration, distribution, and use of the SDKs, APIs, API Keys, code snippets, libraries, and related developer tools is subject to the [SDK EULA](/docs/legal/sdk-eula), which is incorporated by reference. In the event of any conflict between these Terms and the [SDK EULA](/docs/legal/sdk-eula) with respect to SDK or API usage, the [SDK EULA](/docs/legal/sdk-eula) shall control. ### 6.2. No White-Labeling or Standalone Use [#62-no-white-labeling-or-standalone-use] Customer will not, and will not permit any third party to, white-label, resell, sublicense, lease, or otherwise make the SDK or any feedback-collection functionality available as a standalone product or service, or as part of a service bureau, managed service, or similar offering, except as expressly permitted in writing by Encatch. ### 6.3. No Circumvention of Controls [#63-no-circumvention-of-controls] Customer will not bypass, interfere with, or circumvent any access controls, technical limitations, Usage Limits, rate limits, metering mechanisms, or other restrictions applicable to the Service, SDKs, APIs, or API Keys, including by sharing credentials, creating duplicate accounts, or using automated or programmatic means to evade plan limits. ## 7. CUSTOMER RESPONSIBILITIES AND ACCEPTABLE USE [#7-customer-responsibilities-and-acceptable-use] ### 7.1. Customer Responsibilities [#71-customer-responsibilities] Customer is responsible for (a) its and its Authorized Users' use of the Service, SDKs, APIs, and API Keys, (b) configuring the Service (including fields, prompts, integrations, routing, and any AI Features) in accordance with these Terms and applicable laws, and (c) ensuring that its internal policies and instructions to Authorized Users align with how Customer deploys the SDK and collects Customer End-User Feedback Data. ### 7.2. Customer End-User Notices and Consents [#72-customer-end-user-notices-and-consents] Customer will provide all notices and obtain all consents, authorizations, and rights required to (a) deploy the SDK in Customer's mobile application(s) and/or website(s), (b) collect and transmit Customer End-User Feedback Data and any Customer End User Identifiers to Encatch, (c) enable any integrations or data transfers to Third-Party Services, and (d) use AI Features in connection with Customer End-User Feedback Data (including where such processing may occur via cloud-based model providers depending on configuration and compatibility). Customer is solely responsible for the content of any end-user disclosures shown through Customer's application(s) or website(s). ### 7.3. Prohibited Data; Sensitive Data Restrictions [#73-prohibited-data-sensitive-data-restrictions] Customer will not (and will not permit Customer End Users to) submit, upload, transmit, or otherwise make available through the Service any Sensitive Data, including any personal data treated as special category/sensitive under Applicable Law, and including government-issued identification numbers, payment card data, bank account details, precise health or medical information, biometric identifiers, or similar regulated sensitive categories. Encatch does not monitor, screen, or filter Customer Data to detect or prevent submission of Sensitive Data, and Customer is solely responsible for configuring its feedback flows (including fields, prompts, and warnings/notices) to minimize and avoid collection of Sensitive Data. If Customer anticipates that Sensitive Data may be processed through the Service (whether intentionally or inadvertently), Customer must promptly notify Encatch and ensure it has provided all required notices and obtained all required consents/authorizations and lawful bases under Applicable Law. To the extent Sensitive Data is processed through the Service, the parties' obligations regarding such processing will be governed by the Sensitive Data section (or equivalent enhanced safeguards provisions) of the DPA, and Customer remains responsible for compliance with Applicable Law in relation to its collection and provision of such data to Encatch. ### 7.4. Acceptable Use [#74-acceptable-use] Customer will not, and will not permit any Authorized User, Customer End User, or third party to: (a) use the Service in violation of applicable laws or regulations; (b) upload or transmit unlawful, infringing, defamatory, or harmful content; (c) use the Service to store or transmit malware or other harmful code; (d) interfere with or disrupt the integrity or performance of the Service, SDKs, APIs, or Third-Party Services; (e) attempt to gain unauthorized access to the Service, systems, networks, or data; (f) probe, scan, or test the vulnerability of the Service except as expressly authorized in writing by Encatch; or (g) use the Service for high-risk activities where failure could result in death, personal injury, or property damage (including emergency response or life-safety systems). ### 7.5. No Competitive Misuse [#75-no-competitive-misuse] Customer will not (and will not permit any third party to) use the Service, Customer Data, or any AI Outputs to build, benchmark, or improve a competing product or service, including by scraping or extracting data from the Service in a systematic manner beyond ordinary use. ### 7.6. No Unauthorized Data Collection or Scraping [#76-no-unauthorized-data-collection-or-scraping] Customer will not use the Service to collect, ingest, or process data in a manner that violates third-party rights or applicable law, including by uploading or importing (via CSV/JSON or otherwise) data that was collected without proper notice or consent or in breach of contractual or legal restrictions. Customer is responsible for ensuring it has a lawful basis to provide Customer End-User Feedback Data and Customer End User Identifiers to Encatch for processing. ### 7.7. Compliance with Usage Limits and Policies [#77-compliance-with-usage-limits-and-policies] Customer will comply with these Terms, the [SDK EULA](/docs/legal/sdk-eula), and all Usage Limits and technical restrictions applicable to its Plan. Customer will not misrepresent usage metrics, manipulate event generation, or otherwise attempt to distort billing, limits, or reporting. ## 8. CUSTOMER DATA, OWNERSHIP, AND LICENSE [#8-customer-data-ownership-and-license] ### 8.1. Customer Data Ownership [#81-customer-data-ownership] As between Encatch and Customer, Customer retains all right, title, and interest in and to Customer Data. Customer is solely responsible for the accuracy, quality, legality, and manner of acquisition of Customer Data (including ensuring it has all required rights, permissions, notices, and lawful basis/consents to provide Customer Data to Encatch for processing). ### 8.2. License to Encatch [#82-license-to-encatch] Customer grants Encatch a limited, worldwide, non-exclusive, royalty-free right during the applicable subscription term to host, store, transmit, reproduce, process, and otherwise use Customer Data solely to: (a) provide, operate, maintain, secure, support, and improve the Service; provided that, to the extent Customer Data constitutes Customer End-User Feedback Data (and related Customer End User Identifiers) processed by Encatch as a processor on Customer's behalf, Encatch's use of such data for "improvement" is limited to what is necessary to provide, maintain, secure, and support the Service in accordance with Customer's documented instructions and the DPA (and does not include training, fine-tuning, or improving any machine learning or generative models except as expressly agreed in writing); (b) implement Customer's configurations and instructions provided through the Service (including routing, workflows, tagging, and integrations enabled by Customer); (c) generate AI Outputs and other results requested by Customer or its Authorized Users through use of AI Features (subject to Clause 9); and (d) comply with applicable law and enforce these Terms. ### 8.3. Data Processing Roles; DPA [#83-data-processing-roles-dpa] To the extent Customer Data includes Customer End-User Feedback Data and related Customer End User Identifiers processed by Encatch on Customer's behalf, the DPA (if applicable) governs the parties' respective data protection roles and obligations. Customer acknowledges that Encatch may act as an independent controller for certain account, billing, and administrative data, as described in the Privacy Policy. For clarity, Encatch processes Customer End-User Feedback Data as a processor on Customer's documented instructions under the DPA (where applicable). ### 8.4. Customer Instructions; Integrations [#84-customer-instructions-integrations] Customer controls and is responsible for (a) the configurations it selects (including SDK settings, fields, prompts, and data collection parameters), and (b) any Third-Party Services, integrations, webhooks, or connectors it enables. Customer authorizes Encatch to transfer Customer Data to such Third-Party Services as directed or initiated by Customer, and Customer is responsible for third-party terms and any downstream processing. ### 8.5. Feedback and Suggestions [#85-feedback-and-suggestions] If Customer or its Authorized Users submit suggestions, ideas, enhancement requests, feedback, or recommendations about the Service (excluding Customer Data) ("Feedback"), Customer grants Encatch a perpetual, irrevocable, worldwide, transferable, sublicensable, royalty-free license to use and incorporate such Feedback into the Service and related offerings without restriction or compensation. ### 8.6. Usage Data and Aggregated Insights [#86-usage-data-and-aggregated-insights] Encatch may collect and use Usage Data to operate, maintain, protect, and improve the Service, develop new features, and generate aggregated analytics and benchmarks. Usage Data and any aggregated or de-identified outputs derived from Customer's use of the Service will be maintained in a manner intended not to reasonably identify Customer, Customer End Users, or any individual. ### 8.7. No Sale of Customer Data [#87-no-sale-of-customer-data] Encatch does not sell Customer Data. Encatch will access and use Customer Data only as permitted under these Terms and, where applicable, the DPA, and as described in the Privacy Policy. ## 9. AI FEATURES AND AI CREDITS [#9-ai-features-and-ai-credits] ### 9.1. AI Features; Assistive Use Only [#91-ai-features-assistive-use-only] The Service may include AI Features that generate AI Outputs based on Customer Data and configurations selected by Customer. AI Features are provided as assistive tools to support Customer's internal workflows, analysis, and decision-making. Customer acknowledges that AI Outputs may be probabilistic, incomplete, or inaccurate and must be reviewed and validated by humans before being relied upon. AI Outputs do not constitute professional, legal, medical, or other regulated advice. ### 9.2. No Guaranteed Accuracy or Outcomes [#92-no-guaranteed-accuracy-or-outcomes] Encatch does not guarantee the accuracy, completeness, reliability, or suitability of any AI Outputs. Customer is solely responsible for evaluating and using AI Outputs, including determining whether they are appropriate for Customer's intended use. Customer will not use AI Outputs as the sole basis for decisions that produce legal effects concerning an individual or similarly significantly affect an individual, without meaningful human review, except as permitted under Applicable Law and subject to appropriate safeguards. ### 9.3. No AI Training on Customer Data by Default [#93-no-ai-training-on-customer-data-by-default] Encatch will not use Customer Data to train, fine-tune, or improve any of its own machine learning or generative AI models unless expressly agreed in writing by Customer (for example, in an Enterprise Agreement or written addendum). Use of AI Features may involve processing via third-party model providers depending on configuration and compatibility, as described in the Privacy Policy and DPA (where applicable). ### 9.4. AI operational logs [#94-ai-operational-logs] Operational logs indicating when AI Features are invoked/triggered are generally retained for one (1) month in active records and may remain in backups for up to ninety (90) days, unless required by law or legal hold. ### 9.5. Customer Use and Configuration of AI Features [#95-customer-use-and-configuration-of-ai-features] Depending on the Plan, Service configuration, and the capabilities made available in the Service from time to time, AI Features may be enabled by default and may run as part of configured workflows. Customer is responsible for its use of the Service where AI Features are enabled in its workflows and for determining what Customer Data is submitted, routed, or made available to AI Features through Customer's use of the Service (including through prompts, workflow design, and any integrations Customer enables). Customer is responsible for ensuring that its use of AI Features complies with Applicable Law and Customer's internal policies, including providing required notices and obtaining required consents where applicable. Encatch may maintain operational logs relating to AI Feature usage for security, troubleshooting, and audit purposes, retained in accordance with Encatch's retention practices. ### 9.6. AI Credits; Usage Limits [#96-ai-credits-usage-limits] AI Credits (including any add-on or additional AI Credits) are issued, metered, and usable only in accordance with the applicable Plan details (including as presented in the Service, pricing page, or checkout flow) or Enterprise Agreement (as applicable), including any stated validity period, expiry, reset frequency, and carry-forward rules. Unless expressly stated otherwise in those Plan details or an Enterprise Agreement, AI Credits do not carry forward and expire as described therein. ### 9.7. Suspension or Limitation of AI Features [#97-suspension-or-limitation-of-ai-features] If Customer exhausts applicable AI Credits or exceeds Usage Limits, Encatch may suspend or limit access to the relevant AI Features until Customer upgrades, purchases additional credits, or the applicable usage period resets. ### 9.8. Regulatory and High-Risk Use Restrictions [#98-regulatory-and-high-risk-use-restrictions] Customer will not use AI Features for high-risk or regulated activities where failure or inaccuracy could result in death, personal injury, legal liability, or significant harm (including emergency response, medical diagnosis, or safety-critical systems), unless expressly approved in writing by Encatch. ## 10. INTEGRATIONS AND THIRD-PARTY SERVICES [#10-integrations-and-third-party-services] ### 10.1. Customer-initiated integrations [#101-customer-initiated-integrations] The Service may support integrations, webhooks, connectors, or other interoperability with Third-Party Services. Customer controls whether to enable or use any Third-Party Services and is solely responsible for its decision to connect them to the Service. ### 10.2. Third-party terms [#102-third-party-terms] Customer's use of any Third-Party Services is governed by the applicable third party's terms, policies, and agreements (including any fees charged by such third parties). Encatch does not control and is not responsible for Third-Party Services, including their availability, security, functionality, or any acts or omissions of the applicable third party. ### 10.3. Data transfers at Customer instruction [#103-data-transfers-at-customer-instruction] If Customer enables a Third-Party Service or configures an integration, webhook, or connector, Customer authorizes Encatch to transmit, disclose, and otherwise process Customer Data to and from that Third-Party Service, to the extent reasonably necessary to provide the integration as configured or initiated by Customer through the Service. Customer is responsible for ensuring it has all necessary rights, notices, and lawful bases/consents to enable such transfers and any downstream processing by the Third-Party Service. ### 10.4. No liability for third-party outages or downstream processing [#104-no-liability-for-third-party-outages-or-downstream-processing] Encatch will not be liable for (a) any interruption, failure, error, or loss caused by Third-Party Services, or (b) any access to, use of, or processing of Customer Data by a Third-Party Service (including any deletion, modification, or disclosure of Customer Data by such third party), except to the extent directly caused by Encatch's breach of these Terms. ### 10.5. Disabling integrations [#105-disabling-integrations] Customer may disable or remove integrations through the Service (where supported). Disabling an integration may prevent further data transfers to the relevant Third-Party Service but may not delete Customer Data already transferred to such Third-Party Service. Customer is responsible for managing deletion, retention, and access controls within the applicable Third-Party Service. ## 11. FEES, BILLING, TAXES, AND REFUNDS [#11-fees-billing-taxes-and-refunds] ### 11.1. Plans; usage limits [#111-plans-usage-limits] Access to the Service may be subject to a Plan, applicable fees, and applicable Usage Limits. Plan details (including included-features, caps/limits, trial or promotional access, grace periods (if any), renewal terms (if any), and any add-ons) are as described in the Service, pricing page, checkout flow, and/or an Enterprise Agreement (as applicable). ### 11.2. Billing model; merchant-of-record / payment processing [#112-billing-model-merchant-of-record--payment-processing] Payments for the Service may be processed by Encatch and/or through one or more third-party payment processors or a merchant-of-record provider. Customer authorizes Encatch (and its payment processor/merchant-of-record, as applicable) to charge Customer's selected payment method for all amounts due in accordance with the applicable Plan details, checkout flow, the Billing Policy, and/or an Enterprise Agreement. ### 11.3. Fees; due dates; failed payments [#113-fees-due-dates-failed-payments] Fees are due and payable in advance unless otherwise stated in the applicable Plan details, checkout flow, the Billing Policy, or an Enterprise Agreement. If Customer's Plan is offered on an auto-renewing basis, renewal (and renewal timing) will occur as described in the applicable Plan details, checkout flow, the Billing Policy, or an Enterprise Agreement. Where Customer has internal credits stored with Dodo Payments, Encatch may apply those credits to eligible future charges, including subscription renewals, as described in the applicable Plan details, checkout flow, the Billing Policy, or an Enterprise Agreement. If a payment fails or is reversed, Encatch may (a) re-attempt the charge, (b) require Customer to update payment information, and/or (c) suspend or limit access to the Service until payment is received, without limiting any other rights or remedies. ### 11.4. Refunds and cancellations [#114-refunds-and-cancellations] Refunds (if any), cancellation timing, internal credits stored with Dodo Payments, and related billing mechanics are governed by Encatch's then-current billing/refund/cancellation policy available at: [https://encatch.com/docs/billing/billing-faq](https://encatch.com/docs/billing/billing-faq) (the "Billing Policy"). Unless the Billing Policy, applicable law, or an applicable Enterprise Agreement expressly states otherwise, fees are non-refundable and Customer will not be entitled to cash refunds or payouts to a card, bank account, payment provider balance, or other payment channel for partial periods. Internal credits stored with Dodo Payments, where provided under the Billing Policy, are credits for eligible future Encatch charges and are not cash refunds. ### 11.5. Upgrades; downgrades; plan changes [#115-upgrades-downgrades-plan-changes] If Customer upgrades its Plan, changes between paid Plans, or purchases add-ons, Customer authorizes Encatch to charge the applicable amounts as described in the Service, pricing page, checkout flow, the Billing Policy, or an Enterprise Agreement. Changes between paid Plans may take effect immediately, may reset the billing cycle to the date of change, and may result in internal credits stored with Dodo Payments for unused paid-plan value, each as described in the Billing Policy, checkout flow, or an Enterprise Agreement. Moving from a paid Plan to a free Plan takes effect only after the then-current paid billing cycle is completed, unless the Billing Policy or an Enterprise Agreement expressly states otherwise. ### 11.6. Caps/limits; no implied overages [#116-capslimits-no-implied-overages] Unless expressly stated otherwise in the applicable Plan details, checkout flow, the Billing Policy, or an Enterprise Agreement, Customer will not be charged "overage" fees solely because Customer approaches or exceeds a Usage Limit. If Customer reaches or exceeds applicable Usage Limits, Encatch may (depending on the feature and Plan) provide notice, throttle usage, restrict or suspend the relevant feature(s), require an upgrade or add-on purchase, and/or resume access when the applicable usage period resets, each as described in the Service, pricing page, checkout flow, the Billing Policy, or an Enterprise Agreement. ### 11.7. Taxes [#117-taxes] Fees are exclusive of applicable taxes, duties, or government charges (including GST), which may be added and collected as required by law, unless the applicable pricing page, checkout flow, or Enterprise Agreement expressly states that taxes are included in the displayed price. Where Encatch uses a merchant-of-record or payment processor that collects and remits taxes on Encatch's behalf, such taxes will be handled through that provider as described in the checkout flow or the provider's terms. Customer is responsible for all other taxes associated with its purchase of the Service, except for taxes based on Encatch's net income. ### 11.8. Invoices; purchase orders; bank transfer (enterprise only) [#118-invoices-purchase-orders-bank-transfer-enterprise-only] If invoicing, purchase orders, or bank transfer payment terms are offered, they apply only if expressly agreed in writing by Encatch (for example, in an Enterprise Agreement). Any invoice is payable in accordance with the payment terms stated on the invoice or in the Enterprise Agreement. ### 11.9. Billing communications [#119-billing-communications] Customer agrees that Encatch may send billing and account-related notices (including receipts, renewal reminders, and payment failure notices) to the email address associated with Customer's account and/or to Admins. ## 12. SUPPORT, MAINTENANCE, AND AVAILABILITY [#12-support-maintenance-and-availability] ### 12.1. Support [#121-support] Encatch will use commercially reasonable efforts to provide support for the Service through the support channels described in the Service or on Encatch's support pages (if any). Unless expressly agreed in an Enterprise Agreement, Encatch does not guarantee any specific response or resolution times. ### 12.2. Maintenance; updates [#122-maintenance-updates] Encatch may perform maintenance, updates, upgrades, or repairs to the Service from time to time. Encatch may make the Service (or portions of it) temporarily unavailable for maintenance or operational reasons, including emergency maintenance. ### 12.3. Availability; no SLA [#123-availability-no-sla] The Service is provided on an "as available" basis. Unless expressly stated in an Enterprise Agreement, Encatch does not provide any uptime service level agreement (SLA) or service credits for downtime, interruptions, or unavailability. ### 12.4. Third-party dependencies [#124-third-party-dependencies] Customer acknowledges that the Service may rely on third-party infrastructure and Third-Party Services. Encatch is not responsible for outages, interruptions, or performance issues caused by third parties outside Encatch's reasonable control. ### 12.5. Changes to support and availability [#125-changes-to-support-and-availability] Encatch may change its support offerings, maintenance practices, and availability features from time to time, provided that Encatch will use commercially reasonable efforts to avoid material adverse impacts to core Service functionality during a then-current paid subscription term. ## 13. SUSPENSION AND TERMINATION [#13-suspension-and-termination] ### 13.1. Suspension [#131-suspension] Encatch may suspend or limit Customer's or any Authorized User's access to the Service (in whole or in part) immediately upon notice (or, where not practicable, as soon as reasonably practicable) if Encatch reasonably believes that: a. fees are past due or a payment has failed; b. the Service is being used in violation of these Terms, the [SDK EULA](/docs/legal/sdk-eula), applicable law, or applicable Usage Limits; c. Customer's account, credentials, or use poses a security risk to the Service or to any data, systems, or users; d. suspension is necessary to comply with law, a court order, or a governmental request; or e. Customer's use could materially harm Encatch, the Service, or third parties. For billing failures, Encatch may provide a short grace period or limited functionality access as described in the Service or Billing Policy, but is not required to do so. ### 13.2. Restoration [#132-restoration] Where feasible, Encatch will restore access after the event giving rise to the suspension is resolved (for example, payment is received, the security risk is mitigated, or the violation is cured). Encatch may require Customer to take reasonable corrective actions as a condition to restoration. ### 13.3. Termination by Customer [#133-termination-by-customer] Customer may cancel its Plan as described in the Service, pricing page, checkout flow, the Billing Policy, or an Enterprise Agreement. Unless stated otherwise therein, cancellation or a move from a paid Plan to a free Plan will be effective at the end of the then-current paid billing period, and Customer will remain responsible for all amounts due through the effective date of cancellation. ### 13.4. Termination for Cause [#134-termination-for-cause] Either party may terminate these Terms (or an applicable Enterprise Agreement) for material breach by the other party if such breach is not cured within thirty (30) days after written notice; provided that Encatch may terminate immediately upon notice if Customer's breach is not curable or involves: a. non-payment; b. unlawful use, abuse of the Service, or security-related harm; or c. unauthorized access, circumvention, or misuse of the Service, SDKs, APIs, or API Keys. ### 13.5. Effect of Termination [#135-effect-of-termination] Upon the effective date of termination or cancellation: a. Customer's right to access and use the Service will end (and Encatch may disable access); b. Customer remains responsible for all fees accrued through the effective date; and c. Encatch's obligations regarding retention, deletion, and export of Customer Data are governed by Clause 14 (Retention, Deletion, and Backups), the Privacy Policy, the DPA (if applicable), and any applicable Enterprise Agreement. ### 13.6. Data export window (if offered) [#136-data-export-window-if-offered] If the Service provides self-service export functionality or Encatch offers an export window as described in the Service, the Billing Policy, the [Privacy Policy](/docs/legal/privacy-policy), the [DPA](/docs/legal/data-processing-addendum), or an Enterprise Agreement, Customer may export Customer Data during that period. Encatch is not responsible for any deletion or loss of Customer Data after the applicable retention/export period ends. ### 13.7. Survival [#137-survival] Any provisions that by their nature should survive termination will survive, including restrictions, confidentiality (if applicable), disclaimers, limitation of liability, indemnities, and dispute resolution terms. ## 14. RETENTION, DELETION, AND BACKUPS [#14-retention-deletion-and-backups] ### 14.1. Retention during an active account [#141-retention-during-an-active-account] During Customer's subscription term (and subject to Customer's configuration choices), Customer Data is retained and made available in the Service in accordance with the applicable Plan details and the Service's functionality. For clarity, retention periods for specific categories of Customer Data (including Customer End-User Feedback Data) may vary based on the applicable Plan and Customer's retention configuration (for example, selecting a feedback data retention window such as 3 months up to 2 years), and apply during the active subscription term. ### 14.2. Account inactivity (admin) [#142-account-inactivity-admin] If Customer's admin account is inactive (not logged in) for a continuous period of six (6) months, Encatch may notify Customer (using the email address associated with the account and/or Admin contacts) up to three (3) times, at one (1) month intervals. If Customer does not respond or access the account following such notices, Encatch may suspend or terminate the account and mark the associated Customer Data for deletion, subject to Clause 14.7 (Legal hold) and any applicable retention/export periods described in Clause 14.4. ### 14.3. Deletion on request [#143-deletion-on-request] Customer may request deletion of Customer Data as described in the Service, Privacy Policy, or DPA (if applicable). Encatch will process deletion requests in a commercially reasonable timeframe, subject to: (a) verification of the requester's authority, (b) technical feasibility, and (c) any applicable legal retention or legal hold requirements. ### 14.4. Post-termination retention; export [#144-post-termination-retention-export] After cancellation or termination, Encatch may retain Customer Data for a limited period as described in the Service, Plan details, checkout flow, the Billing Policy, the Privacy Policy, the DPA (if applicable), or an Enterprise Agreement, to allow account close-out, billing reconciliation, support requests, and (if offered) data export. Unless expressly stated otherwise in those sources, the default post-termination retention period will not exceed sixty (60) days, after which Customer Data may be deleted from active systems, subject to Clause 14.7. Where self-service export is not available, Customer may request export via Encatch support, as described in the Service or support pages (if any). ### 14.5. Backup deletion [#145-backup-deletion] After Customer Data is deleted from active systems, Encatch will use commercially reasonable efforts to delete it from backups within forty-five (45) days, unless a longer period is required by law or applicable legal hold. For clarity, this Clause 14.5 applies to Customer Data deleted from active systems and does not apply to operational logs retained in accordance with Clause 9.4. ### 14.6. Transient metadata and logs [#146-transient-metadata-and-logs] Certain technical, diagnostic, and operational data (including auto-captured device/app metadata and similar properties) may be transmitted to Encatch systems for processing. Where such properties are not enabled by Customer for storage, reporting, or use as persistent attributes, Encatch will process them transiently and use commercially reasonable efforts to discard them from active records within one (1) month, subject to legal hold requirements. If Customer enables such properties for reporting/storage, retention will follow the applicable Plan details and the Service's functionality. ### 14.7. Legal hold [#147-legal-hold] Notwithstanding anything else in these Terms, Encatch may retain Customer Data where required to comply with applicable law, lawful requests, or to establish, exercise, or defend legal claims. ## 15. PUBLICITY; CUSTOMER MARKS (OPT-OUT) [#15-publicity-customer-marks-opt-out] ### 15.1. Use of Customer name and logo [#151-use-of-customer-name-and-logo] Subject to this Clause 15, Customer grants Encatch a limited, non-exclusive, non-transferable, revocable license during the subscription term (unless revoked earlier) to use Customer's name, logo, and trademarks ("Customer Marks") solely to identify Customer as a user of the Service (for example, on [Encatch's website](https://encatch.com), sales materials, and marketing listings). For clarity, Encatch will not use any individual's name, likeness, or testimonial relating to Customer without Customer's prior written consent. ### 15.2. No endorsement [#152-no-endorsement] Encatch's use of Customer Marks will not imply any sponsorship, endorsement, partnership, or affiliation, and Encatch will not issue press releases or case studies about Customer without Customer's prior written consent (email is sufficient). ### 15.3. Brand guidelines [#153-brand-guidelines] If Customer provides reasonable written brand/trademark guidelines, Encatch will use commercially reasonable efforts to comply with them. ### 15.4. Opt-out / revocation [#154-opt-out--revocation] Customer may revoke the license in Clause 15.1 at any time by written notice delivered in accordance with Clause 22 (Notices). ### 15.5. Removal timing [#155-removal-timing] After receiving a valid revocation notice, Encatch will use commercially reasonable efforts to (a) remove Customer Marks from [Encatch's website](https://encatch.com) within five (5) business days, and (b) remove Customer Marks from other non-website marketing materials in the next standard update/revision cycle, (or sooner where reasonably practicable). ### 15.6. Enterprise override [#156-enterprise-override] If an applicable Enterprise Agreement includes publicity or trademark terms, those terms will control to the extent of any conflict. ## 16. CONFIDENTIALITY [#16-confidentiality] ### 16.1. Confidential Information [#161-confidential-information] "Confidential Information" means any non-public information disclosed by or on behalf of a party ("Disclosing Party") to the other party ("Receiving Party") in connection with the Service or these Terms, whether disclosed in writing, orally, visually, electronically, or by inspection, that (a) is marked or designated as confidential, or (b) reasonably should be understood to be confidential given the nature of the information and the circumstances of disclosure. Confidential Information includes: (i) the Service and any non-public features, roadmaps, pricing, plans, discounting, and performance information; (ii) non-public technical information, architecture, APIs, security measures, vulnerabilities, and any Security Incident-related details; (iii) any non-public business, financial, product, and go-to-market information; (iv) the terms of any Enterprise Agreement (if applicable) and any non-public communications relating to support or account management; and (v) all copies, extracts, analyses, compilations, and derivative materials of the foregoing. For clarity, Customer Data is addressed under Clause 8 and the DPA (if applicable). Any non-public Customer Data accessed by Encatch for support will be treated as Confidential Information under this Clause 16. ### 16.2. Protection and permitted use [#162-protection-and-permitted-use] The Receiving Party will protect the Disclosing Party's Confidential Information using at least (a) the same degree of care it uses to protect its own confidential information of a similar nature, and (b) the reasonable industry-standard degree of care for information of that type, in each case, whichever is higher, and in no event less than reasonable care. ### 16.3. Permitted disclosures; Representatives [#163-permitted-disclosures-representatives] The Receiving Party may disclose Confidential Information to its employees, contractors, and professional advisors ("Representatives") who have a need to know for the permitted purpose and who are bound by confidentiality obligations at least as protective as these Terms. The Receiving Party is responsible for any breach of this Clause 16 by its Representatives. ### 16.4. Exclusions [#164-exclusions] Confidential Information does not include information that the Receiving Party can demonstrate: (a) is or becomes publicly available through no breach of these Terms; (b) was lawfully known to the Receiving Party without restriction before receipt from the Disclosing Party; (c) is lawfully received from a third party without restriction and without breach of any obligation owed to the Disclosing Party; or (d) was independently developed by the Receiving Party without use of or reference to the Disclosing Party's Confidential Information. ### 16.5. Compelled disclosure [#165-compelled-disclosure] If the Receiving Party is required by law, regulation, or a valid court or governmental order to disclose Confidential Information, it may do so provided that, where legally permitted, it gives the Disclosing Party prompt notice and reasonably cooperates (at the Disclosing Party's expense) to seek confidential treatment or limit the disclosure. The Receiving Party will disclose only the minimum Confidential Information required. ### 16.6. Remedies [#166-remedies] The Receiving Party acknowledges that unauthorized disclosure or use of Confidential Information may cause irreparable harm for which monetary damages may be inadequate. The Disclosing Party may seek injunctive or equitable relief, in addition to any other remedies available at law. ### 16.7. Survival [#167-survival] This Clause 16 will survive termination or expiration of these Terms for three (3) years; provided that obligations relating to trade secrets will survive for so long as such information remains a trade secret under applicable law. ## 17. SECURITY AND SECURITY INCIDENT HANDLING [#17-security-and-security-incident-handling] ### 17.1. Reasonable security measures [#171-reasonable-security-measures] Encatch will implement and maintain commercially reasonable administrative, technical, and organizational safeguards designed to protect Customer Data against unauthorized access, use, disclosure, alteration, or destruction. Such safeguards may include measures relating to access controls, encryption (where appropriate), network security, and monitoring. Encatch does not warrant that the Service will be completely secure or free from vulnerabilities. ### 17.2. Shared responsibility [#172-shared-responsibility] Customer acknowledges that security is a shared responsibility. Customer is responsible for (a) configuring the Service appropriately, (b) maintaining the security of its account credentials and API Keys, (c) controlling access by Authorized Users, and (d) securing its own systems, devices, and integrations with Third-Party Services. ### 17.3. Notification of Security Incident [#173-notification-of-security-incident] In the event of a confirmed Security Incident affecting Customer Data within Encatch's systems, Encatch will notify Customer without undue delay and, where feasible, within seventy-two (72) hours after Encatch becomes aware of the confirmed Security Incident. Notice may be provided by email to Customer's Admin contact(s) or through the Service. ### 17.4. Incident response and cooperation [#174-incident-response-and-cooperation] Encatch will take commercially reasonable steps to contain, investigate, and mitigate the effects of a Security Incident. Encatch will provide information reasonably requested by Customer to assist Customer in meeting its own legal obligations, subject to confidentiality and security limitations. Any additional assistance beyond Encatch's standard incident response may be provided at Customer's expense, as agreed. ### 17.5. Limitations [#175-limitations] Encatch will not be responsible for Security Incidents or breaches resulting from (a) Customer's or Authorized Users' acts or omissions, (b) compromised credentials not caused by Encatch, (c) Customer's configuration choices, or (d) Third-Party Services outside Encatch's reasonable control. ## 18. WARRANTIES AND DISCLAIMERS [#18-warranties-and-disclaimers] ### 18.1. Service provided "as is" and "as available" [#181-service-provided-as-is-and-as-available] Except as expressly stated in an Enterprise Agreement, the Service (including the SDKs, APIs, integrations, and any AI Features) is provided on an "as is" and "as available" basis. ### 18.2. No implied warranties [#182-no-implied-warranties] TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, ENCATCH DISCLAIMS ALL WARRANTIES AND REPRESENTATIONS OF ANY KIND, WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, NON-INFRINGEMENT, AND ANY WARRANTIES ARISING OUT OF COURSE OF DEALING OR USAGE OF TRADE. ### 18.3. No guarantee of uninterrupted or error-free service [#183-no-guarantee-of-uninterrupted-or-error-free-service] Encatch does not warrant that the Service will be uninterrupted, timely, secure, or error-free, or that defects will be corrected, or that the Service will be free of viruses or other harmful components. ### 18.4. AI Features and AI Outputs disclaimers [#184-ai-features-and-ai-outputs-disclaimers] Customer acknowledges that AI Outputs may be probabilistic, incomplete, inaccurate, or inappropriate for Customer's use case. Encatch disclaims any warranty regarding the accuracy, completeness, reliability, or suitability of AI Outputs. Customer is solely responsible for reviewing and validating AI Outputs before relying on them, and for determining whether AI Outputs are appropriate for Customer's intended use. ### 18.5. Third-Party Services and integrations [#185-third-party-services-and-integrations] Encatch does not warrant and is not responsible for any Third-Party Services, including their availability, security, functionality, or any acts or omissions of third parties. Any integration is provided for convenience and may be modified, interrupted, or discontinued. ### 18.6. Beta/preview features [#186-betapreview-features] Any beta, preview, early access, pilot, or "coming soon" features are provided "as is" and "as available," may contain errors or limitations, and may be changed or discontinued at any time. ### 18.7. Data and compliance responsibility [#187-data-and-compliance-responsibility] Customer is responsible for (a) configuring and using the Service in compliance with applicable laws, (b) obtaining all notices, consents, and rights required for its collection and use of Customer Data, and (c) maintaining appropriate backups or exports of Customer Data where needed. ### 18.8. No professional advice [#188-no-professional-advice] The Service and any AI Outputs do not constitute legal, medical, financial, or other professional advice, and Customer should not rely on them as such. ### 18.9. Jurisdictional limitation [#189-jurisdictional-limitation] Some jurisdictions do not allow the exclusion of certain warranties, so some of the above disclaimers may not apply to Customer. In such cases, Encatch's warranties are limited to the minimum scope permitted by applicable law. ## 19. LIMITATION OF LIABILITY [#19-limitation-of-liability] ### 19.1. Exclusion of indirect damages [#191-exclusion-of-indirect-damages] To the maximum extent permitted by applicable law, in no event will Encatch be liable for any indirect, incidental, special, consequential, exemplary, or punitive damages, or for any loss of profits, revenue, goodwill, business, anticipated savings, or data, arising out of or relating to the Service or these Terms, even if Encatch has been advised of the possibility of such damages. ### 19.2. Liability cap [#192-liability-cap] To the maximum extent permitted by applicable law, Encatch's total aggregate liability arising out of or relating to the Service or these Terms will not exceed the fees paid (or payable) by Customer to Encatch for the Service in the six (6) months immediately preceding the event giving rise to the claim. ### 19.3. Basis of the bargain [#193-basis-of-the-bargain] Customer acknowledges that the fees reflect the allocation of risk under these Terms and that the limitations in this Clause 19 form an essential basis of the bargain between the parties. ### 19.4. Exceptions [#194-exceptions] Nothing in these Terms excludes or limits Encatch's liability to the extent it cannot be excluded or limited under applicable law. Without limiting the foregoing, the exclusions and cap in this Clause 19 will not apply to liability of Encatch arising from Encatch's fraud or willful misconduct. ### 19.5. Third-Party Services [#195-third-party-services] Without limiting Clause 10, Encatch will not be liable for any interruption, failure, security issue, or loss caused by Third-Party Services or third-party infrastructure outside Encatch's reasonable control. ## 20. INDEMNITIES [#20-indemnities] ### 20.1. Customer indemnity [#201-customer-indemnity] Customer will defend, indemnify, and hold harmless Encatch, its Affiliates, and their respective directors, officers, employees, and agents from and against any third-party claims, demands, suits, proceedings, damages, losses, liabilities, costs, and expenses (including reasonable attorneys' fees) arising out of or relating to: a. Customer Data or any content submitted, uploaded, transmitted, or otherwise made available by or on behalf of Customer or Customer End Users through the Service (including any allegation that such content infringes, misappropriates, or violates any third-party rights); b. Customer's failure to provide required notices, obtain required consents, or establish a lawful basis to collect, use, and provide Customer Data (including Customer End-User Feedback Data and any Customer End User Identifiers) to Encatch for processing; c. Customer's deployment, configuration, or use of the Service, SDKs, APIs, or API Keys in violation of these Terms, the [SDK EULA](/docs/legal/sdk-eula), applicable law, or any Usage Limits; d. Customer's integrations with, or use of, Third-Party Services (including webhooks/connectors) and any downstream processing or disclosure of Customer Data by such third parties; e. Customer's use of the Service to collect, ingest, import, or process data (including via CSV/JSON or similar imports) in a manner that violates applicable law or third-party rights; and f. Any acts or omissions of Customer's Authorized Users or Customer End Users in connection with the Service. ### 20.2. Indemnity procedure [#202-indemnity-procedure] Encatch will: a. promptly notify Customer in writing of any indemnified claim (provided that any delay will not relieve Customer of its obligations except to the extent materially prejudiced by the delay); b. give Customer control of the defense and settlement of the claim (provided that Customer may not settle any claim in a manner that imposes any admission of liability or obligation on Encatch without Encatch's prior written consent, not to be unreasonably withheld); and c. provide reasonable cooperation at Customer's expense. Encatch may participate in the defense with counsel of its choosing at its own expense. ### 20.3. Enterprise IP indemnity (if applicable) [#203-enterprise-ip-indemnity-if-applicable] Any intellectual property indemnity by Encatch (if offered) will apply only if expressly set out in an Enterprise Agreement, and will be subject to the terms, conditions, exclusions, and remedies stated therein. ## 21. IP AND PROPRIETARY RIGHTS [#21-ip-and-proprietary-rights] ### 21.1. Encatch IP [#211-encatch-ip] As between the parties, Encatch and its licensors retain all right, title, and interest in and to the Service, including the dashboard, software, SDKs, APIs, API Keys, integrations, AI Features, AI Outputs (to the extent not consisting of Customer Data), documentation, and all related technology and intellectual property rights. Except for the limited rights expressly granted in these Terms (and the [SDK EULA](/docs/legal/sdk-eula), as applicable), no rights are granted to Customer, whether by implication, estoppel, or otherwise. ### 21.2. Customer Data [#212-customer-data] As between Encatch and Customer, Customer retains all right, title, and interest in and to Customer Data, subject to the license granted to Encatch under Clause 8.2 and, where applicable, the DPA. ### 21.3. Feedback [#213-feedback] Customer (and its Authorized Users) may provide Feedback as described in Clause 8.5. Encatch may use such Feedback in accordance with Clause 8.5. ### 21.4. Restrictions; no reverse engineering [#214-restrictions-no-reverse-engineering] Except to the extent prohibited by applicable law, Customer will not (and will not permit any third party to): (a) copy, modify, or create derivative works of the Service; (b) reverse engineer, decompile, disassemble, or otherwise attempt to derive source code or underlying ideas or algorithms of the Service; (c) remove or alter proprietary notices; or (d) use the Service to build, benchmark, or improve a competing product or service (including by systematic scraping or extraction beyond ordinary use). SDK-specific restrictions (including SDK distribution, API Keys, and developer tooling) are governed by the [SDK EULA](/docs/legal/sdk-eula). ### 21.5. Open-source software [#215-open-source-software] The Service, SDKs, or related components may include or incorporate open-source software ("OSS"). OSS is licensed to Customer under the applicable OSS license terms (not these Terms), and those OSS license terms will control with respect to the OSS components. Where required, Encatch will make applicable OSS notices available in the documentation, within the SDK/package, or on Encatch's website/support pages. ### 21.6. Customer Marks [#216-customer-marks] Customer grants Encatch only the limited rights to use Customer Marks described in Clause 15. Except as expressly stated in Clause 15, Encatch will not use Customer Marks without Customer's consent. ### 21.7. Reservation of rights [#217-reservation-of-rights] Each party reserves all rights not expressly granted under these Terms. ## 22. NOTICES [#22-notices] ### 22.1. Method of notice [#221-method-of-notice] Except as otherwise expressly stated in these Terms, any legal notice required or permitted under these Terms must be in writing and will be deemed given: a. when delivered personally; b. one (1) business day after being sent by reputable overnight courier; or c. when sent by email to the designated notice email address, provided no bounce-back or delivery failure message is received. ### 22.2. Notice to Encatch [#222-notice-to-encatch] Legal notices to Encatch must be sent by email to [privacy@encatch.com](mailto:privacy@encatch.com) and by courier, registered post, or speed post to: Phyder Mobile Solutions Pvt. Ltd. 412/413, 4th Floor, Palmspring (Above Croma) Link Road, Malad West Mumbai City, Mumbai, Maharashtra 400064 India ### 22.3. Notice to Customer [#223-notice-to-customer] Notices to Customer will be sent to the email address associated with Customer's account or to any designated Admin contact. ### 22.4. Operational communications [#224-operational-communications] Service-related communications (including billing notices, security alerts, support communications, and general updates) may be provided through the Service, dashboard notifications, or email, and will be deemed effective when sent. ### 22.5. Change of contact details [#225-change-of-contact-details] Either party may update its notice details by providing written notice in accordance with this Clause 22. ## 23. GOVERNING LAW; DISPUTE RESOLUTION [#23-governing-law-dispute-resolution] ### 23.1. Governing law [#231-governing-law] These Terms and any dispute or claim (including non-contractual disputes or claims) arising out of or relating to the Service or these Terms will be governed by and construed in accordance with the laws of India. ### 23.2. Exclusive jurisdiction (Mumbai) [#232-exclusive-jurisdiction-mumbai] The courts at Mumbai, Maharashtra, India will have exclusive jurisdiction over (a) any dispute, claim, or proceeding arising out of or relating to these Terms (including any question regarding their existence, validity, or termination), (b) any application for interim or injunctive relief (including under the Arbitration and Conciliation Act, 1996), and (c) any application relating to the arbitration (including appointment of the arbitrator, interim measures, supervisory jurisdiction, and enforcement of any arbitral award). For clarity, arbitration under Clause 23.4 will be the final method of resolving disputes on the merits, and the courts at Mumbai will be approached only for interim relief and arbitration-related court applications. ### 23.3. Good-faith negotiations; mediation (pre-arbitration) [#233-good-faith-negotiations-mediation-pre-arbitration] Before commencing arbitration, a party must deliver a written notice of dispute describing the nature of the dispute, the relief sought, and the basis for its position. The parties will use good faith efforts to resolve the dispute informally for fifteen (15) days after the notice of dispute is received (the "Negotiation Period"). If the dispute is not resolved within the Negotiation Period, either party may propose mediation in Mumbai, India (in English). Unless the parties agree otherwise in writing, mediation will be non-binding and will not extend beyond thirty (30) days from the date the mediation is initiated. If the dispute is not resolved through negotiation/mediation, either party may commence arbitration by submitting a notice of arbitration in accordance with Clause 23.4. ### 23.4. Arbitration [#234-arbitration] Any dispute, controversy, or claim arising out of or relating to the Service or these Terms, including their existence, validity, interpretation, performance, breach, termination, or enforceability, will be finally resolved by arbitration administered by the Mumbai Centre for International Arbitration (MCIA) in accordance with the MCIA Rules in force when the notice of arbitration is submitted. ### 23.5. Seat, venue, language; tribunal [#235-seat-venue-language-tribunal] The seat (and legal place) of arbitration will be Mumbai, India. The venue of hearings will be Mumbai, India (or such other place / remote mode as the tribunal may determine). The arbitration will be conducted in English. The tribunal will consist of one (1) arbitrator. ### 23.6. Confidentiality [#236-confidentiality] The parties will keep the existence of the arbitration, all arbitral communications, and all materials and awards confidential, except to the extent disclosure is required by law, to enforce an award, or to seek interim relief. ### 23.7. Continuity [#237-continuity] During the pendency of any dispute, each party will continue to perform its undisputed obligations under these Terms to the extent commercially reasonable. ## 24. GENERAL TERMS [#24-general-terms] ### 24.1. Assignment [#241-assignment] Customer may not assign or transfer these Terms (or any rights or obligations under them) without Encatch's prior written consent. Encatch may assign these Terms without Customer's consent (a) to an Affiliate, or (b) in connection with a merger, acquisition, corporate reorganization, or sale of all or substantially all of Encatch's assets. Any attempted assignment in violation of this Clause 24.1 is void. Subject to the foregoing, these Terms bind and benefit the parties and their permitted successors and assigns. ### 24.2. Force majeure [#242-force-majeure] Neither party will be liable for any delay or failure to perform (other than payment obligations) due to events beyond its reasonable control, including acts of God, natural disasters, war, terrorism, riots, civil unrest, labor disputes, government actions, epidemics/pandemics, internet or telecommunications failures, power outages, and failures of third-party hosting or infrastructure providers ("Force Majeure Event"). The affected party will use commercially reasonable efforts to mitigate the effects of the Force Majeure Event. ### 24.3. Severability [#243-severability] If any provision of these Terms is held to be invalid, illegal, or unenforceable, the remaining provisions will remain in full force and effect, and the invalid provision will be modified to the minimum extent necessary to make it enforceable while preserving the parties' intent as closely as possible. ### 24.4. Waiver [#244-waiver] No failure or delay by either party in exercising any right or remedy under these Terms will operate as a waiver of that right or remedy. Any waiver must be in writing and signed by the party granting the waiver. A waiver of any breach will not be a waiver of any other breach. ### 24.5. Relationship of the parties [#245-relationship-of-the-parties] The parties are independent contractors. Nothing in these Terms creates a partnership, joint venture, agency, fiduciary relationship, or employment relationship between the parties. Customer has no authority to bind Encatch. ### 24.6. Entire agreement [#246-entire-agreement] These Terms, together with the Incorporated Terms (and any applicable Enterprise Agreement), constitute the entire agreement between the parties regarding the Service and supersede all prior or contemporaneous understandings, communications, or agreements on that subject matter. In the event of any conflict, the order of precedence in Clause 1.2 will apply. ### 24.7. Changes to these Terms [#247-changes-to-these-terms] Encatch may update these Terms from time to time. Unless an Enterprise Agreement states otherwise, updated Terms will be effective when posted in the Service or on Encatch's website (or otherwise made available to Customer). If a change materially reduces Customer's rights or materially increases Customer's obligations, Encatch will use commercially reasonable efforts to provide notice (for example, via the Service or email). Continued use of the Service after the effective date of an update constitutes acceptance of the updated Terms. ### 24.8. Survival [#248-survival] Clauses that by their nature should survive termination or expiration will survive, including (as applicable) Clauses 1–2, 7–11, 13–14, 16–24, and any disclaimers, limitations of liability, indemnities, and dispute resolution provisions. # SDK Rate Limits (/docs/sandbox-limits/rate-limits) We enforce rate limits to prevent abuse and ensure that the APIs (called from SDKs for feedback fetching and submission) is used fairly by all users. These limits apply when using our [Web SDK](/docs/sdk-reference/web) and [Mobile SDKs](/docs/sdk-reference/mobile-sdk/flutter). ### Rate Limit Enforcement [#rate-limit-enforcement] Rate limits are applied per project, per contact/user ID, and per IP address. The following table shows the limits for each environment type: #### Production projects [#production-projects] | Limit scope | Requests per minute | | --------------------- | ------------------- | | Per project | 40,000 | | Per contact / user ID | 100 | | Per IP address | 300 | #### Sandbox projects [#sandbox-projects] Sandbox projects are designed to let you test during implementation and throughout ongoing project development. They are not intended for production use. Their limits are set to avoid exhausting our systems while still supporting development workflows. | Limit scope | Requests per minute | | --------------------- | ------------------- | | Per project | 50 | | Per contact / user ID | 10 | | Per IP address | 50 | #### Rate Limit Headers [#rate-limit-headers] When you make requests to the API, you'll receive rate limit information in the response headers: * `X-RateLimit-Limit`: The maximum number of requests allowed per time window * `X-RateLimit-Remaining`: The number of requests remaining in the current time window * `X-RateLimit-Reset`: The time at which the current rate limit window resets (Unix timestamp in seconds) #### Handling Rate Limits [#handling-rate-limits] When you exceed the rate limit, you'll receive a `429 Too Many Requests` response. You should: 1. Wait for the rate limit window to reset 2. Implement exponential backoff in your application 3. Consider caching responses to reduce API calls These limits apply to **publishable SDK** traffic. Admin API keys use a separate per-project and per-key quota — see [Admin API rate limits](/docs/api-reference#rate-limits). # Sandbox Environment (/docs/sandbox-limits/sandbox-environment) When creating a new project, administrators choose whether the project should be created as a **Sandbox** or **Production** environment. This choice is fixed at project creation and cannot be changed later. Sandbox is designed for setup, implementation, and validation, but its value goes beyond the initial launch phase. It gives developers a safe place to integrate the SDK, test triggers, forms, and events, and verify end-to-end behavior without affecting live production activity. It also gives product managers room to review flows, confirm experience details, and align teams before changes are exposed to real users. This matters because teams often need to configure, test, and iterate not only during onboarding, but also as an ongoing part of product development. Sandbox helps you validate new events, forms, and behavior changes in a controlled environment without being charged too early in the integration process or testing directly in production. ## Why Use Sandbox [#why-use-sandbox] * **Avoid production usage charges during setup:** Activity in Sandbox does not consume your standard usage allocation while your team is still integrating and validating the product experience. * **Support implementation and review workflows:** Developers can test integrations confidently, while product managers can review the user journey before rollout. * **Keep tighter control over production access:** Teams can allow developers to work freely in Sandbox while limiting Production access to product owners or product managers responsible for approving and publishing live experiences. * **Use it as an ongoing testing environment:** Sandbox is useful for continuous validation, allowing teams to test new forms, events, and experience changes outside the live production environment. * **Reduce go-live risk:** Sandbox makes it easier to catch setup issues, validate configurations, and confirm expected behavior before you create or use a Production project. Sandbox usage does not consume standard product usage, but **AI Credits are still charged** when AI-powered capabilities are used. ## Rate Limits [#rate-limits] Sandbox environments have lower rate limits than Production. This helps protect the platform while still providing enough capacity for testing and validation. Refer to the [Rate Limits](/docs/sandbox-limits/rate-limits) page for the current limits and guidance. ## Feature Limits Per Project [#feature-limits-per-project] Sandbox projects have the following limits per project. | Feature | Sandbox Value | | ------------------------------ | ----------------- | | Feedback Responses | As per rate limit | | AI Credits | As per rate limit | | Destination Messages | As per rate limit | | Events Tracked | As per rate limit | | Page Views Tracked | As per rate limit | | Remove Branding | Available | | IP Whitelisting | Available | | Throttling | Available | | Projects | As per rate limit | | Feedback Retention | 30 days | | Active Feedback Configurations | 10 configurations | | Draft Feedback Configurations | 5 configurations | | Monthly Active Users | 50 users | | Active Destinations | 5 destinations | | Destinations | 5 destinations | | Segments | 5 segments | | Unique User Traits | 150 traits | | Unique Tracked Events | 150 events | | Shareable Links | 50 links | | Publishable SDK Keys | 10 keys | | API Rate Limit | 0 requests/min | | Admin Members | — | | Admin Roles | — | | Experiments | 5 experiments | | In-App Feedback | Available | ## Choosing the Right Environment [#choosing-the-right-environment] Create a Sandbox project when your team needs a safe environment for integration work, validation, ongoing testing, and internal review. This is the right choice when developers are implementing or updating events, forms, and triggers, or when product managers want to verify the experience before exposing changes to live users. Sandbox is also useful when you want different levels of access across teams. For example, product owners or product managers may retain control over Production, while developers are given access to Sandbox during implementation. This allows the team to build and validate confidently, while keeping the final production-ready forms under the control of the people responsible for launching them. Create a Production project when the experience is ready for real users, live traffic, and production usage tracking. # Data-driven Segments (/docs/segmentation/data-driven) **Use when:** You want dynamic groups based on user traits, tracked events, feedback interaction, or past survey answers. ## What are data-driven segments? [#what-are-data-driven-segments] A data-driven segment is a group of users that updates automatically based on conditions you define. Users **enter** the segment when they match your rules and **leave** when they no longer match. In the dashboard, data-driven segments appear with a **Dynamic** badge. Membership changes as encatch receives new user data, feedback activity, or tracked events, without you editing the list manually. ## What data can you use? [#what-data-can-you-use] You can add as many conditions as needed to define a segment. encatch supports **filter groups** so you can combine conditions with AND/OR logic. All condition types below can be mixed in a single segment. When you click **Add condition**, choose one of: * **User Traits** * **Tracked Events** * **Feedback Interaction** * **Feedback Response** ### User Traits [#user-traits] **User Traits** are attributes on the user profile. They appear when you choose **User Traits** from **Add condition**. In the trait list: * **User Traits**: System fields and custom traits (for example `email`, `device_os`, `plan`) * **Account Data**: Account-related traits Examples of system fields: `user_name`, `display_name`, `email`, `first_seen_at`, `last_seen_at`, `feedback_views_count`, `feedback_response_count`, `device_os`, `browser`, `sdk_version`. Custom traits are sent when identifying users via [`identifyUser`](/docs/sdk-reference/web#2-identify-users) or the API. See [User Traits](/docs/settings/user-data/user-traits) to configure traits. **Operators by data type** (labels as shown in the UI): | Data type | Operators | | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Text** | Equals, Does not equal, Contains, Does not contain, Starts with, Does not start with, Ends with, Does not end with, Is one of, Is not one of, Value exists, Value does not exist | | **Numeric** | Equals, Does not equal, Greater than, Less than, Greater than or equals, Less than or equals, Value exists, Value does not exist | | **Boolean** | Is True, Is False, Value exists, Value does not exist | | **Datetime** | Less than … ago, More than … ago, After (fixed date), Before (fixed date), Value exists, Value does not exist | Traits dropdown - Search and select traits Company trait condition with text operators and value ### Feedback Response [#feedback-response] **Feedback Response** conditions filter users by **what they answered** on a past feedback form. When adding a condition: 1. Choose **Feedback Response** from **Add condition**. 2. Select the **feedback form** and **question**. 3. Choose which **response** to evaluate when a user has multiple submissions: * **All responses** * **Specific** response (for example First, Second, Third, or Last, Second last, Third last) * **First** or **Last** N responses (2 or 3), matching if any of those responses meet the condition 4. Set the **operator** and **value** based on question type. Supported question types include rating, NPS, CSAT, opinion scale, single choice, multiple choice, picture choice, ranking, nested selection, matrix questions, short/long text, yes/no, consent, email, website, and more. Operators vary by type. For example, NPS supports *is*, *is not*, *is greater than*, *is between*; single choice supports *is*, *is any of*, *is none of*. **Examples:** * NPS **is** 9 or 10 on "Customer Satisfaction Survey" (promoters). * CSAT **is less than or equals** 2 on a support survey (detractors). * Single choice **is** "Enterprise" on a plan question. ### Feedback Interaction [#feedback-interaction] **Feedback Interaction** conditions filter users by **form engagement**, not by answer content. Interaction types: | Type | Meaning | | ---------------------- | ------------------------------------------ | | **Feedback Seen** | The form was shown to the user | | **Feedback Not Seen** | The form was not shown to the user | | **Feedback Started** | The user started the form | | **Feedback Dismissed** | The user closed the form before submitting | | **Feedback Completed** | The user submitted the form | | **Feedback Answered** | The user answered at least one question | For each interaction, choose: * **Feedback form**: Any Feedback Form, or a specific form * **Timeframe**: Last 24 hours, Last 48 hours, Last 7 days, Last 14 days, Last 30 days, Last 90 days, Last 180 days, Last 365 days, or All time **Examples:** * **Feedback Completed** on "Onboarding Survey" in the last 30 days. * **Feedback Seen** on "Pricing Survey" but **Feedback Completed** did not occur (use two conditions in a filter group). ### Tracked Events [#tracked-events] **Tracked Events** conditions filter users by **in-app actions** sent via `trackEvent()` in the SDK or API. Operators: * **Event occurred** * **Event did not occur** * **Event occurred at least…** (with a count) * **Event occurred at most…** (with a count) Set a **timeframe** (same options as Feedback Interaction) for when the event should be counted. **Examples:** * `checkout_completed` **occurred** at least once in the last 7 days. * `feature_used` **did not occur** in the last 30 days. Configure event slugs in [Tracked Events](/docs/settings/user-data/tracked-events) before using them in segments. ### Filter groups and match logic [#filter-groups-and-match-logic] Within a filter group: * **Match all filters**: Every condition in the group must be true (AND). * **Match any filter**: At least one condition must be true (OR). Across groups: * Use **Add filter group** for more complex logic. * Combine groups with **Match all** or **Match any** of the groups. You can mix User Traits, Tracked Events, Feedback Interaction, and Feedback Response in the same segment. **Example:** *Group 1* (`plan` equals enterprise) **AND** *Group 2* (NPS **is less than or equals** 6 on "Q1 NPS"). Segment Conditions with multiple groups ## Create a data-driven segment [#create-a-data-driven-segment] ### Step 1: Open Segments [#step-1-open-segments] In the encatch dashboard, click **Segments** in the left sidebar. The page shows your existing segments (including **All Users**) and a **New Segment** button. Segments in sidebar and list view ### Step 2: Create a new segment [#step-2-create-a-new-segment] Click **New Segment** and configure: * **Name of segment**: A label (e.g. "Enterprise detractors"). Max 250 characters. * **Description (optional)**: Short purpose note. * **Segment type**: Select **Data Driven Segment**. Create new segment - Name, description, and segment type Segment type selection - Data-driven vs Manual ### Step 3: Add conditions [#step-3-add-conditions] In the **Segment Conditions** section, click **Add condition** and choose one of: * **User Traits**: Filter by user properties * **Tracked Events**: Filter by user behavior * **Feedback Interaction**: Feedback seen, started, completed, etc. * **Feedback Response**: Filter by what users answered Configure each condition in the dialog that opens. Add more conditions and filter groups as needed. Segment Conditions - Add condition ### Step 4: Live Preview [#step-4-live-preview] While building conditions, use **Live Preview** at the bottom of the page to see a sample of matching users before you save. * Shows up to **50 users** who match your current conditions. * Click **Refresh** after changing conditions to update the preview. * If you change conditions without refreshing, the preview may show as outdated until you refresh again. ### Step 5: Save the segment [#step-5-save-the-segment] Click **Create segment**. encatch rebuilds membership for all users in the project. During rebuild: * A **Segment is being rebuilt** banner appears on the segment page. * Depending on the size of your user base, this may take a few minutes. * The segment appears in the list with a **Dynamic** badge when saved. Segments list - All Users, dynamic, and manual segments ## Update a data-driven segment [#update-a-data-driven-segment] On a data-driven segment page: * **Update conditions**: Opens the edit page where you can change segment conditions. Saving triggers a full rebuild. * **Edit segment** (dropdown): Change name or description. * **Delete segment** (dropdown): Permanently remove the segment. **Delete restrictions:** If the segment is used by a feedback form (or another consumer), deletion is blocked and you will see which items reference it. Remove the segment from those places first, then delete. ## When are segments updated? [#when-are-segments-updated] encatch updates segment membership in two ways: ### Per-user updates [#per-user-updates] When significant user activity occurs, encatch re-evaluates whether that user still matches each data-driven segment. This includes when: * A user is identified via `identifyUser` * A user sees, starts, completes, or dismisses a feedback form * A new tracked event is recorded for the user * A user submits a feedback response ### Full rebuild [#full-rebuild] A full rebuild runs when you: * Create a new data-driven segment * Save updated conditions on an existing segment During a rebuild, encatch checks every user in the project against the segment rules. The member table refreshes automatically when the rebuild completes. ## View and manage members [#view-and-manage-members] Click a segment in the list to open its member table. **Default columns** (for new segments): Username (always visible), Display Name, Email, First seen at, Last seen at, Feedback Views Count, Last feedback submission. **Search and sort:** Find users by email, username, or display name. Use **Sort by** and filters to organize the list. **Custom columns:** Use the column settings control to show or hide trait columns in the table. **User detail:** Click a user to open the detail drawer with these tabs: * **Feedback Activity** (includes expandable past responses) * **Traits** * **Segments** * **Tracked Events** **Show info:** View segment name, description, member count, created/updated timestamps, and last calculation time. **Bulk actions:** Select users and use **Actions** to: * **Add to segment**: Copy selected users into a **manual** segment * **Delete Users**: Permanently delete selected users from the project You cannot remove individual users from a data-driven segment. Membership is controlled by conditions only. Segment members table with search and sort ## Summary [#summary] | Step | Action | | ---- | ------------------------------------------------------------------------ | | 1 | Open **Segments** from the sidebar | | 2 | Click **New Segment** and choose **Data Driven Segment** | | 3 | Enter name and optional description | | 4 | Add conditions (traits, events, feedback interaction, feedback response) | | 5 | Use **Live Preview** to verify matching users | | 6 | Click **Create segment** (rebuild runs) | | 7 | View members, customize columns, and inspect users in the detail drawer | ## Related [#related] * [Segmentation overview](/docs/segmentation/overview) * [Manual segments](/docs/segmentation/manual) * [User Traits](/docs/settings/user-data/user-traits) * [Tracked Events](/docs/settings/user-data/tracked-events) * [Logged-in Users targeting](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/logged-in-users) # Manual Segments (/docs/segmentation/manual) Manual segments let you freely group users in encatch. You add and remove users yourself. The list stays fixed until you change it. Manual segments do not update automatically based on user data. A username is the same unique identifier used in [`identifyUser`](/docs/sdk-reference/web#2-identify-users). In the dashboard, manual segments appear with a **Manual** badge. **Use when:** You need a static, hand-picked list (e.g., beta testers, VIP users, custom cohorts for one-off surveys). ## Workflow Overview [#workflow-overview] 1. Open **Segments** from the sidebar 2. Click **New Segment** and choose **Manual Segment** 3. Click **Create segment** to create the empty segment 4. Add users by username import or from the member table 5. View, search, add, or remove users in the segment ## Step 1: Open Segments [#step-1-open-segments] In the encatch dashboard, click **Segments** in the left sidebar. The Segments page shows your existing segments (including **All Users**) and a **New Segment** button. Segments in sidebar and list view ## Step 2: Create a New Segment [#step-2-create-a-new-segment] Click **New Segment** to open the **Create new segment** form. Configure: * **Name of segment**: A label for the segment (e.g., "Beta testers"). Max 250 characters. * **Description (optional)**: A short description of the segment's purpose (e.g., "Users invited to beta product feedback"). * **Segment type**: Select **Manual Segment**. Create new segment - Name, description, and segment type Segment type selection - Data-driven vs Manual ## Step 3: Save the Segment [#step-3-save-the-segment] Click **Create segment** (or **Save** for edits) to create the segment. It will appear in the Segments list with a **Manual** tag. You can start adding users after saving. Segments list - All Users, dynamic, and manual segments ## Step 4: Add Users [#step-4-add-users] There are two ways to add users to a manual segment. ### Import users by username [#import-users-by-username] 1. Click the segment in the list to open it. 2. Click **Add users** in the segment header. 3. In the **Add Users to Segment** modal, enter usernames separated by commas or new lines. 4. Follow these rules: * No spaces in a username * Max 255 characters per username * Max 1000 usernames per submission * Users that don't exist are created automatically with that username 5. Click **Add Users** (or **Add N User(s)**) to confirm. The Add Users modal matches users by username (`user_name`), not by the Email trait. If you enter `john@example.com`, encatch looks for a user whose username is exactly `john@example.com`. It does not look up a user whose email trait is `john@example.com`. Use each person's actual username. Empty segment state - Add users prompt The modal validates each username before the users are added and updates the confirmation button to show how many valid users were detected. ### Add users from the member table [#add-users-from-the-member-table] You can also add users from any segment or **All Users** list: 1. Open a segment (or **All Users**) and select users in the member table. 2. Open the **Actions** menu. 3. Choose **Add to segment**. 4. Select an existing **manual** segment. This is useful when you find users while browsing and want to add them without typing usernames. The target must be a manual segment. You cannot add users into a data-driven segment this way. ## Step 5: View and Manage Members [#step-5-view-and-manage-members] The segment page shows a table with default columns such as Username, Display Name, Email, and Feedback Views Count. Use column settings to show or hide other trait columns. Use the search bar to find users by email, username, or name. Use **Sort by** and filters to organize the list. Segment members table with search and sort Click **Show info** to view the segment's name, description, member count, created/updated timestamps, and last calculation time. ### Bulk actions [#bulk-actions] Select users in the table, then use the **Actions** menu: * **Remove from segment**: Remove selected users from this manual segment. This does not delete them from the project. * **Add to segment**: Copy selected users into another manual segment. * **Delete Users**: Permanently delete selected users from the project. ### Manual vs data-driven bulk actions [#manual-vs-data-driven-bulk-actions] | Action | Manual | Data-driven | All Users | | --------------------------- | ------ | ----------- | --------- | | Remove from segment | Yes | No | No | | Add to a manual segment | Yes | Yes | Yes | | Delete Users (from project) | Yes | Yes | Yes | Data-driven segment membership is controlled by conditions. You cannot remove users manually from a dynamic segment. You can still copy selected users into a manual segment, or delete them from the project. ## Update and delete a manual segment [#update-and-delete-a-manual-segment] **Edit name or description:** Open the segment dropdown and choose **Edit segment**. **Delete segment:** 1. Open the segment dropdown and choose **Delete segment**. 2. If the segment is used by a feedback form (or another consumer), deletion is blocked. You will see which items reference the segment. Remove it from those places first. 3. If the segment is not in use, type the segment name to confirm deletion. This permanently removes the segment and its membership data. ## Summary [#summary] | Step | Action | | ---- | ----------------------------------------------------- | | 1 | Open **Segments** from the sidebar | | 2 | Click **New Segment** and choose **Manual Segment** | | 3 | Enter name and optional description | | 4 | Click **Create segment** (or **Save**) | | 5 | Add users by username import or from the member table | | 6 | View and manage members; use bulk actions as needed | ## Related [#related] * [Segmentation overview](/docs/segmentation/overview) * [Data-driven segments](/docs/segmentation/data-driven) * [Logged-in Users targeting](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/logged-in-users) # Overview (/docs/segmentation/overview) **Segments** let you organize users in encatch based on shared attributes or behavior. A segment is a group of users who meet criteria you define. For manual segments, it is a list you curate yourself. The **Segments** page in the dashboard shows **All Users** (every identified user in your project) and any segments you create. Use segments to control who sees your feedback forms, compare responses by audience, and run targeted campaigns. ## Segment types [#segment-types] encatch supports three kinds of segments: | Type | UI label | How it works | When to use | | --------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------- | | **All Users** | All Users (no badge) | Contains every identified user in the project. You cannot edit, delete, rename, or change membership of this segment. | Baseline audience, browsing all users in the project | | **Data-driven** | Dynamic | Users enter and leave automatically when they match (or stop matching) the conditions you set. Membership updates as encatch receives new user data, feedback activity, or tracked events. | Dynamic groups based on traits, behavior, feedback history, or survey answers | | **Manual** | Manual | You add and remove users by username. The list stays fixed until you change it. | Beta testers, VIPs, one-off lists from spreadsheets or external tools | Docs refer to **Data-driven** segments. In the dashboard, these appear with a **Dynamic** badge. When creating a segment, the option is labeled **Data Driven Segment**. ### Data-driven vs Manual [#data-driven-vs-manual] | | Data-driven | Manual | | :------------- | :--------------------------------------------------- | :-------------------------------------------- | | **Membership** | Automatic based on conditions | You add and remove users manually | | **Updates** | Users enter/leave when data changes | List changes only when you edit it | | **Best for** | Traits, events, feedback interaction, survey answers | Hand-picked cohorts, imports from other tools | ## What you can do with segments [#what-you-can-do-with-segments] Segments are used throughout encatch: * **Target feedback forms**: Include or exclude segments when configuring [Logged-in Users](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/logged-in-users) targeting so only matching users see a form. * **Run targeted campaigns**: Show forms to specific groups (e.g. enterprise plan users, iOS users, highly engaged users). * **Analyze by audience**: Filter feedback results by user segment in reports (for example, Audience Overview). * **Reduce survey fatigue**: Combine segment targeting with [Past Interaction](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/past-interaction) rules to avoid showing forms to users who already saw or responded to other surveys. * **Reuse across forms**: Build a segment once and reference it on multiple feedback forms. ## Condition types (data-driven segments) [#condition-types-data-driven-segments] When you click **Add condition**, the picker shows four options: | Condition type | What it filters on | | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **User Traits** | User properties, including system fields (e.g. `device_os`, `email`) and custom traits (e.g. `plan`). Account traits appear under **Account Data** in the trait list. | | **Tracked Events** | In-app actions sent via `trackEvent()` (e.g. `feature_used`, `checkout_completed`) | | **Feedback Interaction** | Form engagement: seen, started, completed, dismissed, and more | | **Feedback Response** | What users answered on past surveys (e.g. NPS score, choice selections) | See [Data-driven segments](/docs/segmentation/data-driven) for full details on each condition type and how to configure them. Traits are configured in [User Traits](/docs/settings/user-data/user-traits). Events are configured in [Tracked Events](/docs/settings/user-data/tracked-events). ## Use case examples [#use-case-examples] | Use Case | Segment Type | Example | | ---------------------------- | ------------ | ---------------------------------------------------------------------------- | | **Beta product feedback** | Manual | Add beta testers by username for a dedicated feedback campaign. | | **Highly engaged users** | Data-driven | `feedback_response_count` greater than a threshold for loyalty surveys. | | **Device-specific rollouts** | Data-driven | `device_os` equals iOS or Android for compatibility testing. | | **SDK upgrade campaigns** | Data-driven | `sdk_version` starts with an older version for upgrade prompts. | | **Technical environment** | Data-driven | `device_os` is set AND `browser` equals Chrome. | | **NPS detractor follow-up** | Data-driven | Feedback Response: NPS is 0-6 on a previous survey. | | **Non-responders** | Data-driven | Feedback Interaction: form was Seen but not Completed in the last 30 days. | | **Feature power users** | Data-driven | Tracked Event: `feature_used` occurred at least 10 times in the last 7 days. | | **Custom cohorts** | Manual | Provide a list of usernames for a one-off survey or special offer. | ## Next Steps [#next-steps] * [Data-driven segments](/docs/segmentation/data-driven): Create dynamic segments using traits, events, feedback interaction, and feedback response conditions. * [Manual segments](/docs/segmentation/manual): Build static, hand-picked lists of users by username. * [User Traits](/docs/settings/user-data/user-traits): Configure traits used in segment conditions. * [Tracked Events](/docs/settings/user-data/tracked-events): Configure events used in segment conditions. * [Logged-in Users targeting](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/logged-in-users): Use segments when setting up who sees your feedback forms. # Additional Settings (/docs/settings/additional-settings) When you create API key, they are associated with your defined app names. To provide best and fast experience we cache feedback configurations for specific app names. ## Configuration Settings [#configuration-settings] Below settings are available to configure: * **Config sync interval**: The interval at which the config sync will be performed by your SDK for any changes in your feedback configurations. * **Feedback frequency**: A global setting to control the frequency between two feedback forms being displayed to your users, unless a form is marked as important. * **Disable all feedback forms**: A global setting to disable all feedback forms from being displayed to your users for this specific app name. The disable all feedback forms does not disable the feedback forms for other app names. ## Cache Management [#cache-management] * When you make changes to already created feedback forms, you can clear the cache for a specific app name by clicking the clear cache button, so that during next cycles of config sync, your SDK will fetch the latest feedback configurations. * If your changes are not immediately needed, you dont need to perform this step since the cache will be cleared automatically after 15 minutes. Suppose your app is active for multiple channels(android - MYAPP\_ANDROID, ios - MYAPP\_IOS, web - MYAPP\_WEB) and you want to temporarily disable feedback forms for web then you can use this feature to disable all feedback forms for web where you have defined the app name as MYAPP\_WEB, during API key creation. # User Management (/docs/settings/users) Users in encatch are your application users (end users) who interact with your application and provide feedback. * **Users**: End users of your application who submit feedback. Your users can scoped to the project level. Therefore, same user in two projects are counted as two different users. * **Members**: Administrators who manage the project and have access to the portal. ### User Attributes [#user-attributes] You can configure users atrributes like email, department, role, etc. to help you filter and analyze feedback data. User attributes are broken into 3 types **Pre-configured attributes**: Attributes that are pre-defined by you, that are filterable in the portal. * Examples include: email, department, role, etc. **Dynamic attributes**: Attributes that are not planned in advance and are created on the fly from your code. * Examples include: custom attributes, traits, etc. **System attributes**: Attributes that are pre-defined by the system and are not editable by you. * Examples include: user\_name, last\_seen, first\_seen, created\_at, updated\_at, etc. ### Manage Users [#manage-users] You can manage (create, view,edit,delete) users in the portal. * Individually * Bulk upload * Sync from your backend using API keys (Comming soon) - **user\_name** field should be unique for each user in the project. - When chosing to create a user from SDK, ensure that this field is not easily guessable or reproducible. - Only configure user fields which are useful for you to create filters and segments in the portal. - To protect users information, the API SDK cannot send back the user fields to your frontend application. Unless explicitly configured to show certain fields where dynamic attribute of users data is shown in your form. Example, a question like, "How has **\{\{user\_f\_name}}** been expereincing the app?" # Advanced Configuration (/docs/shareable-feedback/advanced-configuration) You can pre-fill supported questions by adding `response_` query parameters to a generated feedback link. Use this when you already know part of a respondent's answer, want to create personalized links, or want a one-click response from an email or campaign. For example, this link pre-fills an email question whose slug is `email` and an NPS question whose slug is `nps`: ```text https://form.encatch.com/?response_email=user%40example.com&response_nps=9 ``` Prefilling changes the initial values shown in the form. It does not submit the form; the respondent can review or change the answers before submitting. Query parameters can appear in browser history, server logs, analytics tools, and copied links. Do not place secrets, authentication tokens, or data that should not be exposed in a URL. ## Parameter format [#parameter-format] Use one of these formats: ```text response_= response_[]= ``` * Start every response parameter with the exact, case-sensitive prefix `response_`. * Identify a question using its UUID or a unique question slug. An exact UUID match takes precedence. A duplicated or unknown slug is ignored. * Supply the raw answer value, not an answer object or JSON document. * Use repeated parameters for multi-value answers. A comma is treated as part of one value, not as a separator. * Use bracketed member keys for matrix rows and address fields. * Apply normal URL percent encoding. No additional JSON, Base64, or custom encoding layer is required. When generating links in JavaScript, `URL` and `URLSearchParams` handle encoding safely: ```javascript const link = new URL('https://form.encatch.com/'); link.searchParams.set('response_email', 'user@example.com'); link.searchParams.set('response_nps', '9'); link.searchParams.append('response_features', 'analytics'); link.searchParams.append('response_features', 'exports'); console.log(link.toString()); ``` ## Scalar questions [#scalar-questions] Scalar questions accept exactly one non-empty value per question. | Question type | Value format | Example | | ----------------------- | ----------------------------------------------------------------------------------- | ----------------------------------------- | | Short answer, long text | Plain text within the configured character limit | `response_name=Ada` | | Email | Valid email address | `response_email=user%40example.com` | | Website | Valid HTTP or HTTPS URL; the scheme may be omitted | `response_site=example.com%2Fdocs` | | Phone number | International format beginning with `+` | `response_phone=%2B919876543210` | | Number | A number allowed by the question's decimal, negative, minimum, and maximum settings | `response_amount=-12.5` | | Date | `YYYY-MM-DD` | `response_date=2026-09-03` | | Date with time enabled | `YYYY-MM-DDTHH:mm` | `response_appointment=2026-09-03T14%3A30` | | Yes/No | Lowercase `true` or `false` | `response_recommend=true` | | Rating | Integer from `1` through the configured rating count | `response_rating=4` | | NPS | Integer from `0` through `10` | `response_nps=9` | | CSAT | Integer from `1` through the configured scale | `response_csat=5` | | Opinion scale | Integer within the configured start value and number of steps | `response_effort=3` | | Single choice | Configured option ID or value | `response_plan=plan-pro-id` | For choice questions, use the option's stored **ID** or **Value**, not its visible label. Prefilling an **Other** option is not supported. ## Multi-value and ordered questions [#multi-value-and-ordered-questions] Repeat the same parameter once for every selection: ```text ?response_features=analytics&response_features=exports ``` | Question type | How values are interpreted | | -------------------------- | ------------------------------------------------------------------------------------------------------------- | | Multiple choice (multiple) | Each repeated value is one selected option. Order does not matter. | | Picture choice | Each repeated value is one selected option. The configured single/multiple and maximum-selection rules apply. | | Ranking | Parameter order is the ranking order. | | Nested selection | Parameter order is the parent-to-child path, and the path must end at a leaf option. | Ranking example: ```text ?response_priority=quality&response_priority=speed&response_priority=price ``` Nested-selection example: ```text ?response_location=india&response_location=karnataka&response_location=bengaluru ``` Use an option ID or value for each entry. Duplicate values, unknown options, incomplete nested paths, and values beyond configured selection limits are ignored for that question. ## Matrix questions [#matrix-questions] Use the matrix row ID or value inside brackets. Use a selectable option ID or value on the right side. Single-choice matrix: ```text ?response_service[mobile]=good&response_service[desktop]=excellent ``` Multiple-choice matrix—repeat the same bracketed row key: ```text ?response_service[mobile]=fast&response_service[mobile]=accessible ``` Rating matrix: ```text ?response_satisfaction[reliability]=scale-very-satisfied-id ``` When constructing the URL manually, brackets may be percent-encoded as `%5B` and `%5D`. For example, `response_service%5Bmobile%5D` is equivalent to `response_service[mobile]`. For the most reliable result, use row, column, and scale-point IDs from the form configuration. Multiple-choice matrix limits are validated per row. ## Address questions [#address-questions] Use bracketed address field names. You may pre-fill one or more enabled fields: ```text ?response_shipping[city]=Bengaluru&response_shipping[country]=IN ``` Supported member names are: * `addressLine1` * `addressLine2` * `city` * `stateProvince` * `postalCode` * `country` Disabled address fields and unknown member names are ignored. ## Unsupported question types [#unsupported-question-types] URL prefilling is intentionally unavailable for: * Consent * Signature * File upload * Video, audio, or photo * Scheduler * Q\&A with AI Display-only elements such as welcome screens, thank-you screens, message panels, and exit forms cannot have responses. ## Validation and invalid values [#validation-and-invalid-values] Each parameter is validated against the published form configuration. An invalid parameter is ignored independently and does not prevent the form from opening or other valid answers from being populated. Common reasons a value is ignored include: * The question ID or slug does not exist, or the slug is not unique * A scalar question appears more than once * The value is empty or outside the question's configured range * A choice, row, column, or nested path does not exist * A bracketed key is malformed or used with the wrong question type * A question type does not support URL prefilling ## Persistence and partial responses [#persistence-and-partial-responses] The effective set of valid prefilled responses and context values from `en_ctx` and `context_` define the retained-draft scope: * Opening the same link parameters restores its saved draft. * Changing a valid `response_`, `context_`, or `en_ctx` value creates a separate retained-draft scope. * A restored draft takes precedence for questions it already contains; URL values provide defaults for questions not present in that draft. If partial responses are enabled, merely opening a prefilled link does not trigger a partial-response API request. A partial response becomes eligible only after the effective answer state differs from the initialized state. Final form submission is unchanged. The `response_`, `context_`, and `en_ctx` parameters are excluded from source tracking. Other URL parameters continue to follow the form's [Source Tracking](/docs/feedback-management/advanced-options/source-tracking) configuration. ## Pass context variables [#pass-context-variables] Use `context_` query parameters when a form's question or section text contains context variables such as `{{ context.customer_name }}`. Context values personalize the form but do not create responses or identify the respondent. Use an untyped parameter for a string, or add a bracketed type when the value must be a boolean or number: ```text context_= context_[string]= context_[boolean]=true|false context_[number]= ``` For example: ```text https://form.encatch.com/?context_customer_name=Ada&context_is_trial[boolean]=true&context_invoice_total[number]=1499.50 ``` The form can reference these values as: ```liquid Hello {{ context.customer_name }} ``` | Parameter | Parsed value | Parsed type | | --------------------------------------- | ------------ | ----------- | | `context_customer_name=Ada` | `Ada` | String | | `context_customer_id=00123` | `00123` | String | | `context_is_trial[boolean]=true` | `true` | Boolean | | `context_invoice_total[number]=1499.50` | `1499.5` | Number | | `context_campaign[string]=renewal` | `renewal` | String | ### Context rules [#context-rules] * The `context_` prefix and bracketed type names are case-sensitive. * Omitting the bracketed type always produces a string. Use this for identifiers with leading zeroes. * Boolean values accept `true` or `false`, ignoring surrounding whitespace and letter case. * Number values must be finite JSON-style numbers. Values such as `01`, `NaN`, and `Infinity` are ignored; use a string when formatting must be preserved. * Variable names may contain letters, numbers, underscores, periods, and hyphens, and may be up to 100 characters long. * A link may supply up to 50 valid context variables, with up to 10,000 decoded UTF-8 bytes per value. * The variable names `__proto__`, `constructor`, and `prototype` are not allowed. * Provide each logical variable only once. Repeating a variable, including with different type annotations, causes that variable to be ignored. * Brackets may be written literally or percent-encoded as `%5B` and `%5D`. * Invalid context parameters are ignored independently, so other valid context values still apply. You can combine response and context parameters in the same link: ```text https://form.encatch.com/?context_customer_name=Ada&context_is_trial[boolean]=true&response_nps=9 ``` When both `en_ctx` and `context_` provide the same top-level variable, a valid `context_` value takes precedence. An invalid `context_` value is ignored and does not replace the value from `en_ctx`. Valid context values are included in the retained-draft scope. Changing a valid `context_` value creates a separate retained draft, just like changing a valid prefilled response or `en_ctx`. The shareable page removes `context_` parameters from the visible address after reading them and retains them across refreshes in its encoded launch parameter. This reduces casual editing but is not tamper protection or encryption. The original link and its values may still be visible to systems through which it is shared. The `context_` parameters are excluded from source tracking. Arbitrary campaign and tracking parameters remain available to the form's [Source Tracking](/docs/feedback-management/advanced-options/source-tracking) configuration. ## Related [#related] * [Feedback Links](/docs/shareable-feedback/feedback-links) * [User Identification](/docs/shareable-feedback/user-identification) * [Source Tracking](/docs/feedback-management/advanced-options/source-tracking) * [Partial Save](/docs/feedback-management/advanced-options/partial-save) # Email Surveys (/docs/shareable-feedback/email-surveys) Email surveys turn **one published question** from your feedback form into an HTML block you can paste into an email campaign. Recipients click an answer (or a call-to-action) in the email, open your hosted form when needed, and their response is associated with the correct contact when identity mappings are configured. Use email surveys for lifecycle campaigns, post-purchase follow-ups, support check-ins, and other outbound email where you already know the recipient through your email service provider (ESP). You need a **published** form, **Link & email distribution** enabled, and at least one **active shareable link**. Create a link first in [Feedback Links](/docs/shareable-feedback/feedback-links). ## Open the email survey builder [#open-the-email-survey-builder] 1. Open your feedback form in the editor. 2. Go to **Link & email distribution**. 3. Turn on **Link & Email** if it is not already enabled. 4. Open the **Email** tab. 5. Click **New** under **Email survey**, or **Edit** on a saved template. The builder opens in two steps: | Step | Name | What you configure | | ---- | ----------------------- | -------------------------------------------------- | | 1 | **Survey setup** | Shareable link, question, language, email provider | | 2 | **Customize & preview** | Appearance, variables, HTML editor, live preview | When you finish, use **Copy HTML** or **Download HTML** and paste the block into your ESP template. ## Step 1 — Survey setup [#step-1--survey-setup] ### Shareable link [#shareable-link] Choose the active shareable link that should receive responses. Export is blocked if the link is inactive, expired, or no longer available. Links that require **recipient signatures** cannot be used for email survey export. Choose an unsigned link instead. If the link does not allow anonymous submissions, map **contact\_email** or **contact\_id** in Step 2 before exporting. ### Question to show [#question-to-show] Pick **one published question** to embed in the email. Only supported question types appear in the list. The selected **Language** controls the question title and description shown in the email. How the question behaves in email depends on its type: | Behavior | Question types | What happens when a recipient clicks | | ------------------ | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | **Direct capture** | Rating, NPS, CSAT, opinion scale, yes/no, single choice, picture choice (single-select) | Opens the survey and records the selected answer when partial saving allows it | | **Prefill** | Multiple choice (multi-select), ranking, nested selection, picture choice (multi-select), matrix questions | Opens the hosted survey with that selection prefilled; the recipient finishes there | | **Hosted entry** | Number, date, email, website, phone, short answer, long text, address | Shows a static preview and an **Answer in survey →** link | | **Welcome screen** | Welcome | Shows **Start survey →** without recording an answer | **Other** options on choice questions are excluded from email choices. ### Email provider [#email-provider] Search and select the ESP you send campaigns with. Encatch uses the provider to prefill common **contact\_email** merge tags where a verified URL-safe expression exists. * **Auto-configured providers** — Encatch fills the recipient email merge tag for you. * **Manual providers** — You supply and test your own URL-safe recipient expression. Provider notes in the builder explain what to verify before sending. Each provider shows a setup guide link labeled with that provider’s name (for example, **Klaviyo setup guide**). That link opens the ESP’s official personalization or merge-field documentation when a verified guide is available. **Custom / Other** and providers without a working official guide open this page. **Lifecycle.io** shows a message instead of a link. ## Step 2 — Customize & preview [#step-2--customize--preview] ### Appearance [#appearance] Email appearance is separate from your hosted survey theme. | Setting | Purpose | | ----------------------------- | -------------------------------------------------------------------------- | | **Answer color** | Accent color for choices, buttons, and markers | | **Show question text** | Include the question title in the email block | | **Show question description** | Include the question description when one exists for the selected language | The **Powered by Encatch** footer follows your form theme branding setting. Preview the block in **Desktop** or **Mobile** (iPhone-style) frames. Preview links are inert — no emails are sent and no responses are recorded. ### Variables [#variables] Map identity and context values onto the survey URL. Each row has: | Field | Purpose | | -------------------------------- | ---------------------------------------------------------------------------- | | **Key** | `contact_` or `context_` parameter name | | **Export value** | **Provider merge tag** or **Fixed value** appended to exported links | | **Display merge tag (optional)** | Unencoded tag for visible question text when the export value is URL-encoded | | **Preview sample** | Sample value for preview only — never exported | Default mappings for new templates: * `contact_email` — provider merge tag (auto-filled for supported ESPs) * `contact_display_name` — provider merge tag (configure as needed) **Limits** * Up to **50** `context_` variables * Up to **25** custom `contact_` traits (excluding reserved keys like `contact_id`, `contact_email`, `contact_signature`) * Variable names up to **100** characters; values up to **10,000** characters For how contact parameters work at runtime, see [User Identification](/docs/shareable-feedback/user-identification). For response prefilling outside email capture, see [Advanced Configuration](/docs/shareable-feedback/advanced-configuration). ### HTML editor [#html-editor] The HTML editor shows syntax highlighting for the generated block. Preview updates as you type; **Copy HTML** and **Download HTML** export your edits. Changing generation settings (link, question, language, provider, appearance, or variables) asks you to confirm before discarding custom HTML. Use **Reset HTML** to restore the generated block. Custom HTML edits must preserve survey answer links. Removing or breaking those URLs prevents answer capture. ## Export and send [#export-and-send] Before export, Encatch re-checks that: * The form is still **published** * The shareable link is still **active** and not expired * Link identity requirements have not changed * The published form configuration (including partial save) has not changed * The survey destination has not changed **Copy HTML** copies the full block. **Download HTML** saves `email-survey-{provider}-{question}.html`. Merge tags in exported HTML stay **literal** so your ESP template engine evaluates them at send time. Test with a real campaign send — ordinary preview sends from some ESPs may leave tags unresolved. ### Partial saving requirement [#partial-saving-requirement] If the selected question supports **direct capture** and your form has **more than one** non-panel question, enable **Partial saving** in the form’s **Advanced settings**. Without it, Encatch cannot record a single email click as a complete response before the rest of the survey is finished. Prefill-only and hosted-entry question types do not require partial saving for export, but they still open the hosted survey for completion. ## Saved email templates [#saved-email-templates] Save reusable configurations under **Saved email templates** on the **Email** tab. Each template stores: * Template **name** and **slug** * Shareable link, provider, question, language, appearance, and variables * Generated or custom HTML snapshot From the list you can **Edit**, **Rename**, **Duplicate**, or **Delete** templates. Deleting a template does not change the form or shareable link. If a saved link later expires or is removed, the template shows **Link unavailable**. Preview still works from the saved HTML, but export requires choosing a new active link. ## URL parameters in exported links [#url-parameters-in-exported-links] Exported answer links use your shareable link as the base and add email-survey parameters: | Parameter | Purpose | | --------------------------------- | ------------------------------------------------------- | | `email_survey_question` | Question ID shown in the email | | `lang` | Selected language code | | `email_survey_capture=1` | Present on export for direct-capture question types | | `response_{questionId}` | Prefilled answer value when applicable | | `response_{questionId}[{member}]` | Matrix row member for matrix questions | | `contact_*` | Identity and contact traits from your variable mappings | | `context_*` | Context variables from your variable mappings | Provider merge expressions are appended as raw `key=expression` pairs so ESP syntax (pipes, braces, percent signs) survives export. ## Auto-configured email providers [#auto-configured-email-providers] These providers prefill a verified URL-safe **contact\_email** merge tag: | Provider | URL merge tag (export) | | -------------------------- | ---------------------------------------------- | | Braze | `{{${email_address} \| url_encode}}` | | Brevo | `{{ contact.EMAIL \| urlencode }}` | | Customer.io | `{{ customer.email \| url_encode }}` | | Drip | `{{ subscriber.email \| url_encode }}` | | HubSpot | `{{ contact.email \| urlencode }}` | | Iterable | `{{#urlEncode}}{{{email}}}{{/urlEncode}}` | | Kit | `{{ subscriber.email_address \| url_encode }}` | | Klaviyo | `{{ person.email \| urlencode:'' }}` | | Mailchimp | `*\|URL:EMAIL\|*` | | Mailjet | `{{ UrlEncode(mj:contact.email) }}` | | Salesforce Marketing Cloud | `%%=URLEncode(emailaddr,true,true)=%%` | | Vero | `{{ user.email \| encode }}` | | Zendesk | `{{ ticket.requester.email \| url_encode }}` | All other listed providers are **manual**. Add your ESP’s URL-safe recipient expression, verify plus-addressed and special-character emails in a test send, and confirm the expanded link before launching a campaign. ## Limitations [#limitations] * **Signed shareable links** are not supported for email survey export in the current release. * **Preview** substitutes sample values and uses inert links; only **export** includes live merge tags and capture parameters. * Question media and picture-choice images must use **HTTPS** URLs reachable by recipients. * Rating and CSAT icons in exported HTML use absolute URLs from your admin origin — ensure that origin is reachable from email clients. * Email link scanners and prefetch behavior can affect capture rates; test with your ESP and monitor results. ## Related [#related] * [Feedback Links](/docs/shareable-feedback/feedback-links) * [User Identification](/docs/shareable-feedback/user-identification) * [Advanced Configuration](/docs/shareable-feedback/advanced-configuration) * [Partial Save](/docs/feedback-management/advanced-options/partial-save) # Feedback Links (/docs/shareable-feedback/feedback-links) Shareable links let you send your feedback form to anyone, even if they're not using your app. They're useful for support follow-ups, email campaigns, beta tester outreach, QR codes, and other external distribution channels. ## How to create a feedback link [#how-to-create-a-feedback-link] 1. Open your feedback form and go to **Distribution → Link & Email → Links**. 2. Enable **Link & Email**. Link and Email distribution with the Links tab open 3. Click **+ Create Link** to open **Create Shareable Link**. 4. Set the **Link Expiry (Date & Time)**. 5. Expand **Security Configuration (Optional)** when the link needs signed-user validation or session controls. You can: * Generate a secret key for hashing user IDs on your server. Never expose this key in client-side code. * Set **Session Time (Minutes)**. Use `0` to disable session-time validation. * Allow or block new contact creation. * Allow or block anonymous submissions. 6. Click **Generate Link** to create the link. You can create up to 10 links in a 7-day period. 7. Copy and share the link through email, chat, social media, a support ticket, or another channel. Create Shareable Link with expiry and optional security controls To build provider-ready HTML for email campaigns, see [Email Surveys](/docs/shareable-feedback/email-surveys). To populate answers when someone opens the link, see [Advanced Configuration](/docs/shareable-feedback/advanced-configuration). # User Identification (/docs/shareable-feedback/user-identification) You can identify a respondent and provide contact traits by adding `contact_` query parameters to a shareable feedback link. This is useful for [email surveys](/docs/shareable-feedback/email-surveys), customer follow-ups, lifecycle campaigns, and other situations where you already know who will receive the link. For example: ```text https://form.encatch.com/?contact_id=customer_123&contact_email=alice%40example.com&contact_display_name=Alice&contact_plan=pro ``` The example identifies the respondent as `customer_123` and supplies their email address, display name, and plan. Anyone who can access or modify an unsigned link can change its query parameters. Use optional identity verification when the respondent's identity needs to be trusted. ## Parameter format [#parameter-format] | Parameter | Purpose | | ------------------------ | ------------------------------------------------------------- | | `contact_id` | Stable external identifier for the respondent | | `contact_email` | Respondent's email address and email-only fallback identifier | | `contact_` | Contact trait to associate with the respondent | | `contact_signature` | Optional server-generated HMAC identity signature | | `contact_signature_time` | Optional signature timestamp in Unix epoch milliseconds | Parameters are case-sensitive. Use the exact lowercase `contact_` prefix. ## Choose the contact identifier [#choose-the-contact-identifier] For the most reliable cross-channel history, provide `contact_id` using the same stable identifier that your application uses with `identifyUser`: ```text ?contact_id=customer_123 ``` The identifier must contain 1–50 ASCII characters. Letters, numbers, `.`, `_`, `@`, and `-` are supported. Spaces, Unicode characters, and other symbols are not supported. You can identify a respondent using only their email address: ```text ?contact_email=alice%40example.com ``` When both parameters are present, `contact_id` is the identity and `contact_email` is stored as the email trait: ```text ?contact_id=customer_123&contact_email=alice%40example.com ``` Prefer `contact_id` when the same person may receive email surveys and use an application where they are identified through the Web or Mobile SDK. Reusing the same identifier keeps their feedback activity associated with one contact. ## Add contact traits [#add-contact-traits] Add `contact_` before a user-trait slug: ```text ?contact_id=customer_123&contact_display_name=Alice&contact_plan=pro&contact_region=IN ``` This supplies the following traits: ```json { "display_name": "Alice", "plan": "pro", "region": "IN" } ``` Trait slugs may contain lowercase letters, numbers, and underscores. URL traits use merge semantics: supplied values set or overwrite the corresponding trait, while traits omitted from the link remain unchanged. The link cannot perform advanced trait operations such as incrementing, decrementing, removing traits, or replacing the complete contact record. Projects can control whether previously unknown traits may be created from client data. If automatic trait creation is disabled, only existing enabled traits are accepted. See [User Traits](/docs/settings/user-data/user-traits). URL contact values are read as strings. Existing trait configuration may validate or convert an accepted value according to the trait's data type. Numeric-looking identifiers and values are not automatically converted by the URL parser. ## Combine identification with response prefilling [#combine-identification-with-response-prefilling] `contact_` and `response_` parameters have separate purposes and can be used in the same link: ```text https://form.encatch.com/?contact_id=customer_123&contact_plan=pro&response_nps=9 ``` * `contact_id` and `contact_plan` describe the respondent. * `response_nps` supplies the initial answer to the NPS question. Opening the link does not submit the prefilled answer. The respondent can review or change it before submitting. See [Advanced Configuration](/docs/shareable-feedback/advanced-configuration) for supported response formats. ## When the contact is created or updated [#when-the-contact-is-created-or-updated] Opening a shareable link performs a read-only contact lookup. It does not create a new contact or update an existing contact merely because the page was loaded. A contact is created or updated when one of these events occurs: * The respondent submits the form. * An eligible partial response is saved after the respondent's effective answers differ from the initialized prefilled answers. If someone opens the link and leaves without interacting, no contact or response is created. This also prevents ordinary email-link previews and page scans from creating contacts. ## Optional identity verification [#optional-identity-verification] Unsigned links are supported by default. For cases where the supplied identity must be verified, generate an HMAC signature on your server and add it to the link: ```text ?contact_id=customer_123&contact_signature= ``` Never generate the signature in browser code or expose your secret key in the link. Keep the secret on your server. See [Publishable SDK Keys](/docs/settings/security/publishable-sdk-keys). When no signature session timeout is configured, sign the identifier: ```javascript import crypto from 'node:crypto'; const signature = crypto .createHmac('sha256', process.env.ENCATCH_SECRET_KEY) .update('customer_123') .digest('hex'); ``` When a session timeout is configured, include the current Unix epoch time in milliseconds in both the signed value and URL: ```javascript import crypto from 'node:crypto'; const contactId = 'customer_123'; const timestamp = String(Date.now()); const signature = crypto .createHmac('sha256', process.env.ENCATCH_SECRET_KEY) .update(contactId + timestamp) .digest('hex'); ``` ```text ?contact_id=customer_123&contact_signature=&contact_signature_time= ``` `contact_signature_time` is optional in the URL format but required when the configured signature policy uses a session timeout. If email is the only identifier, use the email address as the value being signed. Identity verification verifies the identifier. It does not make other URL parameters secret, and an identity-only signature does not protect arbitrary `contact_` or `response_` values from modification. ## Generate and encode links safely [#generate-and-encode-links-safely] Use `URL` and `URLSearchParams` instead of manually joining query strings: ```javascript const link = new URL('https://form.encatch.com/'); link.searchParams.set('contact_id', 'customer_123'); link.searchParams.set('contact_email', 'alice@example.com'); link.searchParams.set('contact_display_name', 'Alice & Bob'); link.searchParams.set('contact_plan', 'pro'); console.log(link.toString()); ``` This correctly percent-encodes characters such as `@`, spaces, `&`, `+`, and Unicode characters in trait values. Query parameters can appear in browser history, email security systems, proxy and server logs, analytics tools, referrer information, and copied links. Prefer an opaque `contact_id` and include only the traits needed for the survey. Never include passwords, secret keys, access tokens, or sensitive personal data. ## Invalid parameters [#invalid-parameters] Invalid contact parameters are ignored independently. They do not prevent other valid contact or response parameters from being processed. A contact parameter may be ignored when: * The same parameter appears more than once. * Its value is empty. * `contact_id` contains unsupported characters or exceeds 50 characters. * `contact_email` is not a valid email address. * A trait slug contains uppercase letters, hyphens, brackets, or other unsupported characters. * Bracketed or nested contact syntax is used. * The link supplies more than 25 custom contact traits. * A signature timestamp is malformed or is provided without a signature. * A signature is provided without `contact_id` or `contact_email`. Unlike multi-value response questions, contact parameters do not support repeated values, comma-separated lists, or bracketed member keys. ## Persistence and source tracking [#persistence-and-source-tracking] Contact identity and accepted traits participate in the retained-draft scope. Opening links for two different contacts in the same browser does not restore one contact's draft into the other contact's form. Signature and timestamp values do not participate in the draft identity, so regenerating a signature for the same contact and traits does not create another draft scope. All `contact_` and `response_` parameters are excluded from [Source Tracking](/docs/feedback-management/advanced-options/source-tracking). Other URL parameters continue to follow the form's source-tracking configuration. ## Related [#related] * [Feedback Links](/docs/shareable-feedback/feedback-links) * [Email Surveys](/docs/shareable-feedback/email-surveys) * [Advanced Configuration](/docs/shareable-feedback/advanced-configuration) * [User Traits](/docs/settings/user-data/user-traits) * [Publishable SDK Keys](/docs/settings/security/publishable-sdk-keys) # Members (/docs/account-management/members) ### Inviting Team Members [#inviting-team-members] * Only users with appropriate permissions can invite new members to the organization or project level. * By inviting member at organization level you grant them across all projects (based on scopes defined in that role). * By inviting member at project level you grant them only to that project. * People you are invite are auto accepted to the organization and project. If a user has previously not joined encatch, you will see **invited** status in the members list. If the invited member has already joined encatch, you will see **active** status in the members list. * An invitation email is sent to the invited member to join the organization / project. - Any member assigned at organization level cannot be added as a member at project level and vice versa. - If you want to add a member at project level, you need to remove them from the organization level first. - Organization owner will have access to all organization and project level features and cannot be removed from the organization. - A user can be added as organization admin in multiple organizations but will be owner of only one organization. ### Enterprise Feature [#enterprise-feature] Enterprises have the flexibility to send invitation emails from their own email domain or use encatch's email domain with custom branding and mail content. # Organization & Projects (/docs/account-management/overview) ## Platform Hierarchy [#platform-hierarchy] The encatch platform follows a hierarchical structure that organizes your feedback collection and management: read about the platform hierarchy [here](#platform-hierarchy). ## Organization / Project Management [#organization--project-management] * Use the **Manage** option in the sidebar to access the organization and project management page. The page will show you the list of organizations and projects you have access to. * Roles and permissions (for orgnization and projects level) are created / managed at the organization level only. * Members can be chosen to be invited at organization level or at project level. #### Important Notes: [#important-notes] * One email address can only be associated with one organization as owner. * At present, reassigning organization owner to a different user is restricted from admin portal as self service. Contact us for such requests. * You can only access the organization and project management page if you have the **Manage** permission. * Every new user registration on the encatch admin portal automatically creates an organization, with the registering user becoming the organization owner. # Role & Permissions (/docs/account-management/roles-permissions) ## Roles and permissions [#roles-and-permissions] Roles define what actions users can perform within the organization and projects. Permissions can be customized at both the **organization level** and the **project level**. #### Default Roles [#default-roles] * By default, a organization admin role is created with all permissions at organization level. This role cannot be deleted or modified. #### Custom Roles [#custom-roles] You can create custom roles to meet your organizational and project needs. * When creating a new role at organization level, you can choose to limit the role with permissions at organization level or across projects. - Organization admin role cannot be deleted or modified. - Organization Owner (the user who creates the organization) is automatically added as an organization admin and cannot be removed. #### Example of custom roles: [#example-of-custom-roles] * You may create a role as system admin, which will have access to organization level features that allow to manage roles and member invitations only. * You may create a project level role as feedback management who has access to view and manage feedback within the project. * You may create a project level role as integration manager who has access to manage data pipelines within the project, since these contain sensitive information and may need to be managed by a dedicated team. # Appearance (/docs/feedback-management/form-builder/appearance) The **Appearance** tab lets you control how your feedback form looks and behaves. On desktop, the editor has a **left configuration column**, a **center preview**, and a **right editor** when you open Theme or a section layout. Appearance sits under **Form design**, alongside Questions and Logic jumps. Appearance tab overview ## Overview [#overview] Use **Appearance** to align the form with your brand: **colors**, **typography (font family)**, **custom CSS**, and form behavior for in-app and shareable experiences. **Theme** opens a right-side editor with **Basic** and **Advanced** tabs. The center preview shows the form in device frames, and **Section Layouts** lets you set defaults or override individual sections. ## Appearance tab layout [#appearance-tab-layout] 1. **Left column — Configure** * **Theme** (palette icon): opens the right-side Theme editor. * **Other Fields Configuration**: opens shared display and button-label settings. * **Section Layouts**: includes **Defaults**, which applies to all sections unless overridden, followed by each page and the Thank you section for per-section media and layout. 2. **Center — Preview** Live preview with device tabs, light/dark preview, language, and toolbar actions including **Your screenshots** (device mockup uploads). 3. **Right — Theme or layout editor** (when active) **Theme** opens the Basic or Advanced theme controls. Picking a section or **Defaults** under Section Layouts opens the layout and media controls for that scope. *** ## Theme editor [#theme-editor] Open **Theme** from the Appearance configuration column. The right-side editor has two tabs: 1. **Basic** — Light and Dark color settings, **Edit all colors**, **Color presets**, Font family, and form controls such as Progress bar, encatch branding, Previous button, Corners, and Right-to-left (RTL). 2. **Advanced** — The Custom CSS editor. Color options - Light and Dark Mode ### Basic colors [#basic-colors] Use the **Light** and **Dark** controls to configure the two modes. The visible core color fields are **Brand / Action**, **Text on Brand**, **Page Background**, and **Primary Text**. If the selected color pairings may be hard to read, the editor displays a review warning; use the information icons to check where each color is used. * **Choosing a color:** Click the **swatch** and **hex preview** (monospace). A **color picker** opens in a popover; when you **close** the popover, the value is applied. * **Copy:** The copy control copies the hex value and shows brief confirmation. * **Hints:** The **information** icon next to each label opens a tooltip with usage notes. #### Brand / Action [#brand--action] The main accent color used for primary actions. Choose a color that remains distinct from the page background in each mode. #### Text on Brand [#text-on-brand] The color of text or icons placed on the Brand / Action color. #### Page Background [#page-background] The page background color for the form. #### Primary Text [#primary-text] The primary text color for questions, labels, and body text. ### Edit all colors [#edit-all-colors] All colors dialog Use **Edit all colors** in the Basic tab to open the complete color controls. Use **Color presets** when you want to start from a predefined palette. The complete dialog includes: * **Brand / Action** and **Text on Brand** for primary actions and their foreground content * **Page Background** for the form page * **Control Surface** for inputs and other interactive surfaces * **Primary Text** and **Supporting Text** for the content hierarchy * **Control Border** for inputs, cards, and dividers * **Error** for validation and error states * **Backdrop Overlay** for the layer behind a modal or popup ### Custom CSS (Advanced tab) [#custom-css-advanced-tab] Open the **Advanced** tab to use the Custom CSS editor. The editor exposes the form's customization hooks and includes controls for common editing actions and downloading the CSS. ### Font family (Basic tab) [#font-family-basic-tab] **Font family** is in the **Basic** tab of the Theme editor. It sets the form typeface from encatch-hosted web fonts (central font manifest). * **Default:** Built-in system or default stack (shown as the system default in the picker). * **Other fonts:** Each row is a manifest key, with metadata (weight/style for preview) and a **live preview** of the font name when the font loads. * **Search and scroll:** Use **Search fonts...**, scroll the list, and choose a row to apply (popover closes). Long lists **load more** as you scroll toward the bottom. * **Saved value:** The **manifest key** for the selected font (not a raw CSS `font-family` string). Keys removed from the catalog can still appear so your choice is preserved. * **Errors:** If the list fails to load, a short message may appear; the saved value remains. Use the information icon next to **Font family** for the in-product note about hosted fonts and manifest keys. *** ## Basic form settings [#basic-form-settings] Scroll the **Basic** tab below the color controls to configure visible options including **Progress bar**, **encatch branding**, **Previous button**, **Corners**, and **Right-to-left (RTL)**. Additional in-app and shareable settings appear farther down the same editor. ### Corners [#corners] Use **Corners** to choose the form's corner treatment. The selected treatment is reflected in the center preview. ### Dark overlay [#dark-overlay] When enabled, a semi-transparent dark overlay appears behind the form while it is open. When disabled, the background stays visible. On native mobile apps, disabling this uses a blocker-style popup with a transparent overlay instead of a dimmed one. ### Close button [#close-button] When enabled, users can dismiss the widget with a close control before finishing the form. When disabled, they typically need to move through or complete the form to exit. ### Progress bar [#progress-bar] When enabled, a progress indicator shows how much of the form remains. ### encatch branding [#encatch-branding] Controls whether **Powered by encatch** appears. A lock icon can indicate plan or permission limits. ### Previous button [#previous-button] Select **Always** or **Never** to control whether a previous-step control is shown in the form flow. ### Right-to-left (RTL) [#right-to-left-rtl] When enabled, RTL layout applies for supported form languages (for example Arabic, Hebrew, Persian, Urdu). See the in-product help for the exact language list. ### In-app display [#in-app-display] Expand **In App** in the Basic tab to configure how the form appears inside your product: * **Dark overlay** dims the host interface while the form is open. * **Close button** lets respondents dismiss the form before completion. * **Size** controls the in-app form size. * **Position** places the form on a corner, edge, center, or full-center surface. **Default (bottom right)** uses the standard placement. * **Display type** controls how the in-app form is presented. **Auto** lets encatch choose the appropriate presentation. * **Max dialog height** limits the form height as a percentage of the viewport. The default is **75%**. ### Shareable display [#shareable-display] Expand **Shareable** in the Basic tab to configure forms opened through a shareable link: * **Size** controls the shareable form size. * **Mode** can be **Light**, **Dark**, or **System**. Light and Dark fix the theme, while System follows the visitor's browser or operating-system preference. * **Keyboard accessibility** enables desktop keyboard shortcuts for fullscreen shareable forms. * **Logo** controls whether the configured logo appears on the shareable form. Shareable Mode - Display mode options ### Keyboard accessibility (shareable) [#keyboard-accessibility-shareable] When enabled on desktop shareable links, respondents can use keyboard shortcuts: * **Enter** — next question, submit, or activate the thank-you Done button * **Backspace** — previous question or section (also works from empty text fields) * **Tab** — moves focus within the survey (focus stays inside the form) * **Number keys** — select ratings, choices, CSAT scores, and similar options (press the same key again to clear where supported) * **Space** — toggle consent, matrix cells, and file-upload browse zones Only applies to fullscreen shareable forms on non-touch-primary devices. *** ## Widget position options [#widget-position-options] Open **In App → Position** in the Theme editor to place the form. The dropdown lists the placements below. Position options for in-app forms | Position (label) | Description | | ---------------- | -------------------------------------------------------------- | | Top Left | Upper-left corner | | Top Center | Top edge, centered | | Top Right | Upper-right corner | | Center | Center of the screen (horizontal and vertical) | | Bottom Left | Lower-left corner | | Bottom Center | Bottom edge, centered | | Bottom Right | Lower-right corner | | Full Center | Centered presentation that uses the full available dialog area | Default placement when not customizing is **bottom right**. *** ## Preview panel and device mockups [#preview-panel-and-device-mockups] The **center** preview toolbar includes light/dark toggles, device framing, language, and **Your screenshots** (upload icon) to open **Upload Device Mockup Images**. Upload Device Mockup Images Upload custom images for **mobile**, **desktop**, and **tablet**, each with **light** and **dark** variants. The dialog accepts **PNG, JPG, WEBP, and SVG** files up to **10 MB**. It recommends iPhone dimensions for mobile, **2048×1080** for desktop, and iPad Air dimensions for tablet. Images are stored locally for the project and replace the default mockup artwork in preview flows. # Customize Feedback Form (/docs/feedback-management/form-builder/build-feedback-form) This guide walks you through building a feedback form in encatch. You can add questions, organize them into pages, support multiple languages, and customize the structure to match your needs. ## Introduction [#introduction] The form builder lets you create feedback forms step by step. You start with a blank form or a template, then add and configure form elements such as welcome screen, questions, thank you screen, and optional exit form marker. Forms can span multiple pages, support multiple languages, and be fully customized for branding and behavior. ## Form Elements [#form-elements] Form elements are the building blocks of your feedback form. Each type serves a specific purpose in collecting user feedback. Use the links below to learn more about each element: * **[Welcome Panel](/docs/feedback-management/question-types/panels/welcome-screen)** — Introductory screen before the survey. Set context, explain the purpose, and show estimated time to complete. * **[Thank you screen](/docs/feedback-management/question-types/panels/thank-you-screen)** — Closing screen after the form is completed; title, markdown description, and button label (for example Close). * **[Exit form](/docs/feedback-management/question-types/panels/exit-form)** — Silent end-of-form marker (no visible screen); use as a [Logic jumps](/docs/feedback-management/form-builder/logic-jumps) target to stop the form without a thank-you step. * **[Call to action](/docs/feedback-management/form-builder/call-to-action)** — Post-submit behavior on thank-you screens and exit forms — redirects, in-app navigation, auto-trigger, and optional secondary button. * **[Message panel](/docs/feedback-management/question-types/panels/message-panel)** — Informational panel between questions; title, markdown description, and continue button (default Next). * **[NPS](/docs/feedback-management/question-types/scale/nps)** — Net Promoter Score (0–10) question for measuring loyalty. * **[Single Choice](/docs/feedback-management/question-types/choice/single-choice)** — One option selected from a list. * **[Multiple Choice](/docs/feedback-management/question-types/choice/multiple-choice)** — One or more options selected from a list. * **[Nested Selection](/docs/feedback-management/question-types/choice/nested-selection)** — Hierarchical dropdown selections with parent and child options. * **[Rating](/docs/feedback-management/question-types/scale/rating)** — Star or numeric rating scale. * **[Short Answer](/docs/feedback-management/question-types/text/short-answer)** — Single-line text response. * **[Long Answer](/docs/feedback-management/question-types/text/long-answer)** — Multi-line text response. * **[Other Fields Configuration](/docs/feedback-management/question-types/other-fields-configuration)** — Display options (question numbers, page titles) and button labels (Submit, Previous, Next). For a full overview of element types, see [Element Types Overview](/docs/feedback-management/question-types). ## Features of the Form [#features-of-the-form] ### Add Questions [#add-questions] Use the **+ Add Question** button to add new questions to your form. You can add questions to the current page or create new pages and add questions there. Use **+ Add More Questions** at the bottom of a page to continue building. ### Add Page Breaks [#add-page-breaks] Organize your form into multiple pages. Each page can have its own title and set of questions. Add new pages using the **+** icon in the page header. This helps keep long forms manageable and improves completion rates by breaking content into smaller steps. ### Add Languages [#add-languages] Support multiple languages from the language dropdown (e.g. **English (1 language)**). Add additional languages so respondents can complete the form in their preferred language. All form content—questions, welcome screen, end screen—can be translated per language. See [Language Setup](/docs/feedback-management/form-builder/language-setup) for configuration details and Auto Translate with AI. ### Edit [#edit] Use the pencil (edit) icon next to any element—Welcome Screen, End Screen, Other Fields Configuration, page titles, or individual questions—to open the configuration dialog and customize settings. ### Delete [#delete] Use the trash icon next to pages or questions to remove them from the form. Deleted content cannot be recovered, so confirm before removing. ### Rearrange Questions [#rearrange-questions] Use the drag handle (vertical ellipsis with up/down arrows) to the left of each question to reorder questions within a page. You can also move questions between pages by dragging them to the desired location. ### Resize the editor and preview [#resize-the-editor-and-preview] Drag the divider between the form structure and the live preview to give either side more room. This is useful when editing long question text, reviewing a larger preview, or working on a smaller display. The panel size changes only your builder workspace. It does not change the size or layout respondents see. Resizable form editor and live preview panels ### Logic jumps [#logic-jumps] Send respondents to different questions based on answers, SDK context, or user traits. Enable branching on the **[Logic jumps](/docs/feedback-management/form-builder/logic-jumps)** tab after you have added questions on the Form tab. # Call to action (/docs/feedback-management/form-builder/call-to-action) **Call to action** controls what happens after a feedback form ends—close the form, navigate inside your app, or redirect to a URL. Configure it when editing a **[Thank you screen](/docs/feedback-management/question-types/panels/thank-you-screen)** (visible buttons) or an **[Exit form](/docs/feedback-management/question-types/panels/exit-form)** (silent action with no UI). In the form builder, open **Call to action** → **Configure** on either panel type in the **Thank you & Exit Section**. ## When to use [#when-to-use] * Send respondents to a pricing page, support article, or onboarding flow after submission * Navigate users inside your app (for example billing upgrade) when the form runs in your product * End disqualified branches silently via an exit form without showing a thank-you screen * Auto-dismiss or auto-redirect after a short delay on the thank-you screen ## How it works [#how-it-works] 1. **Enable** call to action on a thank-you screen or exit form in the form editor. 2. **Choose surfaces** — set actions separately for **In-App** (form embedded in your product) and **Shareable link** (standalone form URL). 3. **Respondent finishes or is routed** — on a thank-you screen they see CTA buttons; on an exit form the form ends with no UI when a [Logic jumps](/docs/feedback-management/form-builder/logic-jumps) rule targets it. 4. **Action runs** — when call to action is **enabled**, the configured action executes (close, redirect, or in-app navigation). If call to action is **not enabled** on an exit form, the form still ends silently but no post-exit action runs. If call to action is disabled on a thank-you screen, respondents see a single button using the **Next button label** (typically Close). ## Configuration [#configuration] 1. Open your feedback form on the **Form** tab. 2. Edit a **Thank you screen** or **Exit form** in the **Thank you & Exit Section**. 3. Find **Call to action** and click **Configure**. 4. Turn on **Enable call to action**. 5. Set per-surface actions for **In-App** and **Shareable link** as needed. 6. Save the panel. ### Surfaces [#surfaces] | Surface | When it applies | | ------------------ | -------------------------------------------------------- | | **In-App** | Form runs inside your product via the Web or mobile SDK. | | **Shareable link** | Form is opened as a standalone URL in a browser tab. | If a surface is not configured, the form falls back to **Close form** on that surface. ### Actions [#actions] Each surface supports one action. Available options depend on the panel type and button (primary vs secondary): | Action | Description | | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Close form** | Dismiss the form. Default when call to action is disabled or a surface is unset. | | **Navigate in app** | Send respondents to a route inside your app. Available on **In-App** only—not on shareable links. Requires SDK integration — see [Web SDK](/docs/sdk-reference/web) or [Mobile SDK](/docs/sdk-reference/mobile-sdk/react-native). | | **Open in same tab / in-app browser** | Open a URL in the current tab or in-app browser. | | **Open in new tab / external browser** | Open a URL in a new browser tab or the device browser. **Not available** on shareable links for **exit form** primary actions or **secondary** button actions. | For **Navigate in app**, enter a route such as `onboarding/start` or `billing/upgrade`. Your development team maps that route in the SDK integration. For redirect actions, enter a valid `http://` or `https://` URL. On the **In-App** surface, **Open in new tab / external browser** may not work reliably in all application setups. ## Thank you screen options [#thank-you-screen-options] When call to action is enabled on a thank-you screen: | Option | Description | | --------------------------- | -------------------------------------------------------------------------------------------- | | **Primary button label** | Text on the main CTA button. If unset, the **Next button label** is used. | | **Auto-trigger delay (ms)** | Optional timer that fires the primary action automatically. Leave empty for manual-only. | | **Primary button actions** | Per-surface action for the main button (In-App and Shareable link). | | **Secondary button** | Optional second button with its own label (default: **Close form**) and per-surface actions. | Translate **Primary button label** and **Secondary button label** per language using the language tabs. Actions, URLs, routes, and auto-trigger settings are shared across languages. See [Language Setup](/docs/feedback-management/form-builder/language-setup) for multilingual forms. ## Exit form options [#exit-form-options] Exit forms have no respondent-visible UI. When a logic jump routes here **and call to action is enabled**, the configured action fires on the matching surface: | Option | Description | | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | **Auto-trigger delay (ms)** | Use **0** for an immediate silent action (this is also the default when left empty). Optional higher values delay the action. | | **Primary button actions** | Per-surface action (In-App and Shareable link). No button labels—the exit form shows no screen. | Exit forms do not support a secondary button. If call to action is **not enabled**, the form still ends silently with no thank-you screen, but no post-exit redirect or navigation runs. ## Examples [#examples] ### Thank you → upgrade page [#thank-you--upgrade-page] 1. Edit the thank-you screen → **Call to action** → enable. 2. Set **Primary button label** to `Upgrade now`. 3. **In-App** → **Navigate in app** → route `billing/upgrade`. 4. **Shareable link** → **Open in same tab / in-app browser** → `https://yoursite.com/pricing`. 5. Work with your development team to handle in-app navigation for the `billing/upgrade` route in your SDK integration. ### Silent exit for disqualified respondents [#silent-exit-for-disqualified-respondents] 1. Add an **[Exit form](/docs/feedback-management/question-types/panels/exit-form)** in the Thank you & Exit Section. 2. **Call to action** → enable → **Auto-trigger delay** `0` → **Close form** on both surfaces. 3. On a screening question, add a logic jump: disqualified answer → **Go to** Exit form. Respondents on that branch end immediately with no thank-you screen. ### Auto-close after 5 seconds [#auto-close-after-5-seconds] 1. Thank-you screen → enable call to action. 2. **In-App** and **Shareable link** → **Close form**. 3. **Auto-trigger delay** → `5000`. The thank-you message stays visible for five seconds, then the form dismisses automatically. ## Tips [#tips] * Configure **both surfaces** when the same form is used in-app and via shareable links. * Use a **secondary button** on thank-you screens for “Continue” + “Close” patterns (for example primary → upgrade, secondary → close). * Pair exit forms with **[Logic jumps](/docs/feedback-management/form-builder/logic-jumps)** for screening flows that should end without a thank-you message. * Test call to action behavior in **Test logic jumps** using **In app** vs **Shareable** preview modes. ## Related [#related] * [Thank you screen](/docs/feedback-management/question-types/panels/thank-you-screen) * [Exit form](/docs/feedback-management/question-types/panels/exit-form) * [Logic jumps](/docs/feedback-management/form-builder/logic-jumps) * [Language Setup](/docs/feedback-management/form-builder/language-setup) * [Web SDK](/docs/sdk-reference/web) — developer integration for in-app navigation and CTA events * [Mobile SDK](/docs/sdk-reference/mobile-sdk/react-native) — developer integration for in-app navigation and CTA events # Form Elements (/docs/feedback-management/form-builder/form-elements) Content coming soon. # Language Setup (/docs/feedback-management/form-builder/language-setup) **Language Setup** lets you add multiple languages to your feedback form so respondents can complete it in their preferred language. You can select which languages to support, set a default language, and use **Auto Translate** to translate form content across all configured languages. Language menu in the Questions toolbar ## Purpose [#purpose] Language Setup enables multilingual feedback forms. By adding multiple languages, you can: * **Reach a wider audience** — Respondents see the form in their preferred language. * **Improve completion rates** — Users are more likely to complete forms in their native language. * **Support global deployments** — Forms can be localized for different regions and markets. All form content—welcome screen, questions, end screen, labels, and error messages—can be configured per language. One language is designated as the **default** and serves as the primary or fallback language when a respondent's preference is not available. *** ## Configuration [#configuration] ### Selecting Languages [#selecting-languages] Language selection with Selected Languages and Add Language Open **Form design**, select **Questions**, then open the language menu in the builder toolbar. Use **Search languages...** to find a language by name or code. The language menu has two sections: **Selected Languages** — Lists languages currently active for your form. One language is marked as **Default** (e.g. **English \[en] Default**). The `[en]` is the ISO 639-1 language code used for programmatic reference. **Add Language** — Lists additional languages you can add. Each entry shows the language name and its code. Use the **+** icon next to a language to add it to Selected Languages. A warning icon marks languages that have not been configured under **Settings → Translations**. Supported languages include Chinese, Hindi, Spanish, Arabic, and others. After adding a language, complete any missing translations before publishing the form. ### Custom Language [#custom-language] If the language you need is not available in the dropdown, you can add a **Custom Language**. Scroll to the bottom of the Add Language list and click **+ Custom Language**. The **Add new language** dialog opens with two fields: * **Language Code** — Enter the code used to identify the language. The dialog requires an ISO-3166-style code. * **Language Label** — Enter a human-readable name for the language (e.g. `English`). This label appears in the language selector and tabs. Custom languages do not support translation content. Use them when your integration needs a custom language identifier and label rather than a translated form variant. Click **Add** to add the custom language, or **Cancel** to close the dialog without changing the form. Add new language dialog ### Editing Content Per Language [#editing-content-per-language] When editing form elements—such as the Welcome Screen, End Screen, or individual questions—you can switch between languages using tabs at the top of the edit dialog. Each tab shows the content for that language so you can enter or adjust text for questions, descriptions, error messages, and labels (e.g. minimum and maximum rating labels) per language. Edit question - Language tabs and Auto Translate *** ## Auto Translate with AI [#auto-translate-with-ai] **Auto Translate** uses AI to translate form content from one language into your other configured languages. This reduces manual translation work and helps keep content consistent across languages. ### How to Use It [#how-to-use-it] The **Auto Translate** button (with a sparkle icon) appears in the Questions toolbar and in editors that contain translatable content. Click it to open the translation menu: Auto Translate - Translate all or select specific languages **Translate to all languages** — Translates the form or open editor content into every configured language. **Select multiple languages** — Lets you choose which languages to translate into. Check the boxes for languages you wish to translate. Only the selected languages receive the AI translation. After choosing an option, the system fills the corresponding language tabs. Review the translations and adjust them as needed. In an open page or question editor, click **Save changes** to apply the edited content. ### When to Use Auto Translate [#when-to-use-auto-translate] * **Initial setup** — After adding new languages, use Auto Translate to quickly populate content from your default language. * **Bulk updates** — When you change question text, labels, or messages in one language, use Auto Translate to update the other languages. * **Consistency** — AI translation helps maintain consistent terminology and tone across languages. *** # Logic Jumps (/docs/feedback-management/form-builder/logic-jumps) **Logic jumps** let you send respondents to different questions based on their answers, workflow context, or user traits—so they can skip irrelevant steps and follow branching paths instead of a single fixed order. The **Logic jumps** tab sits in the feedback editor next to **Form** and **Appearance**. Use **Form** to add questions and pages first; then open **Logic jumps** to design and test branching. ## Before you start [#before-you-start] * Add questions on the **[Form](/docs/feedback-management/form-builder/build-feedback-form)** tab. The logic jumps canvas stays empty until at least one question exists. * For paths that should end **without** a thank-you screen, add an **[Exit form](/docs/feedback-management/question-types/panels/exit-form)** in the Thank you & Exit Section and use it as a jump target. ## Enable logic jumps [#enable-logic-jumps] At the top of the **Logic jumps** tab, turn on **Enable logic jumps**. * When enabled, the flow canvas appears with a **Start** node, your questions, and routing edges. * When you turn logic jumps **off**, a confirmation dialog warns that **all logic jump rules**, **canvas layout**, and **workflow context** for this feedback are cleared. You can enable logic jumps again later, but you will need to set them up from scratch. ## Flow canvas [#flow-canvas] The canvas is an interactive graph of your form flow: | Element | Description | | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | **Start** | Entry point before the first question. Rules here choose which question respondents see first. | | **Question nodes** | One node per form element (welcome, questions, message panels, thank-you screens, exit form). Each shows the type badge and title. | | **Section backgrounds** | Faint regions grouping nodes by form page/section. | | **Edges** | Lines from a source to a **Go to** target. Custom rules use the default edge style; the automatic **Else** (default) rule uses a **fuchsia** edge. | **Canvas controls** * Pan and zoom the graph; use the minimap and **fit view** control in the corner. * Open **fullscreen** for a larger canvas on complex forms. * When zoomed out, nodes switch to a **compact** view (type + title only). Zoom in to add or edit rules—compact nodes show a hint if you click them while zoomed out. **Visual indicators** * **Yellow border** — Hidden question (skipped at runtime like welcome/message panels; still routable). * **Red border** — Never reached: no incoming logic jump targets this question (orphan in the graph). Terminal screens (**Thank you screen**, **Exit form**) appear at the **end** of the logic order even if they live in the Thank you & Exit Section on the Form tab. They cannot have outgoing **Else** rules. ## How routing works [#how-routing-works] For each question (and for **Start**), the runtime evaluates rules in this order: 1. **Custom rules** — Listed on the node; evaluated top to bottom. 2. **Else (default) rule** — Always true (`1 = 1`); catches every case no custom rule matched. You can change only its **Go to** target. The **first rule whose conditions match** wins. Its **Go to** target is where the respondent goes next. **Start node** * Start rules run before any question is shown and pick the first question (or a later jump target). * If no Start rule matches, the respondent begins at the first question in logic order. **Linear fallback** * If no rule matches at a question and there is no valid default target, flow continues to the **next question in order** on the canvas. **Safety** * If routing would loop forever, the engine stops at a cycle instead of hanging. **Passthrough questions** * **Welcome screen** and **Message panel** do not collect answers; rules on them still run. * **Hidden** questions are auto-skipped for respondents but remain on the canvas for routing. ## Create and edit rules [#create-and-edit-rules] On any non-terminal node (or on **Start**), use **Add rule** or click an existing rule to open the rule editor. | Field | Behavior | | -------------- | -------------------------------------------------------------------------------------- | | **Rule title** | Required for custom rules. Must be unique per source node (case-insensitive). | | **Go to** | Target question. Must appear **after** the source in logic order (forward jumps only). | | **Conditions** | One or more conditions combined with **AND** or **OR**. | | **Delete** | Remove a custom rule. The **Else** rule cannot be deleted. | **Condition sources** * On a **question** node: conditions can reference that question and any **earlier** question that supports operators (see table below). * On **Start**: conditions can use **workflow context**, **user traits**, or **later** questions when testing with prefilled answers (see Start node section). **Matrix questions** * For rating matrix and matrix choice types, pick the **row/statement** the condition applies to, then set the operator and value for that row. ## Else (default) rule [#else-default-rule] Every non-terminal question gets an automatic **Else** rule: * It always matches when no custom rule does. * In the editor it is titled **default**; on the canvas its edge is **fuchsia**. * You can only change its **Go to** target—not its conditions or title. Use custom rules for branches; use **Else** for “everyone else goes here.” ## Terminal targets [#terminal-targets] | Target | Effect | | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **[Thank you screen](/docs/feedback-management/question-types/panels/thank-you-screen)** | Shows your closing screen, then submission completes. Optional [Call to action](/docs/feedback-management/form-builder/call-to-action) controls buttons, redirects, and auto-trigger. | | **[Exit form](/docs/feedback-management/question-types/panels/exit-form)** | Ends the session **silently** with no visible closing UI. Optional [Call to action](/docs/feedback-management/form-builder/call-to-action) can run a post-exit action. | Place thank-you screens and the optional exit form in the **Thank you & Exit Section** on the Form tab. In the logic graph they still act as valid **Go to** targets for any branch. ## Start node and workflow context [#start-node-and-workflow-context] ### Workflow context [#workflow-context] On the **Start** node, open **Workflow context** to define keys and types available when the form begins: | Type | Example use | | --------- | ------------------------------- | | `string` | Plan name, locale, feature flag | | `number` | Account tier, seat count | | `date` | Trial end, contract date | | `boolean` | Beta access, admin flag | Each field becomes `context.` in Start conditions (for example `context.plan`). Keys must be unique. Save the dialog to apply changes. ### User traits [#user-traits] Start rules can also test **[user traits](/docs/settings/user-data/user-traits)** as `contact.` (for example `contact.role`), using the trait’s data type for operators. Traits must exist in your project and be enabled; only types that map to string, number, date, or boolean are available in the rule editor. ### Prefilled questions on Start [#prefilled-questions-on-start] For testing or advanced flows, Start conditions may reference **forward** questions (answered via SDK prefill before the form opens). See **Test logic jumps** below. ### SDK and runtime data [#sdk-and-runtime-data] Pass metadata when showing the form so Start rules can branch immediately: ```javascript _encatch.showForm('form-abc-123', { context: { plan: 'enterprise' }, }); ``` The `context` object in [`showForm`](/docs/sdk-reference/web.mdx) is the same data exposed as `context.*` in Start rules. Identify users with traits before `showForm` when rules depend on `contact.*`. ## Operators by question type [#operators-by-question-type] Operators depend on the question (or context field) type. Unsupported types (welcome, thank you, exit form, message panel) cannot be used as condition sources. | Group | Question types (examples) | Operators | | -------------------- | ----------------------------------------------------------------------------------- | ---------------------------------------------------------------- | | **Text** | Short answer, long answer, email, website, phone, annotation | is, is not, contains, does not contain, is empty, is not empty | | **Number / scale** | Rating, NPS, CSAT, opinion scale, number, date | is, is not, greater/less than (or equal) | | **Single value** | Single choice, yes/no, consent, matrix single per row | is, is not | | **Multi value** | Multiple choice, nested selection, ranking, picture choice, matrix multiple per row | contains option, does not contain option, is empty, is not empty | | **Matrix rating** | Rating matrix (per row) | Same as number/scale for that row | | **Structured** | Address (country, etc.) | is, is not, is empty, is not empty | | **Presence only** | File upload, video/audio, signature, Q\&A with AI, scheduler, payments | is empty, is not empty | | **Context / traits** | Workflow context, user traits on Start | Matches field type (text/number/date/boolean operators) | For full field-level options, see the [Element Types Overview](/docs/feedback-management/question-types). ## Test logic jumps [#test-logic-jumps] Use **Test logic jumps** to simulate paths without publishing: 1. **Test mode** — **In app** (embedded preview) or **Shareable** (full-page style). 2. **Context & contact variables** — Enter sample values for `context.*` and `contact.*` used in Start rules. 3. **Prefill responses** — Set answers for questions before the live preview runs (mirrors SDK `addToResponse`). 4. **Live preview** — Answer questions in the preview; the canvas highlights the traced path (green = visited, blue pulse = current stop). Edges and nodes update as rules fire so you can confirm branching before go-live. ## Form tab interactions [#form-tab-interactions] Changes on the **Form** tab affect logic jumps automatically: * **Reorder or delete questions** — Custom rules whose target points **backward**, or whose conditions reference questions that now come **after** the source, are **removed**. You may see a toast listing pruned rule names. * **Hidden questions** — Still on the canvas but skipped for respondents; rules can still target or source them where supported. After large structural edits, review the canvas for **Never reached** (red) nodes and fix routing. ## Viewing responses [#viewing-responses] When logic jumps are enabled, submissions store which questions were on the respondent’s path. In **[Individual Responses](/docs/feedback-management/reports-and-export/feedback-dashboard/individual-responses)**, switch to **Respondent path** to see only questions the person actually saw—not the full form outline. ## Examples [#examples] ### NPS follow-up by score [#nps-follow-up-by-score] 1. Add an NPS question, a long-answer follow-up, and a thank-you screen. 2. On the NPS node, add a rule **Detractor follow-up**: NPS **is less than** 7 → **Go to** long answer. 3. Add a rule **Promoter thanks**: NPS **is greater than or equal to** 9 → **Go to** thank you. 4. Set **Else** → thank you (or another neutral path). ### Start by plan (SDK context) [#start-by-plan-sdk-context] 1. In **Workflow context**, add `plan` (string). 2. On **Start**, add a rule: `context.plan` **is** `enterprise` → **Go to** your premium block’s first question. 3. Set Start **Else** → default first question. 4. Launch with `showForm(..., { context: { plan: 'enterprise' } })`. ### Silent exit for disqualified respondents [#silent-exit-for-disqualified-respondents] 1. Add an **[Exit form](/docs/feedback-management/question-types/panels/exit-form)** at the end of the Thank you & Exit Section. 2. On a screening question, add a rule: answer **is** “No” → **Go to** **Exit form**. 3. Set **Else** → continue the main survey. Respondents on that branch end immediately with no thank-you screen. # Create a Feedback (/docs/feedback-management/form-creation-methods/create-a-feedback) This guide walks you through the complete workflow for creating a feedback form in encatch, from **New Form** through selecting a creation method, customizing your form, and publishing. ## Workflow Overview [#workflow-overview] Creating a feedback form in encatch follows three main steps: 1. **Create a form**: Open **Forms**, click **New Form**, then choose a template, **Start blank**, or **Encatch AI** 2. **Customize form**: Use the Form Builder to add questions, configure screens, and adjust settings 3. **Publish**: Save and make your form live *** ## Step 1: Select a creation method [#step-1-select-a-creation-method] Open **Forms** and click **New Form**. The creation dialog opens with the template browser, a **Start blank** action, and additional creation options below the template list. New Form dialog with templates and Start blank ### 1. Generate with AI [#1-generate-with-ai] Choose **Encatch AI** under **Other ways to create**, then describe what feedback you want to collect in plain language. encatch drafts a form with questions and structure tailored to your description. You can review the live preview and refine the result before moving it into the Form Builder. **Best for:** Quick starts, exploratory feedback, or when you want AI to suggest question types and flow. Encatch AI workspace with generated form and live preview ### 2. Using Templates [#2-using-templates] Start from pre-built templates for common scenarios such as feature adoption, onboarding feedback, and product satisfaction. Browse by team category, select a template to load its live preview, then click **Use this template** to create an editable draft. **Best for:** Standard use cases (NPS, CSAT, feature requests, bug reports) where you want a proven starting point. Ready Templates gallery with browse by role, industry, behaviour, and goal ### 3. From Scratch [#3-from-scratch] Build a form from scratch with full control over every question, page, and flow. Click **Start blank** in the creation dialog, enter a title and optional description, then add welcome screens, questions, and thank-you screens as needed. **Best for:** Custom use cases or when you want complete control over structure and wording. *** ## Step 2: Customize Form [#step-2-customize-form] Regardless of which method you chose, you land in the Form Builder where you can customize your form before publishing. Customize Form - Form Builder with questions and preview ### Form Builder Features [#form-builder-features] * **Welcome Screen**: Enable and configure an introductory screen * **End Screen**: Set a thank-you message, redirect to store, or a third-party link * **Questions**: Add, edit, reorder, and delete questions across multiple pages * **Other Fields**: Configure display options (question numbers, page titles) and button labels * **Languages**: Add multiple languages and use Auto Translate with AI For a detailed guide on building and customizing forms, see the Customize Feedback Form page. ### Quick Actions in the Form Builder [#quick-actions-in-the-form-builder] * Use **+ Add Question** to add new questions * Use the pencil icon to edit any element (Welcome Screen, End Screen, questions) * Use the trash icon to delete pages or questions * Use the drag handle to reorder questions within or between pages * Use the form-design actions to save your progress * Use the preview controls to review the form on supported devices *** ## Step 3: Publish [#step-3-publish] When your form is ready, click **Publish** or **Publish Edits**. The publish dialog asks for a required **Version Title**, optional notes, and whether this version should become the live version. Publish Edits dialog with version title, notes, and live-version option Before publishing, you can: * **Preview**: See how the form looks and behaves * **Save**: Save your work without publishing * **Configure**: Use **Form design**, **Distribution**, and **Destinations** to finish the form before launch After publishing, your feedback form is active and will collect responses based on your targeting and trigger settings. *** ## Summary: Method Comparison [#summary-method-comparison] | Method | Entry Point | Best For | | --------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------------------------ | | Generate with AI | **New Form** → **Encatch AI** | Quick starts, exploratory feedback | | Using Templates | **New Form** → choose a template | Standard use cases (NPS, CSAT, feature requests) | | From Scratch | **New Form** → **Start blank** | Full control, custom use cases | All three methods lead to the same Form Builder, where you customize and publish. # Generate with AI (/docs/feedback-management/form-creation-methods/generative-ai) Generate with AI lets you create feedback forms from plain-language descriptions. Describe what feedback you want to collect, and encatch uses AI to draft a form with questions, sections, and question types tailored to your goals. You keep full control: preview the result in real time, refine it with a Notion-style editor or AI chat, and publish when ready. encatch introduces **AI-powered form generation** with support for multiple assistants—use the built-in **Encatch AI** or bring your own workflow with external models. AI uses credits to generate forms when you use **Encatch AI**. Credits consumed are shown in the chat input bar (for example, **1 credit used**) so you can track your usage. External assistants use your own provider accounts. ## AI-powered form generation [#ai-powered-form-generation] Choose an assistant from the provider dropdown in the **AI assist** input bar on the **Design your form** page: | Provider | Description | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Encatch AI** | Built-in assistant. Chat directly in encatch, switch between **Ask** and **Build** modes, and apply changes with live preview. Uses encatch AI credits. | | **GPT models** | Open **ChatGPT** with a prefilled prompt, generate the form in ChatGPT, then paste the returned questionnaire YAML back into encatch. | | **Claude** | Open **Claude** with a prefilled prompt, generate the form there, then paste the YAML response into encatch. | | **Google AI Studio** | Open **AI Studio** with a prefilled prompt, generate the form there, then paste the YAML response into encatch. | With external providers, encatch prepares the prompt and opens the selected tool in a new tab. After the model returns questionnaire YAML, paste it into the dialog and click **Apply YAML to form** to load the draft into the live preview. For a full example, see [Using ChatGPT (GPT models)](#using-chatgpt-gpt-models). *** ## Why Use Generate with AI? [#why-use-generate-with-ai] * **Multiple AI providers** — Use **Encatch AI**, **GPT models**, **Claude**, or **Google AI Studio** to draft your form. * **Faster start** — Skip the blank canvas. Describe your intent in a few sentences and get a structured form in seconds. * **Smart question types** — AI suggests appropriate input types (Rating, NPS, Short Answer, Multiple Choice, and more) based on your description. * **Logical flow** — Questions are organized into pages with welcome and thank-you screens where appropriate. * **Live preview** — See the form update on the right as AI builds it or as you edit manually. * **Notion-style rich text editor** — Switch to **Manual edit** for block-based editing with rich text formatting alongside AI chat. * **Edit before launch** — Open the Form Builder to fine-tune questions, appearance, targeting, and triggers before publishing. *** ## Workflow Overview [#workflow-overview] Generating a feedback form with AI follows four main steps: 1. **Start** — Open **Forms**, click **New Form**, then choose **Encatch AI** under **Other ways to create** 2. **Prompt & Generate** — Describe your form on the **Design your form** page; AI drafts sections and questions 3. **Refine** — Use **AI assist**, **Manual edit**, and the live preview to adjust the draft 4. **Publish** — Click **Proceed to draft**, then **Publish** in the Form Builder *** ## Step 1: Open Encatch AI [#step-1-open-encatch-ai] Open **Forms**, click **New Form**, then choose **Encatch AI** under **Other ways to create**. New Form dialog with template and blank-form options This opens the **Design your form** page—a split view with your build workspace on the left and a **Live preview** on the right. *** ## Step 2: Prompt & Generate [#step-2-prompt--generate] On the **Design your form** page, describe the questionnaire you want in the input at the bottom. The conversation appears on the left while the form preview updates on the right. **Example prompts:** * *"Create a customer satisfaction feedback form with rating questions, NPS score, and open-ended feedback across multiple sections."* * *"Build a product feedback form with questions about features, usability, and improvement suggestions organized into different sections."* * *"Design an employee engagement feedback form with multiple choice questions and rating scales spread across several sections."* When you send a prompt, AI drafts the form structure. A status such as **Form updated** confirms the result, and the **Live preview** panel updates to show the welcome screen, pages, and questions. Design your form—AI-generated form with chat and live preview **Using Encatch AI:** Select **Encatch AI** in the provider dropdown. Use **Build** to generate or update the form directly, or **Ask** to plan before clicking **Build form**. Credits used appear in the input bar. **Using external providers:** Select **ChatGPT**, **Claude**, or **AI Studio**. encatch opens the provider with a prefilled prompt; paste the returned YAML into encatch to apply it to your draft. See [Using ChatGPT (GPT models)](#using-chatgpt-gpt-models) below for a step-by-step walkthrough. You can keep chatting (Encatch AI) or re-paste updated YAML (external providers) to add sections, change question types, or adjust wording. Messages are saved in your browser storage for the current session. *** ## Using ChatGPT (GPT models) [#using-chatgpt-gpt-models] You can generate forms with **ChatGPT** without using encatch AI credits. The same paste-and-apply flow works for **Claude** and **Google AI Studio**—only the provider name and opened tab change. ### 1. Select ChatGPT and send your prompt [#1-select-chatgpt-and-send-your-prompt] On the **Design your form** page, open the provider dropdown in the **AI assist** input bar and choose **ChatGPT**. Enter your prompt (or use an example prompt), then click **Send**. Select ChatGPT provider and send a form prompt encatch opens ChatGPT in a new tab with your prompt prefilled. A status message confirms: *Opened ChatGPT with your prompt prefilled. Paste the response in the dialog when ready.* ### 2. Generate questionnaire YAML in ChatGPT [#2-generate-questionnaire-yaml-in-chatgpt] In ChatGPT, review the prefilled instructions and submit your request. ChatGPT returns a brief plan, a fenced `yaml` code block with a `blocks` array, and a summary. ChatGPT generating Encatch questionnaire YAML Copy the full YAML block from ChatGPT (from `blocks:` through the last block). ### 3. Paste YAML and apply to your form [#3-paste-yaml-and-apply-to-your-form] Back in encatch, the **Paste ChatGPT response** dialog opens. Paste the YAML ChatGPT returned, then click **Apply YAML to form**. Paste ChatGPT response dialog with questionnaire YAML encatch validates the YAML and loads the form into the editor. The **Live preview** on the right updates to show welcome screens, pages, and questions. ### 4. Refine in Manual edit [#4-refine-in-manual-edit] Switch to the **Manual edit** tab to adjust blocks, wording, page breaks, and rich text formatting. Your ChatGPT-generated form stays in sync with the live preview. Form loaded from ChatGPT YAML in Manual edit with live preview When you are satisfied, click **Proceed to draft** to open the Form Builder and continue customizing before publish. *** ## Step 3: Refine your form [#step-3-refine-your-form] ### Live preview [#live-preview] The **Live preview** panel on the right updates as you build with **AI assist** or **Manual edit**. Use it to check layout, wording, and flow before opening the Form Builder. Switch device and theme controls in the preview toolbar to see how the form looks on mobile and in light or dark mode. ### Manual edit: Notion-style rich text editor [#manual-edit-notion-style-rich-text-editor] Switch to the **Manual edit** tab to refine your form in a Notion-style block editor with enhanced content creation and formatting. Design your form—Manual edit with Notion-style editor and live preview * **Block-based editing** — Each question type is a block you can add, reorder, and edit inline. * **Slash commands** — Type `/` to open the block palette and insert question types (Rating, NPS, Single Choice, Welcome screen, page breaks, and more). * **Rich text formatting** — Select text in question descriptions to apply **bold**, *italic*, and links. * **Drag and drop** — Reorder blocks by dragging. * **Seamless switching** — Move between **AI assist** and **Manual edit**; your form content stays in sync. ### Proceed to draft [#proceed-to-draft] When the draft looks right, click **Proceed to draft** in the header. This opens the Form Builder with your generated form loaded and ready to customize. *** ## Step 4: Customize & Publish [#step-4-customize--publish] In the Form Builder, you can adjust every detail before going live: * **Edit questions** — Click the pencil icon next to any question to change text, answer type, or settings. * **Reorder** — Use the drag handle to move questions within or between pages. * **Add or remove** — Use **+ Add question** to add fields; use the trash icon to delete questions or pages. * **Configure screens** — Edit the Welcome screen, Endings (thank-you screen), and other form elements. * **Tabs** — Use **Form**, **Appearance**, and **Logic jumps** (plus **Targeting**, **Triggers**, and **Advanced** from the bottom bar) to configure behavior. The Form Builder includes a real-time device preview. Use **Save now** to save progress without publishing. Form Builder—customize AI-generated form with live preview When the form meets your needs, click **Publish** to make it live. Before publishing, ensure: * Questions and wording are correct * Welcome and thank-you screens are configured if needed * Targeting and triggers are set as desired (if applicable) * You've previewed the form on the target device After publishing, the feedback form is active and collects responses according to your configuration. *** ## Best Practices [#best-practices] * **Be specific** — The more detail you provide in your prompt, the better AI can match question types and structure to your goals. * **Iterate in chat** — Ask for additional sections, different question types, or wording changes before moving to the Form Builder. * **Use Manual edit for polish** — Switch to **Manual edit** for fine-grained block edits, page breaks, and rich text formatting. * **Always preview** — Check the live preview and Form Builder device preview before publishing. * **Use ChatGPT without credits** — Select **ChatGPT** (or **Claude** / **AI Studio**) to generate YAML in your own account, then paste it back into encatch. * **Use AI credits wisely** — **Encatch AI** generations use credits; review your account usage if you generate frequently. *** ## Summary [#summary] | Step | Action | | --------------------- | ---------------------------------------------------------------------------------------------- | | **Start** | **Forms** → **New Form** → **Encatch AI** | | **Prompt & Generate** | Describe your form on **Design your form** (**AI assist** tab); credits shown in the input bar | | **Refine** | Use live preview, **Manual edit**, or continue chatting with AI | | **Proceed to draft** | Opens the Form Builder with your generated form | | **Publish** | Click **Publish** in the Form Builder to make the form live | Generate with AI is ideal for quick starts, exploratory feedback, or when you want AI to suggest structure and question types. For more on customizing forms after draft, see Customize Feedback Form. # From Scratch (/docs/feedback-management/form-creation-methods/manual-creation) **Start blank** lets you build a feedback form from an empty canvas with complete control over every question, page, and flow. Open **Forms**, click **New Form**, then choose **Start blank** to design exactly what you need. ## Why Use From Scratch? [#why-use-from-scratch] * **Full control**: Design every question, page break, and screen from scratch. No predefined structure to work around. * **Custom use cases**: Ideal when your feedback needs don't match common templates, such as unique surveys, internal tools, or highly specific flows. * **Precise wording**: Write your own questions and options without adapting someone else's copy. * **Flexible structure**: Add as many pages and questions as you need, in the order that makes sense for your workflow. * **No dependencies**: No need to browse templates or describe your intent to AI. Start building immediately. *** ## Accessing the Form Builder [#accessing-the-form-builder] 1. Open **Forms** and click **New Form**. 2. Click **Start blank** in the creation dialog. New Form dialog showing Start blank 3. In the dialog that opens, enter a **title** and optional **description**, then click **Create Form**. 4. encatch creates a new draft form and opens the Form Builder with an empty form ready for you to build. *** ## Step-by-Step: Building Your Form [#step-by-step-building-your-form] ### Step 1: Review the Form Name [#step-1-review-the-form-name] The title and description you entered when creating the form appear in the Form Builder header. Click the form name to open the edit dialog and update them at any time. ### Step 2: Configure Welcome Screen, End Screen, and Other Fields [#step-2-configure-welcome-screen-end-screen-and-other-fields] Use the configuration blocks to set up the structure of your form: * **Welcome Screen**: Enable this to show an introductory screen before questions. Configure the message, button text, and styling. * **End Screen**: Enable this to show a thank-you message after submission. You can add a redirect to your app store, a third-party link, or a custom message. * **Other Fields Configuration**: Enable this to configure display options such as question numbers, page titles, and button labels. Each block has an edit icon. Click it to configure the details. ### Step 3: Add Questions [#step-3-add-questions] 1. Click **+ Add Question** to add a new question to your form. 2. Search or browse the grouped question types, then choose the element you need. 3. Enter the question text and configure options (required/optional, validation, etc.). 4. Use the **drag handle** (vertical ellipsis) to reorder questions within a page or move them between pages. 5. Use the **pencil icon** to edit a question and the **trash icon** to delete it. Question picker with grouped element types ### Step 4: Organize into Pages [#step-4-organize-into-pages] * Forms can have multiple pages. Use the page controls to add or delete pages. * Move questions between pages by dragging them. This helps you create logical sections and control the flow of your survey. * Each page can have its own set of questions; respondents advance page by page. ### Step 5: Preview and Save [#step-5-preview-and-save] * A **live preview** on the right shows how the form will appear to respondents (including mobile view). * Use the form-design actions to save your progress without publishing. * Use the preview toolbar to review supported device layouts. * Toggle between light and dark mode in the preview to check appearance in both themes. Form Builder with questions, configured screens, and live preview ### Step 6: Configure Appearance, Targeting, and Triggers [#step-6-configure-appearance-targeting-and-triggers] Use the tabs at the top of the Form Builder to fine-tune your form: * **Questions**: Add and edit questions, welcome screens, thank-you screens, and other fields. * **Appearance**: Customize colors, fonts, and section layouts. * **Logic jumps**: Route respondents through the form based on answers and context. * **Distribution**: Configure In-App targeting and triggers, Link & Email, and Advanced Options. * **Destinations**: Send responses to connected tools. ### Step 7: Publish [#step-7-publish] When your form is ready, click **Publish** or **Publish Edits**. Enter a version title, add optional notes, and choose whether the version should become live. Form Builder Publish button *** ## Form Builder Quick Reference [#form-builder-quick-reference] | Action | How | | ---------------------------- | ------------------------------------------ | | Add question | Click **+ Add Question** | | Edit question | Click the pencil icon | | Delete question | Click the trash icon | | Reorder questions | Drag using the vertical ellipsis handle | | Add page | Use page controls (add page) | | Configure Welcome/End Screen | Click edit icon on the configuration block | | Save without publishing | Use the available form-design save action | | Make form live | Click **Publish** or **Publish Edits** | *** ## Summary [#summary] | Step | Action | | ------------- | ---------------------------------------------------------------- | | **Access** | Open **Forms** → **New Form** → **Start blank** | | **Build** | Configure Welcome/End/Other Fields and add questions | | **Organize** | Use pages and drag-and-drop to structure the flow | | **Preview** | Use live preview to see how respondents will experience the form | | **Configure** | Set Appearance, Targeting, Triggers, and Advanced options | | **Publish** | Click Publish to make the form live | From Scratch gives you complete freedom to design feedback forms that match your exact needs. For detailed guidance on customizing forms, see Customize Feedback Form. # Ready Templates (/docs/feedback-management/form-creation-methods/templates) The template browser helps you create feedback forms from pre-built starting points. Open **Forms** and click **New Form** to browse templates, load a live preview, and create an editable draft. ## Why Use Ready Templates? [#why-use-ready-templates] * **Best-practice design** — Templates are designed for common feedback scenarios (NPS, CSAT, feature requests, onboarding) with appropriate question types and flow. * **Quick discovery** — Browse by team category and select a template from the list. * **Live preview** — Preview any template before using it, then launch or customize in minutes. * **Full control** — Templates are starting points. You keep full control to add, remove, or edit any question, page, or option before launch. *** ## Accessing the Ready Templates Page [#accessing-the-ready-templates-page] 1. Open **Forms** in the encatch dashboard. 2. Click **New Form** to open **Start with a proven template**. Ready Templates gallery—browse by role, industry, behaviour, and goal *** ## Browse and Filter Templates [#browse-and-filter-templates] Choose a category such as **Product Management**, **Customer Success**, **Marketing**, **Engineering**, or **Research Panel**. The left side lists templates with descriptions and type labels. Selecting a row loads its description, delivery label, and live preview on the right. *** ## How to Use Ready Templates [#how-to-use-ready-templates] ### Step 1: Browse and Filter [#step-1-browse-and-filter] * **Choose a category** — Use the category buttons above the list. * **Compare templates** — Read the title, description, and Survey, Feedback, or Form label in each row. * **Browse the full gallery** — Use **Browse all templates** to open the complete Encatch template catalog. ### Step 2: Preview a Template [#step-2-preview-a-template] Select a template row that fits your use case. Its live preview opens on the right so you can review the form before using it. ### Step 3: Use the Template [#step-3-use-the-template] * Click **Use this template** beside the preview to create a new form based on the selected template. * encatch creates a draft form with all questions and structure pre-filled. You land in the Form Builder. ### Step 4: Customize in the Form Builder [#step-4-customize-in-the-form-builder] In the Form Builder, you can fully customize the form before publishing: * **Edit questions** — Change wording, answer types, and settings using the pencil icon. * **Reorder** — Use the drag handle to move questions within or between pages. * **Add or remove** — Use **+ Add Question** to add fields; use the trash icon to delete questions or pages. * **Configure screens** — Enable and configure the Welcome Screen and End Screen. * **Other settings** — Adjust languages, appearance, targeting, triggers, and advanced options from the form tabs. A real-time mobile preview shows how the form will appear to respondents. Use **Save now** to save progress without publishing. Form Builder—customize template, add questions, and preview ### Step 5: Publish [#step-5-publish] When the form meets your needs, click **Publish** to make it live. Before publishing, ensure targeting, triggers, and appearance are configured as desired. Form Builder—Publish button ## Download and upload templates [#download-and-upload-templates] You can move a form design between projects or keep it as a reusable JSON template. ### Download a form as JSON [#download-a-form-as-json] 1. Open the form in the builder. 2. Open **More form actions** in the top-right corner. 3. Under **Templates**, select **Download as template**. Form actions with Download as template The downloaded file contains the form structure and configuration. It does not contain collected responses. ### Upload a saved template [#upload-a-saved-template] 1. Open **Forms → New Form**. 2. Go to **My saved templates**. 3. Select **Upload template** and choose the downloaded JSON file. 4. Review the imported template, then use it to create an editable draft. Treat imported templates as starting points. Review targeting, triggers, destinations, and environment-specific settings before publishing in another project. *** ## Example Templates [#example-templates] * **Feature Adoption Survey** — Understand how users discover and adopt new features. * **New User Onboarding Feedback** — Capture friction points during onboarding and improve activation. * **Product Satisfaction Survey** — Measure overall satisfaction and identify areas for improvement. * **Feature Requests** — Gather new feature requests from your customers. * **Help Center Feedback** — Make your help center more helpful and resolve issues quickly. * **Mobile UX** — Improve the user experience of your mobile app. * **Build a Research Panel** — Create a survey to build a panel of participants for future interviews. *** ## Summary [#summary] | Step | Action | | ------------- | ------------------------------------------------------- | | **Access** | Open **Forms** → **New Form** | | **Browse** | Choose a team category and select a template row | | **Preview** | Review the selected template in the live preview | | **Use** | Click **Use this template** to create a draft form | | **Customize** | Edit in the Form Builder—add, remove, reorder questions | | **Publish** | Click Publish to make the form live | Ready Templates streamline feedback form creation by providing proven starting points for common scenarios. You keep full control to tailor every form to your needs. For more on customizing forms, see Customize Feedback Form. # Element Types Overview (/docs/feedback-management/question-types) Form elements are the building blocks of your feedback form. Each type serves a specific purpose in collecting user feedback. In the form builder, **Add question** groups types the same way as below. Use the sidebar or the links under each group to open the doc for that element. The **Add new Question** dialog includes **Search form elements**, a **Recommended** shortlist, and an **Include sample content** option. When sample content is selected, encatch prefills titles, choices, and consent markdown where applicable so you can inspect a typical structure before editing it. Add new Question picker with grouped form elements ### Scale [#scale] * **[Rating](/docs/feedback-management/question-types/scale/rating)** — Star or other icon rating scale * **[CSAT (Rating)](/docs/feedback-management/question-types/scale/csat-rating)** — Customer satisfaction on a visual rating scale * **[NPS](/docs/feedback-management/question-types/scale/nps)** — Net Promoter Score (0–10) * **[Opinion scale](/docs/feedback-management/question-types/scale/opinion-scale)** — Flexible numeric button scale (start at 0 or 1, 5–11 steps) with optional end labels ### Choice [#choice] * **[Single Choice](/docs/feedback-management/question-types/choice/single-choice)** — Exactly one option from a list * **[Multiple Choice](/docs/feedback-management/question-types/choice/multiple-choice)** — One or more options (“select all that apply”) * **[Yes / No](/docs/feedback-management/question-types/choice/yes-no)** — Binary choice with customizable labels * **[Consent](/docs/feedback-management/question-types/choice/consent)** — Agree / disagree to terms or policy text (markdown), without custom option labels * **[Nested Selection](/docs/feedback-management/question-types/choice/nested-selection)** — Dependent hierarchical selections (parent and child options) * **[Ranking](/docs/feedback-management/question-types/choice/ranking)** — Order options by preference (drag-and-drop or arrows) * **[Picture choice](/docs/feedback-management/question-types/choice/picture-choice)** — Image grid with optional multiple selection and “Other” ### Matrix [#matrix] * **[Rating matrix](/docs/feedback-management/question-types/matrix/rating-matrix)** — Multiple statements rated on one shared scale * **[Matrix (single per row)](/docs/feedback-management/question-types/matrix/matrix-single-choice)** — Grid: one column choice per row * **[Matrix (multiple per row)](/docs/feedback-management/question-types/matrix/matrix-multiple-choice)** — Grid: multiple column selections allowed per row ### Text [#text] * **[Short Answer](/docs/feedback-management/question-types/text/short-answer)** — Single-line text * **[Long Answer](/docs/feedback-management/question-types/text/long-answer)** — Multi-line text * **[Date](/docs/feedback-management/question-types/text/date)** — Date (and optional time) with format, separator, and min/max bounds * **[Number](/docs/feedback-management/question-types/text/number)** — Numeric value with optional min/max, decimals, negatives, unit, and pre-fill ### Panels [#panels] * **[Welcome screen](/docs/feedback-management/question-types/panels/welcome-screen)** — Opening screen before the first question * **[Thank you screen](/docs/feedback-management/question-types/panels/thank-you-screen)** — Closing screen after submit * **[Exit form](/docs/feedback-management/question-types/panels/exit-form)** — Silent end marker (no UI); logic jump target to stop the form * **[Call to action](/docs/feedback-management/form-builder/call-to-action)** — Post-submit redirects, in-app navigation, and auto-trigger on thank-you screens and exit forms * **[Message panel](/docs/feedback-management/question-types/panels/message-panel)** — Non-question content between items (markdown, continue action) For branching between questions, see **[Logic jumps](/docs/feedback-management/form-builder/logic-jumps)** in the Form Builder docs. ### Contact Info [#contact-info] * **[Email](/docs/feedback-management/question-types/contact/email)** — Validated email with placeholder and optional pre-fill * **[Phone Number](/docs/feedback-management/question-types/contact/phone-number)** — Phone with country code, optional country lock, pre-fill * **[Website](/docs/feedback-management/question-types/contact/website)** — URL with placeholder and optional pre-fill * **[Address](/docs/feedback-management/question-types/contact/address)** — Structured postal address with per-line settings * **[Signature](/docs/feedback-management/question-types/contact/signature)** — Draw, type, or upload signature with canvas options ### Advanced [#advanced] * **[File upload](/docs/feedback-management/question-types/advanced/file-upload)** — Attachments with type filters, size limit, and optional multiple files * **[Video / Audio / Photo](/docs/feedback-management/question-types/advanced/video-audio)** — Recorded or uploaded media with optional duration and rich labels * **[Scheduler](/docs/feedback-management/question-types/advanced/scheduler)** — Google Calendar or Calendly embed with intro and autofill * **[Q\&A with AI](/docs/feedback-management/question-types/advanced/qna-with-ai)** — Knowledge-base-grounded chat with limits and UI copy ### Other [#other] * **[Other Fields Configuration](/docs/feedback-management/question-types/other-fields-configuration)** — Display options and button labels across the form Choose a page from the groups above or from the **Form Elements** section in the sidebar. # Other Fields Configuration (/docs/feedback-management/question-types/other-fields-configuration) The **Other Fields Configuration** lets you customize display options and button labels across your feedback form. Access it from the **Edit Other Fields** dialog to tailor the form experience to your needs. ## When to use [#when-to-use] * Control visibility of question numbers and page titles * Customize button labels for branding or localization ## Configuration [#configuration] You can customize these settings from the **Edit Other Fields** dialog. The following options are available: ### Display Options [#display-options] #### Show Question Number [#show-question-number] A checkbox that controls whether question numbers are displayed in the form. When enabled, respondents see numbered questions (e.g., 1, 2, 3) as they progress through the survey. #### Show Page Title [#show-page-title] A checkbox that controls whether the page title is displayed in the form. When enabled, respondents see the title of each page or section. ### Button Label Customization [#button-label-customization] All button label fields are required and support up to 50 characters each. #### Submit Button Label [#submit-button-label] The text displayed on the submit button—the button respondents click to submit their completed feedback. **Default:** "Submit" #### Previous Button Label [#previous-button-label] The text displayed on the previous button—the button respondents click to go back to the previous question or page. **Default:** "Previous" #### Next Button Label [#next-button-label] The text displayed on the next button—the button respondents click to advance to the next question or page. **Default:** "Next" # Dashboard Presets (/docs/feedback-management/reports-and-export/dashboard-presets) Dashboard presets save a report view so your team can reopen the same analysis without rebuilding it. A preset keeps the selected date range, conditions, breakdowns, and chart layout. Presets are available for **Audience Overview**, **Responses Summary**, and **Individual Responses**. ## Save a preset [#save-a-preset] 1. Open one of the supported report views. 2. Set the date range, filters, breakdowns, and presentation layout you want to reuse. 3. Open **Dashboard presets** in the report filter bar. 4. Save the current view with a clear name. Saving a preset does not duplicate responses. It stores the view configuration and applies it to the current report data when opened. ## Find and reuse presets [#find-and-reuse-presets] Open **Dashboard Presets** from the project sidebar. Search by preset or form name, filter by report type, switch between grid and list views, or narrow the list by form collection. Dashboard Presets workspace Select a preset to open its report with the saved configuration. The report still uses current data and respects your access to the underlying form. ## Keep presets useful [#keep-presets-useful] * Name the audience or decision in the preset, such as `Enterprise onboarding — last 30 days`. * Save separate presets when different teams need different breakdowns. * Update or replace presets when the report structure changes. # Export Reports (/docs/feedback-management/reports-and-export/export-reports) The **Export Reports** page lets you view, download, and analyze export jobs for your project. Each row links back to the feedback it came from, so you can jump from an export file to that form's results. Open **Export Reports** from the project sidebar to see all export jobs, their status, and download actions. ## Export jobs list [#export-jobs-list] The page shows a table of export jobs with: * **Status** — Pending, Initializing, Running, Completed, or Failed (see the status legend above the table) * **Export** — File name and linked feedback title * **Timeline** — Created, completed, and expiry times * **Actions** — Download and **Open with AI** Use **+ Create new export** to start a new export job, or **Refresh** to update the list. Exports arrive as `.gz` files. Unzip them before opening with 7-Zip, WinRAR, The Unarchiver, or your OS built-in archive tool. The file inside is typically CSV or JSON. *** ## Download an export [#download-an-export] For a **Completed** export, click the download icon to save the `.gz` file to your computer. Decompress it, then open the CSV or JSON in your spreadsheet, BI tool, or script. *** ## Open with AI [#open-with-ai] For completed exports, use **Open with AI** to send the export to an external assistant for analysis. The dropdown offers two providers: | Provider | Where it opens | Best for | | ---------- | --------------------------------------- | -------------------------------------------------------------------- | | **Claude** | Claude on the web or **Claude Desktop** | Slide-style summaries, themes, sentiment, and chart-ready breakdowns | | **Codex** | **Codex desktop app** | Code-oriented analysis and scripted exploration of export data | Export Reports—Open with AI dropdown with Claude and Codex Both options open a configuration dialog where you edit what the AI should analyze. encatch automatically includes the system instructions, file name, and secure download URL in the prompt. *** ## Open with Claude [#open-with-claude] Select **Claude** from the **Open with AI** menu to open the **Open with Claude** dialog. Open with Claude—prompt editor and domain setup ### One-time setup (Claude only) [#one-time-setup-claude-only] Before Claude can fetch your export, add the export download domain to Claude's allowlist: 1. In Claude, go to **Settings → Capabilities → Allow network egress** 2. Under **Additional allowed domains**, paste the domain shown in the dialog (for example `encatch-report-export.s3.ap-south-1.amazonaws.com`) 3. Click **Add** Use **Copy domain** in the dialog to copy the exact domain for your environment. Expand **How to add the domain** for step-by-step guidance. ### Configure your analysis [#configure-your-analysis] 1. Edit **What should the AI analyze?** — Describe what you want (for example, summarize themes, sentiment, or recurring issues). Click the info icon for example prompts such as **Executive summary**, **Find recurring issues**, **Sentiment and themes**, or **Prioritize improvements**. 2. Review the **System prompt** accordion — encatch adds instructions that the file is gzip-compressed CSV/JSON, plus the file name and download URL. 3. Check **I understand that export data may be shared with an external AI provider and want to continue.** 4. Click **Claude Web** or **Claude Desktop** to open Claude with the prefilled prompt. Claude downloads the export, decompresses it, and analyzes it according to your instructions. Opening an export in Claude shares export data with Anthropic. Review [Claude's privacy policy](https://www.anthropic.com/legal/privacy) before continuing. *** ## Open with Codex [#open-with-codex] Select **Codex** from the **Open with AI** menu to open the **Open with Codex** dialog. The flow is similar to Claude, with Codex-specific setup: * **Codex desktop app required** — Codex opens in the desktop app. Install it before continuing. * **Allow network access** — When Codex prompts for network access to download the export, click **Allow** for the domain shown in the dialog. * **Configure your analysis** — Edit the prompt, accept the external AI consent checkbox, then click **Codex App**. Opening an export in Codex shares export data with OpenAI. Review [OpenAI's privacy policy](https://openai.com/policies/privacy-policy/) before continuing. *** ## Example analysis prompts [#example-analysis-prompts] Use these as starting points in **What should the AI analyze?** (via the info icon or by typing your own): * **Executive summary** — Key insights, themes, sentiment, and top action items in a slide-style format * **Find recurring issues** — Group similar feedback and rank by frequency and business impact * **Sentiment and themes** — Positive and negative themes with chart suggestions * **Prioritize improvements** — A prioritized backlog with impact-effort framing *** ## Summary [#summary] | Action | How | | ----------------------- | --------------------------------------------------------------------------------------- | | **View exports** | Sidebar → **Export Reports** | | **Download** | Click the download icon on a completed job; unzip the `.gz` file | | **Analyze with Claude** | **Open with AI** → **Claude** → configure prompt → **Claude Web** or **Claude Desktop** | | **Analyze with Codex** | **Open with AI** → **Codex** → configure prompt → **Codex App** | For in-product AI analysis without external providers, see [Feedback Studio](/docs/feedback-management/reports-and-export/feedback-studio/external-insights). # Reports & Export (/docs/feedback-management/reports-and-export) ## Overview of Feedback Reports [#overview-of-feedback-reports] Encatch provides three comprehensive reporting views to help you understand and analyze your feedback data: 1. **Audience Analytics**: Provides insights about your audience and how they're engaging with your feedback forms. 2. **Response Summary**: Provides insights about what users are saying and question-level insights. 3. **Individual Responses**: Provides detailed insights into each user's feedback. Each report provides filters that help you narrow down the data to your specific needs example date filters. ## Export Report [#export-report] The **Export Reports** page lets you download feedback data for offline analysis and open completed exports with **Open with AI**—choose **Claude** (web or desktop) or **Codex** (desktop app) to analyze themes, sentiment, and insights from your export file. See the full guide: [Export Reports](/docs/feedback-management/reports-and-export/export-reports). ## Realtime Feedback Notifications [#realtime-feedback-notifications] The destination feature in encatch allows you to filter and chose which individual user feedback you would like to be notified about. Few available destinations are: * Email * Slack * Discord * Jira * GitLab * GitHub * Custom Webhook (that can be used with Zappier,n8n, MS power automate, etc.) Some usecase for this feature are: * You want to be notified about negative feedback from your users. * You want to be notified about feedback from your users about a specific bug. # Overview Dashboard (/docs/feedback-management/reports-and-export/summary-dashboard) ## Overview [#overview] The **Overview** dashboard summarizes feedback received across your project. Use the date range selector at the top (for example, **All Time** or a custom period) to filter the data and view metrics for your chosen timeframe. Summary Overview - Dashboard with date range, summary cards, and charts ## Data Summaries [#data-summaries] The dashboard displays key metrics in summary cards at the top, each with an information icon (ⓘ) for additional details: * **Responses** — Total number of feedback submissions received * **Viewed** — Total number of times your feedback forms were viewed * **Identified Users** — Number of users who submitted feedback while logged in or identified * **Unidentified Users** — Number of users who submitted feedback anonymously * **Active Feedbacks** — Number of feedback configurations currently active These metrics update dynamically based on the selected date range, providing a project-wise total for the chosen period. ## Chart Theme Customization [#chart-theme-customization] Admins can customize the visual appearance of the charts. Use the theme dropdown in the top right corner (next to the palette icon) to switch between options such as **Default**, **Classic Tableau**, **Vibrant Pop**, **Soft Pastels**, or **Earth & Stone** to match your preference. Summary Overview - Chart theme selector dropdown ## Report Views [#report-views] The Overview dashboard includes the following report views: * **[Views by Time (Daily)](/docs/feedback-management/reports-and-export/charts/views-by-time-daily)** — Daily view counts for your feedback forms * **[Submissions by Time (Daily)](/docs/feedback-management/reports-and-export/charts/submissions-by-time-daily)** — Daily submission counts * **[Engagement](/docs/feedback-management/reports-and-export/charts/engagement)** — User engagement metrics and conversion rates * **[Channel Distribution](/docs/feedback-management/reports-and-export/charts/channel-distribution)** — Breakdown by channel (web, mobile, etc.) * **[Language Distribution](/docs/feedback-management/reports-and-export/charts/language-distribution)** — Feedback by user language * **[Country Distribution](/docs/feedback-management/reports-and-export/charts/country-distribution)** — Geographic distribution of feedback Use these reports together to understand who is seeing your forms, who is responding, and how engagement varies across channels, languages, and regions. # Overview (/docs/feedback-management/targeting-and-triggers) In-App Feedback allows you to target your feedback forms to specific users based on their behavior, attributes, or engagement. ## In-app integration setup [#in-app-integration-setup] Configure in-app feedback in three stages: 1. **Targeting** — Choose who can see the form, including visitors, logged-in users, segments, languages, countries, and device types. 2. **Triggers** — Choose when it launches through a manual SDK call or an automatic rule based on timing, page visits, or tracked events. 3. **SDK integration** — Install the [JavaScript Web SDK](/docs/sdk-reference/web) or choose a [mobile or native SDK](/docs/sdk-reference/mobile-sdk), then verify the form in your application. You can revise targeting and triggers without reinstalling the SDK. Publish the form after the setup reflects the audience and moment you want. ## Triggers [#triggers] Triggers control *when* your feedback form appears. You can use one or both trigger types depending on how you want to collect feedback. ### Manual Trigger [#manual-trigger] The **Manual Trigger** shows your form on demand—whenever you decide it makes sense. You call `_encatch.showForm()` in your code at the exact moment you want the form to appear. Use it when you want full control over the feedback experience, such as: * "Contact us" or "Give feedback" buttons * Help menus or support flows * Custom in-app flows where you choose the trigger moment The form appears only when your code explicitly requests it. ### Automatic Trigger [#automatic-trigger] The **Automatic Trigger** shows your form based on rules you define—no code required. The system displays the form when conditions are met, such as: * A user visits a specific page * A tracked event fires (e.g. purchase, form submit) * A delay elapses after page load or user action Use it when you want hands-off collection at predictable moments in the user journey. # Next.js (/docs/framework-examples/ui-frameworks/nextjs) # Next.js [#nextjs] ## Overview [#overview] ## Getting started [#getting-started] # React.js (/docs/framework-examples/ui-frameworks/reactjs) # React.js [#reactjs] ## Overview [#overview] ## Getting started [#getting-started] # Astro Starlight (/docs/integrations/documentation-platforms/astro-starlight) Collect page-level feedback on every Starlight doc page: helpful votes, suggest an edit, and raise an issue. This guide follows the working example in [get-encatch/astro-starlight-examples](https://github.com/get-encatch/astro-starlight-examples). *** ## Overview [#overview] Starlight does not ship a layout hook for arbitrary footer widgets, so this integration **overrides two built-in components**: | Starlight component | Purpose | | ------------------- | --------------------------------------------------------------------------------- | | `Footer` | Renders the Encatch feedback row above the default footer (pagination, edit link) | | `PageFrame` | Mounts a small React island that initializes the Encatch Web SDK on each page | The feedback UI is a **React island** (`client:load`) so it stays interactive while the rest of the page remains static Astro output. * An Astro Starlight project (`@astrojs/starlight` and `@astrojs/react`) * [`@encatch/web-sdk`](https://www.npmjs.com/package/@encatch/web-sdk) **1.5.2** or later * A [publishable SDK key](/docs/settings/security/publishable-sdk-keys) with your docs origin in **Allowed Domains / Packages** * A published **documentation feedback** form in Encatch (combined form with logic jumps for helpful / suggest edit / raise issue) *** ## Step 1: Install dependencies [#step-1-install-dependencies] In your Starlight project: ```bash pnpm add @encatch/web-sdk @astrojs/react react react-dom lucide-react pnpm add -D @types/react @types/react-dom ``` ```bash npm install @encatch/web-sdk @astrojs/react react react-dom lucide-react npm install -D @types/react @types/react-dom ``` ```bash yarn add @encatch/web-sdk @astrojs/react react react-dom lucide-react yarn add -D @types/react @types/react-dom ``` Enable React and register Starlight component overrides in `astro.config.mjs`: ```js // astro.config.mjs import { defineConfig } from 'astro/config'; import starlight from '@astrojs/starlight'; import react from '@astrojs/react'; export default defineConfig({ integrations: [ react(), starlight({ title: 'My docs', customCss: ['./src/styles/encatch.css'], components: { Footer: './src/components/EncatchFooter.astro', PageFrame: './src/components/EncatchPageFrame.astro', }, }), ], }); ``` *** ## Step 2: Configure environment variables [#step-2-configure-environment-variables] Copy these variables into `.env` (use the `PUBLIC_` prefix so Astro exposes them to client code): ```bash # Required PUBLIC_ENCATCH_SDK_PUBLISHABLE_KEY= PUBLIC_ENCATCH_DOCUMENTATION_FEEDBACK_FORM_SLUG=documentation_feedback PUBLIC_ENCATCH_FEEDBACK_TYPE_QUESTION_SLUG=documentation_feedback_type PUBLIC_ENCATCH_PAGE_URL_QUESTION_SLUG=page_url PUBLIC_ENCATCH_HELPFUL_CHOICE_QUESTION_SLUG=helpful_question_choice # Optional — leave blank for encatch.com defaults PUBLIC_ENCATCH_API_HOST= PUBLIC_ENCATCH_WEB_HOST= ``` | Variable | Description | | ------------------------------------------------- | --------------------------------------------------------------------------- | | `PUBLIC_ENCATCH_SDK_PUBLISHABLE_KEY` | Publishable key from **Settings → Publishable SDK Keys** | | `PUBLIC_ENCATCH_DOCUMENTATION_FEEDBACK_FORM_SLUG` | Slug of your combined documentation feedback form | | `PUBLIC_ENCATCH_FEEDBACK_TYPE_QUESTION_SLUG` | Hidden/routing question that selects helpful vs suggest-edit vs raise-issue | | `PUBLIC_ENCATCH_PAGE_URL_QUESTION_SLUG` | Question prefilled with the current page URL | | `PUBLIC_ENCATCH_HELPFUL_CHOICE_QUESTION_SLUG` | Yes/No question prefilled when the reader votes helpful | The example repo ships a one-click **Install form** button in its README if you need the combined form created in your workspace automatically. *** ## Step 3: Add SDK helpers [#step-3-add-sdk-helpers] Create `src/components/encatch.ts` to initialize the SDK and open the combined form with the correct logic-jump prefills: ```ts import { _encatch } from '@encatch/web-sdk'; import type { Theme } from '@encatch/web-sdk'; type DocumentationFeedbackRoute = 'page-helpful' | 'suggest-edit' | 'raise-issue'; function ensureEncatchInitialized(options?: { theme?: Theme }): boolean { if (typeof window === 'undefined') return false; const apiKey = import.meta.env.PUBLIC_ENCATCH_SDK_PUBLISHABLE_KEY?.trim(); if (!apiKey) { console.warn('PUBLIC_ENCATCH_SDK_PUBLISHABLE_KEY is not set'); return false; } if (!_encatch._initialized) { _encatch.init(apiKey, { theme: options?.theme ?? 'system' }); } return true; } export function openHelpfulFeedbackForm( pageUrl: string, vote: 'yes' | 'no', locale?: string, ) { // Prefill feedback type, page URL, and yes/no — then showForm(formSlug) // See full implementation in get-encatch/astro-starlight-examples } export function openSuggestEditForm(pageUrl: string, locale?: string) { // Route to suggest-edit branch of the combined form } export function openRaiseIssueForm(pageUrl: string, locale?: string) { // Route to raise-issue branch of the combined form } ``` The [example repository](https://github.com/get-encatch/astro-starlight-examples/blob/main/src/components/encatch.ts) contains the full `openDocumentationFeedbackForm` helper, host overrides, and locale sync. *** ## Step 4: Build the feedback UI [#step-4-build-the-feedback-ui] Create `src/components/DocsPageFeedback.tsx` — a React footer row with helpful votes and action buttons: ```tsx import { useState } from 'react'; import { CircleAlert, Pencil, ThumbsDown, ThumbsUp } from 'lucide-react'; import { openHelpfulFeedbackForm, openRaiseIssueForm, openSuggestEditForm, } from './encatch'; export function DocsPageFeedback({ pageUrl, locale, helpfulQuestion, yes, no, suggestEdits, raiseIssue }) { const [vote, setVote] = useState<'yes' | 'no' | null>(null); const handleVote = (next: 'yes' | 'no') => { const newVote = vote === next ? null : next; setVote(newVote); if (newVote) openHelpfulFeedbackForm(pageUrl, newVote, locale); }; return (
{/* Helpful question + Yes/No pills */} {/* Suggest edits + Raise issue buttons */}
); } ``` Copy the complete component from the [example repo](https://github.com/get-encatch/astro-starlight-examples/blob/main/src/components/DocsPageFeedback.tsx). *** ## Step 5: Override Starlight components [#step-5-override-starlight-components] ### PageFrame — initialize the SDK [#pageframe--initialize-the-sdk] `src/components/EncatchPageFrame.astro` wraps the default frame and mounts `EncatchInit` as a client island: ```astro --- import Default from '@astrojs/starlight/components/PageFrame.astro'; import { EncatchInit } from './EncatchInit'; const locale = Astro.currentLocale ?? 'en'; --- ``` `EncatchInit.tsx` calls `ensureEncatchInitialized()` and `syncEncatchLocale(locale)` inside a `useEffect`. ### Footer — render feedback on doc pages [#footer--render-feedback-on-doc-pages] `src/components/EncatchFooter.astro` renders the feedback row only on documentation pages: ```astro --- import Default from '@astrojs/starlight/components/Footer.astro'; import { DocsPageFeedback } from './DocsPageFeedback'; const { entry, id } = Astro.locals.starlightRoute; const locale = Astro.currentLocale ?? 'en'; const isDocPage = id !== undefined; --- {isDocPage && ( )} ``` Add `docsFeedback.*` strings to your Starlight i18n files under `src/content/i18n/` (or hard-code labels while prototyping). *** ## Step 6: Style the footer row [#step-6-style-the-footer-row] Add `src/styles/encatch.css` and reference it in `starlight({ customCss: [...] })`. Use Starlight CSS variables (`--sl-color-text`, `--sl-color-gray-5`, etc.) so the footer matches light and dark themes. See [encatch.css in the example repo](https://github.com/get-encatch/astro-starlight-examples/blob/main/src/styles/encatch.css) for pill buttons, spacing, and border treatment. *** ## Step 7: Run and verify [#step-7-run-and-verify] ```bash pnpm dev ``` Open a doc page, click **Yes** or **No**, **Suggest edits**, or **Raise issue**, and confirm the Encatch modal opens with the page URL prefilled. Check responses in your Encatch dashboard under the linked form. If the modal does not open, confirm your local or production docs URL is listed on the publishable key's **Allowed Domains / Packages** (for example `localhost:4321` during development). *** ## Next steps [#next-steps] * **Route feedback to your team** — Connect [GitHub](/docs/destinations/github), [Slack](/docs/destinations/slack), or other [destinations](/docs/destinations) * **Customize the form** — Edit questions and logic jumps in the Encatch dashboard * **Web SDK reference** — Advanced APIs such as `addToResponse`, locale, and theme: [JavaScript Web SDK](/docs/sdk-reference/web) *** ## Related links [#related-links] * [Example repository](https://github.com/get-encatch/astro-starlight-examples) * [All Encatch example repos](https://github.com/orgs/get-encatch/repositories) * [Starlight component overrides](https://starlight.astro.build/guides/overriding-components/) * [Documentation platform overview](/integrations/documentation-platforms/astro-starlight) on encatch.com # Docusaurus (/docs/integrations/documentation-platforms/docusaurus) Collect page-level feedback on every Docusaurus page: helpful votes, suggest an edit, and raise an issue. The fastest way to get started is the working example on GitHub: **[get-encatch/docusaurus-examples](https://github.com/get-encatch/docusaurus-examples)** That repo is a sample Docusaurus docs site with Encatch page feedback in the footer. *** ## What you'll need [#what-youll-need] * A Docusaurus project * [`@encatch/web-sdk`](https://www.npmjs.com/package/@encatch/web-sdk) * A [publishable SDK key](/docs/settings/security/publishable-sdk-keys) with your docs origin in **Allowed Domains / Packages** * A published **documentation feedback** form in Encatch (combined form with logic jumps for helpful / suggest edit / raise issue) You can install a ready-made form from the [documentation feedback template](https://templates.encatch.com/templates/preview/documentation-frameworks/docs-feedback). *** ## Related [#related] * [Example repository](https://github.com/get-encatch/docusaurus-examples) * [All Encatch example repos](https://github.com/orgs/get-encatch/repositories) * [Documentation platform overview](/integrations/documentation-platforms/docusaurus) on encatch.com # Fumadocs (/docs/integrations/documentation-platforms/fumadocs) Collect page-level feedback on every Fumadocs page: helpful votes, suggest an edit, and raise an issue. The fastest way to get started is the working example on GitHub: **[get-encatch/fumadocs-examples](https://github.com/get-encatch/fumadocs-examples)** That repo includes sample Fumadocs apps (Next.js, TanStack Start, React Router, and Waku) with Encatch page feedback in the footer. *** ## What you'll need [#what-youll-need] * A Fumadocs project * [`@encatch/web-sdk`](https://www.npmjs.com/package/@encatch/web-sdk) * A [publishable SDK key](/docs/settings/security/publishable-sdk-keys) with your docs origin in **Allowed Domains / Packages** * A published **documentation feedback** form in Encatch (combined form with logic jumps for helpful / suggest edit / raise issue) You can install a ready-made form from the [documentation feedback template](https://templates.encatch.com/templates/preview/documentation-frameworks/docs-feedback). *** ## Related [#related] * [Example repository](https://github.com/get-encatch/fumadocs-examples) * [All Encatch example repos](https://github.com/orgs/get-encatch/repositories) * [Documentation platform overview](/integrations/documentation-platforms/fumadocs) on encatch.com # Overview (/docs/integrations/documentation-platforms) Add Encatch page feedback — helpful votes, suggested edits, and issue reports — to popular documentation frameworks. Each guide links to a working example in the [get-encatch GitHub org](https://github.com/orgs/get-encatch/repositories). # Mintlify (/docs/integrations/documentation-platforms/mintlify) Collect page-level feedback on every Mintlify page: helpful votes, suggest an edit, and raise an issue. The fastest way to get started is the working example on GitHub: **[get-encatch/mintlify-examples](https://github.com/get-encatch/mintlify-examples)** That repo is a sample Mintlify docs site with Encatch page feedback in the footer. *** ## What you'll need [#what-youll-need] * A Mintlify project (Node LTS 20 or 22) * A [publishable SDK key](/docs/settings/security/publishable-sdk-keys) with your docs origin in **Allowed Domains / Packages** * A published **documentation feedback** form in Encatch (combined form with logic jumps for helpful / suggest edit / raise issue) You can install a ready-made form from the [documentation feedback template](https://templates.encatch.com/templates/preview/documentation-frameworks/docs-feedback). *** ## Related [#related] * [Example repository](https://github.com/get-encatch/mintlify-examples) * [All Encatch example repos](https://github.com/orgs/get-encatch/repositories) * [Documentation platform overview](/integrations/documentation-platforms/mintlify) on encatch.com # Nextra (/docs/integrations/documentation-platforms/nextra) Collect page-level feedback on every Nextra page: helpful votes, suggest an edit, and raise an issue. The fastest way to get started is the working example on GitHub: **[get-encatch/nextra-examples](https://github.com/get-encatch/nextra-examples)** That repo is a sample Nextra (Next.js) docs site with Encatch page feedback in the footer. *** ## What you'll need [#what-youll-need] * A Nextra project * [`@encatch/web-sdk`](https://www.npmjs.com/package/@encatch/web-sdk) * A [publishable SDK key](/docs/settings/security/publishable-sdk-keys) with your docs origin in **Allowed Domains / Packages** * A published **documentation feedback** form in Encatch (combined form with logic jumps for helpful / suggest edit / raise issue) You can install a ready-made form from the [documentation feedback template](https://templates.encatch.com/templates/preview/documentation-frameworks/docs-feedback). *** ## Related [#related] * [Example repository](https://github.com/get-encatch/nextra-examples) * [All Encatch example repos](https://github.com/orgs/get-encatch/repositories) * [Documentation platform overview](/integrations/documentation-platforms/nextra) on encatch.com # VitePress (/docs/integrations/documentation-platforms/vitepress) Collect page-level feedback on every VitePress page: helpful votes, suggest an edit, and raise an issue. The fastest way to get started is the working example on GitHub: **[get-encatch/vitepress-examples](https://github.com/get-encatch/vitepress-examples)** That repo is a sample VitePress docs site with Encatch page feedback in the footer (Vue 3 theme extension). *** ## What you'll need [#what-youll-need] * A VitePress project * [`@encatch/web-sdk`](https://www.npmjs.com/package/@encatch/web-sdk) * A [publishable SDK key](/docs/settings/security/publishable-sdk-keys) with your docs origin in **Allowed Domains / Packages** * A published **documentation feedback** form in Encatch (combined form with logic jumps for helpful / suggest edit / raise issue) You can install a ready-made form from the [documentation feedback template](https://templates.encatch.com/templates/preview/documentation-frameworks/docs-feedback). *** ## Related [#related] * [Example repository](https://github.com/get-encatch/vitepress-examples) * [All Encatch example repos](https://github.com/orgs/get-encatch/repositories) * [Documentation platform overview](/integrations/documentation-platforms/vitepress) on encatch.com # Advanced Experiments (/docs/feedback-management/advanced-options/advanced-experiments) **Advanced Experiments** controls what percentage of eligible users receive the feedback form. Use it to roll a form out to a portion of the matching audience instead of showing it to everyone at once. ## When to use [#when-to-use] * Gradually rolling a form out to eligible users * Limiting exposure while you validate a new feedback flow * Sampling a large eligible audience * Increasing reach in controlled steps ## Configuration [#configuration] 1. Go to **Distribution → Advanced Options** and locate **Advanced Experiments**. 2. Toggle to **Enabled**. 3. Choose the percentage of eligible users who should receive the form. # API Key Identifier (/docs/feedback-management/advanced-options/api-key-identifier) The **API Key Identifier** option controls which API keys can trigger the feedback form. When multiple environments (e.g. production, staging) or different apps use different keys, the form can be restricted to appear only when a specific key is used. This helps you run different forms in different contexts without creating separate form configurations. ## When to use [#when-to-use] * You have multiple environments (production, staging, development) and want forms to appear only in specific ones * Different apps or integrations use different API keys and you want to target specific ones * You need to ensure a form is only shown when the correct key is used in your SDK integration ## Configuration [#configuration] 1. Go to **Distribution → Advanced Options** and locate **API Key Identifier**. 2. Choose **All** to allow every API key to trigger the form, or **Selected** to restrict it. 3. If **Selected**, use the input field to add the API key identifiers that should trigger this form (e.g. `web-1 Production`). You can add multiple keys. 4. At least one API key identifier is **required** when using Selected mode. API Key Identifier - Select which keys trigger the form # Advanced Options Overview (/docs/feedback-management/advanced-options) The **Advanced Options** tab offers fine-grained control over feedback form behaviour. It allows you to restrict which environments or API keys can trigger a form, define visibility windows, cap submissions, preserve partial responses, and manage exposure over time. Each option can be enabled or disabled independently. Advanced Features - Overview of all available options ## Overview [#overview] Open **Distribution**, then select **Advanced Options**. Eight options are available, each with its own toggle and settings. Most are disabled by default. The page groups settings by where they apply: * **General** — Schedule, Response Limit, Partial Save, Override Feedback Submitted, and Source Tracking. These apply to both **Link & Email** and **In-App** distribution. * **In-App specific** — API Key Identifier, Throttling, and Advanced Experiments. These apply only when the form is displayed inside your application. For an already published form, the **Live form settings** banner warns that saved changes under In-App, Link & Email, or Advanced Options are applied directly to the live form and take effect for end users immediately. ## Available options [#available-options] Use the sidebar or the links below to open the doc for each option: * **[API Key Identifier](/docs/feedback-management/advanced-options/api-key-identifier)** — Restrict the form to specific environments or apps * **[Schedule](/docs/feedback-management/advanced-options/schedule)** — Show the form only during a date range * **[Response Limit](/docs/feedback-management/advanced-options/response-limit)** — Cap total submissions * **[Partial Save](/docs/feedback-management/advanced-options/partial-save)** — Save incomplete responses and optionally auto-complete them * **[Override Feedback Submitted](/docs/feedback-management/advanced-options/override-feedback-submitted)** — Let users edit responses after submission * **[Throttling](/docs/feedback-management/advanced-options/throttling)** — Limit views and responses over time (globally or per user) * **[Advanced Experiments](/docs/feedback-management/advanced-options/advanced-experiments)** — Choose what percentage of eligible users receive the form * **[Source Tracking](/docs/feedback-management/advanced-options/source-tracking)** — Capture UTM tags and click IDs from the page URL with each submission ## Quick reference [#quick-reference] | Feature | Use when you want to… | | ------------------------------- | ----------------------------------------------------------- | | **API Key Identifier** | Restrict the form to specific environments or apps | | **Schedule** | Show the form only during a date range | | **Response Limit** | Cap total submissions | | **Partial Save** | Save incomplete responses and optionally auto-complete them | | **Override Feedback Submitted** | Let users edit responses after submission | | **Throttling** | Limit views and responses over time (globally or per user) | | **Advanced Experiments** | Roll the form out to a percentage of eligible users | | **Source Tracking** | Store UTM and click-ID query parameters with each response | # Override Feedback Submitted (/docs/feedback-management/advanced-options/override-feedback-submitted) **Override Feedback Submitted** allows users to edit their responses after submission. A configurable window determines how long edits are permitted. This can be left empty to allow editing indefinitely. Use this when you want to give respondents the flexibility to correct mistakes or update their feedback. ## When to use [#when-to-use] * Users may need to correct typos or mistakes after submitting * Feedback may change as users continue using your product * You want to improve response quality by allowing post-submission edits * Collecting feedback that may need to be updated (e.g. contact details, preferences) ## Configuration [#configuration] 1. Go to **Distribution → Advanced Options** and locate **Override Feedback Submitted**. 2. Toggle to **Enabled**. 3. Set **Override Window** — enter a number and choose its time unit (for example, **1 day**) to define how long users can edit their responses after submission. 4. Leave this field empty to allow editing indefinitely. Override Feedback Submitted - Let users edit responses after submission # Partial Save (/docs/feedback-management/advanced-options/partial-save) **Partial Save** preserves user progress when the form is not completed. If a user closes the tab or navigates away, their answers are retained. You can optionally configure partial submissions to be automatically marked as complete after a specified duration. This helps reduce drop-off and capture more feedback from users who don't finish in one session. ## When to use [#when-to-use] * Long forms where users may need multiple sessions to complete * Reducing frustration when users accidentally close or navigate away * Capturing partial data that can still be valuable for analysis * Automatically finalizing abandoned responses after a set period ## Configuration [#configuration] 1. Go to **Distribution → Advanced Options** and locate **Partial Save**. 2. Toggle to **Enabled**. 3. (Optional) Set **Auto-Mark as Submitted After** — enter a number of minutes (e.g. 180) after which partial submissions are automatically marked as complete. 4. Leave this field empty to keep partial submissions pending indefinitely. Partial Save - Save progress and optionally auto-mark as complete # Response Limit (/docs/feedback-management/advanced-options/response-limit) **Response Limit** caps the total number of submissions for the form. Once the limit is reached, the form is automatically disabled. This is useful for limited campaigns, beta feedback rounds, or when you want to avoid overflow and ensure a manageable volume of responses. ## When to use [#when-to-use] * Running a beta or pilot program with a fixed number of participants * Limited campaigns where you want to cap responses * Avoiding overflow when you have limited capacity to process feedback * Incentivized surveys where you have a fixed budget or reward pool ## Configuration [#configuration] 1. Go to **Distribution → Advanced Options** and locate **Response Limit**. 2. Toggle to **Enabled**. 3. Enter the **Maximum Responses** value (e.g. 500). 4. The feedback form will be disabled once this number of responses is reached. Response Limit - Set maximum number of responses # Schedule (/docs/feedback-management/advanced-options/schedule) **Schedule** defines a visibility window for the feedback form. The form becomes visible from the start date and is hidden after the end date. This is useful for time-bound campaigns, seasonal surveys, product launches, or when you want to limit feedback collection to a specific period. ## When to use [#when-to-use] * Running a limited-time campaign or survey * Collecting feedback during a product launch or beta period * Seasonal surveys (e.g. end-of-year feedback) * Event-specific feedback (e.g. during a webinar or conference) ## Configuration [#configuration] 1. Go to **Distribution → Advanced Options** and locate **Schedule**. 2. Toggle to **Enabled**. 3. Set **Start Date** — the feedback form will become visible from this date and time (e.g. January 1st, 2026 00:00). 4. Set **End Date** — the feedback form will be hidden after this date and time (e.g. March 31st, 2026 00:00). 5. Use the calendar picker next to each field to choose dates and times. Schedule - Set start and end dates for form visibility # Source Tracking (/docs/feedback-management/advanced-options/source-tracking) **Source tracking** records selected URL query parameters when someone views or submits a feedback form. Use it to tie responses back to marketing campaigns, ad clicks, and referral links—without adding extra questions to the form. Typical parameters include UTM tags (`utm_source`, `utm_medium`, `utm_campaign`) and platform click IDs (`gclid`, `fbclid`, `msclkid`). ## When to use [#when-to-use] * You run paid or email campaigns with UTM parameters on landing pages * You need to know which ad, channel, or campaign drove each response * You want to filter or export responses by `utm_campaign`, `utm_source`, or similar * You use custom query params (e.g. `ref`, `affiliate_id`) and want them stored with submissions ## How it works [#how-it-works] 1. **Configure** which parameter names to capture on the feedback form (**Distribution → Advanced Options**). 2. **Visitor arrives** on a page with query parameters in the URL, e.g. `?utm_source=google&utm_campaign=spring_sale`. 3. **Form is shown** — matching values from the page URL are captured for that form. 4. **Submission** — only the parameters you enabled are stored on the response as key/value pairs. 5. **Reports** — view, filter, and export source data in the admin UI. Only parameters you explicitly enable for that form are saved. If a parameter is configured but missing from the URL, it appears empty (N/A) in results. ## Configuration [#configuration] Source Tracking with suggested and custom parameters 1. Open your feedback form and go to **Distribution → Advanced Options**. 2. Find **Source Tracking** and switch from **Disabled** to **Enabled**. 3. Under **Suggested parameters**, click the tags you want to track (UTM fields, click IDs, etc.). 4. Optionally add **custom parameters** (letters, digits, underscores, hyphens only; max 25 characters per name). 5. Save the form. You must enable at least one parameter for source tracking to take effect. Disabling source tracking clears the parameter list when the form is saved. ### Suggested parameters [#suggested-parameters] | Parameter | Purpose | | -------------- | ----------------------------------------------------------- | | `utm_source` | Site, search engine, or newsletter that sent the traffic | | `utm_medium` | Marketing medium or channel (e.g. `cpc`, `email`, `social`) | | `utm_campaign` | Campaign or promotion name | | `utm_term` | Paid search keywords | | `utm_content` | Differentiates ads or links on the same URL | | `fbclid` | Facebook Ads click ID | | `gclid` | Google Ads click ID | | `gbraid` | Google web-to-app click ID (iOS) | | `wbraid` | Google app-to-web click ID (iOS) | | `msclkid` | Microsoft (Bing) Ads click ID | | `ttclid` | TikTok Ads click ID | | `li_fat_id` | LinkedIn Ads first-party tracking ID | ## Viewing results [#viewing-results] ### Individual responses [#individual-responses] Open **[Individual Responses](/docs/feedback-management/reports-and-export/feedback-dashboard/individual-responses)** and select a submission. When source tracking is enabled for the form: * A **Source Tracking** tab shows configured parameters and their captured values * The response sidebar includes a **Source Tracking** section when data was captured ### Filtering [#filtering] On **Summary Report**, **Audience Overview**, and **Individual Responses**, a **Source Tracking** filter category appears when the form has source tracking enabled with at least one parameter. Filter by conditions such as: * `utm_source` **Equals** `google` * `utm_campaign` **In** `spring_sale`, `product_launch` Supported operators for source tracking filters: **Equals** and **In**. ### Export [#export] When exporting individual responses, include the **Source tracking** column group to export captured parameter values. ## Example [#example] A landing page URL: ``` https://app.example.com/pricing?utm_source=google&utm_medium=cpc&utm_campaign=q2_promo&gclid=abc123 ``` If the form tracks `utm_source`, `utm_medium`, `utm_campaign`, and `gclid`, a submission stores: | Key | Value | | -------------- | ---------- | | `utm_source` | `google` | | `utm_medium` | `cpc` | | `utm_campaign` | `q2_promo` | | `gclid` | `abc123` | Parameters present in the URL but not configured for the form are ignored. Configured parameters missing from the URL are stored as empty for that response. ## Related [#related] * [Advanced Options overview](/docs/feedback-management/advanced-options) * [Individual Responses](/docs/feedback-management/reports-and-export/feedback-dashboard/individual-responses) # Throttling (/docs/feedback-management/advanced-options/throttling) **Throttling** sets limits on how often an in-app form can be shown and how many responses are accepted within a timeframe. It applies to Manual triggers, Auto triggers, or both; shareable-link traffic is not included. Per-user throttling can add separate limits for each user. ## When to use [#when-to-use] * Controlling how often users see the form (e.g. once per week) * Limiting response volume to match your capacity * Preventing a single user from submitting multiple times * Managing exposure across manual and auto-triggered in-app forms ## Configuration [#configuration] 1. Go to **Distribution → Advanced Options** and locate **Throttling**. 2. Toggle to **Enabled**. 3. Choose a **Timeframe** (e.g. Per Week, Per Day, Per Month). 4. Set **Maximum Views** — the upper limit on how many times the form can be shown (e.g. 80,000). 5. Set **Maximum Responses** — the upper limit on submissions (e.g. 1,000). 6. Under **Apply these limits on**, check the boxes that apply: * **Manual** — limits apply to manually triggered forms * **Auto** — limits apply to automatically triggered forms 7. (Optional) Enable **Per-user throttling** to apply additional limits per user: * Choose **Per-user Timeframe** (e.g. Per Week). * Set **Per-user Maximum Views** (e.g. 80). * Set **Per-user Maximum Responses** (e.g. 5). * Apply the per-user limits to **Manual**, **Auto**, or both as needed. Throttling - Set view and response limits Per-user throttling - Apply additional limits per user # Android SDK (/docs/sdk-reference/mobile-sdk/android) The Encatch Android SDK lets you collect in-app feedback and surveys in native Android apps. Display forms as a modal WebView overlay or inline in your layout, identify users, track screens and events, and submit responses to the Encatch backend. *** ## Overview [#overview] * **Package:** [`com.encatch:android`](https://central.sonatype.com/artifact/com.encatch/android) (Maven Central) * **Version:** 0.1.1 * **Platforms:** Android (minSdk 24+) * **Repository:** [github.com/get-encatch/encatch-android](https://github.com/get-encatch/encatch-android) *** ## Installation [#installation] ```kotlin // build.gradle.kts dependencies { implementation("com.encatch:android:0.1.1") } ``` ```groovy // build.gradle dependencies { implementation 'com.encatch:android:0.1.1' } ``` The `com.encatch:android` artifact pulls in `com.encatch:core` (the platform-agnostic business logic — networking, storage, session management) automatically and adds the classic-Views UI: the modal form overlay and the WebView bridge wiring. *** ## Quick Start [#quick-start] ### 1. Initialization [#1-initialization] Install the form UI once in your `Application.onCreate`. `EncatchFormHost.install` tracks the current foreground Activity so modal forms have a host to attach to, and wires foreground retry-queue flushing and completion-CTA handling. ```kotlin import android.app.Application import com.encatch.android.EncatchFormHost class MyApplication : Application() { override fun onCreate() { super.onCreate() EncatchFormHost.install(this) } } ``` Then initialize the SDK. All main SDK entry points are `suspend` functions, so call them from a coroutine — for example `lifecycleScope.launch`: ```kotlin import androidx.lifecycle.lifecycleScope import com.encatch.core.Encatch import kotlinx.coroutines.launch lifecycleScope.launch { Encatch.init("your-api-key") } ``` Without `EncatchFormHost.install(application)`, `showForm` calls that resolve to the modal presentation have no Activity to attach to and nothing will be displayed. Inline forms (see below) attach through `EncatchInlineFormView` instead, but installing the host is still recommended as the fallback presenter. For inline forms, add `EncatchInlineFormView` to your screen layout separately. Pass an optional `EncatchConfig` to customize SDK behavior: ```kotlin import com.encatch.core.Encatch import com.encatch.core.EncatchConfig import com.encatch.core.Theme lifecycleScope.launch { Encatch.init( "your-api-key", EncatchConfig( theme = Theme.SYSTEM, debugMode = true, isFullScreen = false, apiBaseUrl = "https://api.encatch.com", appVersion = "1.2.3", onBeforeShowForm = { payload -> // Return false to prevent the form from showing true }, ), ) } ``` Calling `init` again with a new API key or config reconfigures the SDK in place — useful for switching environments at runtime. ### 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. `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 = mapOf("display_name" to JsonPrimitive("…"))`). ```kotlin lifecycleScope.launch { Encatch.identifyUser("user@example.com") } ``` Trait values in `set` / `setOnce` are `JsonElement`s — wrap primitives with `JsonPrimitive`: ```kotlin import com.encatch.core.UserTraits import kotlinx.serialization.json.JsonPrimitive lifecycleScope.launch { Encatch.identifyUser( "user@example.com", traits = UserTraits( set = mapOf( "name" to JsonPrimitive("Alice"), "plan" to JsonPrimitive("team"), ), ), ) } ``` ```kotlin import com.encatch.core.UserTraits import kotlinx.serialization.json.JsonPrimitive lifecycleScope.launch { Encatch.identifyUser( "user@example.com", traits = UserTraits( set = mapOf( "name" to JsonPrimitive("Alice"), "plan" to JsonPrimitive("team"), ), setOnce = mapOf( "firstSeen" to JsonPrimitive("2026-08-05T12:00:00Z"), ), increment = mapOf("loginCount" to 1.0), decrement = mapOf("credits" to 5.0), unset = listOf("trialEndDate"), ), ) } ``` **User traits** support the following operations: | Operation | Type | Description | | ----------- | --------------------------- | ---------------------------------------------------- | | `set` | `Map?` | Set user attributes (overwrites existing values) | | `setOnce` | `Map?` | Set user attributes only if they don't already exist | | `increment` | `Map?` | Increment numeric user attributes | | `decrement` | `Map?` | Decrement numeric user attributes | | `unset` | `List?` | Remove user attributes | **IdentifyOptions** fields: | Field | Type | Description | | --------- | ---------------- | ----------------------------------------------------------- | | `locale` | `String?` | Preferred language for this user (persisted) | | `country` | `String?` | ISO 3166 country code (persisted) | | `secure` | `SecureOptions?` | Server-generated HMAC signature for verified identification | 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. Pass a server-generated HMAC signature so Encatch can validate the request. `generatedDateTimeInUtc` must be **milliseconds since the Unix epoch** (for example the string form of `System.currentTimeMillis()` 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. ```kotlin import com.encatch.core.IdentifyOptions import com.encatch.core.SecureOptions lifecycleScope.launch { Encatch.identifyUser( "user@example.com", options = IdentifyOptions( secure = SecureOptions( signature = "your-hmac-signature", generatedDateTimeInUtc = "1741867200000", // ms since epoch (2025-03-13T12:00:00Z) ), ), ) } ``` ### 3. Show a form manually [#3-show-a-form-manually] Show a specific form by slug or ID. ```kotlin import com.encatch.core.ResetMode import com.encatch.core.ShowFormOptions lifecycleScope.launch { Encatch.showForm("feedback-form") Encatch.showForm("feedback-form", ShowFormOptions( reset = ResetMode.ALWAYS, )) } ``` | ResetMode | Behavior | | ----------------------- | ------------------------------------------------------ | | `ResetMode.ALWAYS` | Reset pre-fill and response data on every form display | | `ResetMode.ON_COMPLETE` | Reset only after the form is completed | | `ResetMode.NEVER` | Never reset response data | Pass caller context when showing a form. `ContextValue` is a sealed class with `StringValue`, `NumberValue`, `BooleanValue`, and `DateValue` (epoch millis) variants: ```kotlin import com.encatch.core.ContextValue lifecycleScope.launch { Encatch.showForm("feedback-form", ShowFormOptions( reset = ResetMode.ALWAYS, context = mapOf( "plan" to ContextValue.StringValue("team"), "feature" to ContextValue.StringValue("checkout"), "seats" to ContextValue.NumberValue(12.0), "trial" to ContextValue.BooleanValue(false), "signedUpAt" to ContextValue.DateValue(System.currentTimeMillis()), ), )) } ``` ### Other actions [#other-actions] Set the user's preferred language. ```kotlin Encatch.setLocale("fr") ``` Set the user's country. ```kotlin Encatch.setCountry("FR") // ISO 3166 country code ``` Set the theme for forms and surveys. ```kotlin import com.encatch.core.Theme Encatch.setTheme(Theme.DARK) Encatch.setTheme(Theme.LIGHT) Encatch.setTheme(Theme.SYSTEM) // Follows system preference ``` ```kotlin lifecycleScope.launch { Encatch.trackEvent("button_clicked") } ``` ```kotlin lifecycleScope.launch { Encatch.trackScreen("HomeScreen") } ``` Call `trackScreen` from each Activity's `onResume`, a Fragment's `onResume`, or your navigation library's destination-changed listener — for example with Jetpack Navigation: ```kotlin navController.addOnDestinationChangedListener { _, destination, _ -> lifecycleScope.launch { Encatch.trackScreen(destination.route ?: destination.label?.toString() ?: "unknown") } } ``` Subscribe to form lifecycle events. Returns an unsubscribe function. ```kotlin val unsubscribe = Encatch.on { eventType, payload -> Log.d("Encatch", "Event: ${eventType.wireValue}, payload: ${payload.data}") } // Later, to unsubscribe: unsubscribe() ``` Callbacks may fire on any thread — hop to the main thread (`runOnUiThread`, `Dispatchers.Main`) before touching UI. | Event | Description | | -------------------------------- | --------------------------------------------------------------------- | | `EventType.FORM_SHOW` | Fired when a form is displayed | | `EventType.FORM_STARTED` | Fired when a user starts interacting | | `EventType.FORM_SUBMIT` | Fired when a form is submitted | | `EventType.FORM_COMPLETE` | Fired when a form is fully completed | | `EventType.FORM_CLOSE` | Fired when a form is closed | | `EventType.FORM_DISMISSED` | Fired when a form is dismissed without completion | | `EventType.FORM_ERROR` | Fired when an error occurs | | `EventType.FORM_SECTION_CHANGE` | Fired when the visible section changes | | `EventType.FORM_ANSWERED` | Fired when a question is answered | | `EventType.FORM_REMIND_ME_LATER` | Fired when the user taps "Remind me later" | | `EventType.FORM_CTA_TRIGGERED` | Fired when a completion CTA is triggered on thank-you or exit screens | Handle completion CTAs (in-app navigation, internal redirect, or external browser) via `FORM_CTA_TRIGGERED`. Configure actions in the form builder — see [Call to action](/docs/feedback-management/form-builder/call-to-action). The SDK closes the form overlay after emitting the event — your app handles in-app navigation: ```kotlin import com.encatch.core.EventType import kotlinx.serialization.json.jsonPrimitive import kotlinx.serialization.json.contentOrNull Encatch.on { eventType, payload -> if (eventType != EventType.FORM_CTA_TRIGGERED) return@on val action = payload.data?.get("action")?.jsonPrimitive?.contentOrNull if (action != "app_navigate") return@on val route = payload.data?.get("route")?.jsonPrimitive?.contentOrNull // Map route strings to your app's navigation paths if (route == "billing" || route == "billing/upgrade") { runOnUiThread { navController.navigate("billing") } } } ``` For in-app navigation, the SDK closes the form overlay after emitting the event and expects your app to perform navigation. For URL redirect actions, the SDK opens the URL (Custom Tabs or an external browser intent) and closes the form automatically. Pre-fill a form response before showing a form. `questionId` may be a question UUID or a question slug. ```kotlin Encatch.addToResponse("question_id", "pre-filled value") Encatch.addToResponse("choice_question_id", listOf("option-a", "option-b")) lifecycleScope.launch { Encatch.showForm("your-form-slug") } ``` Dismiss the currently displayed form. ```kotlin lifecycleScope.launch { Encatch.dismissForm() // Or dismiss a specific form configuration: Encatch.dismissForm(formConfigurationId = "config-id") } ``` Use `onBeforeShowForm` in `EncatchConfig` to conditionally block forms from showing. The interceptor is a `suspend` lambda, so you can await your own logic inside it. ```kotlin import com.encatch.core.TriggerType lifecycleScope.launch { Encatch.init( "your-api-key", EncatchConfig( onBeforeShowForm = { payload -> // Inspect payload.formId, payload.formConfig, payload.triggerType, etc. if (payload.triggerType == TriggerType.AUTOMATIC && someCondition) { false // Block this form } else { true // Allow } }, ), ) } ``` `identifyUser` starts a session automatically once the backend confirms the identity. You can also control the session lifecycle manually: ```kotlin import com.encatch.core.StartSessionOptions lifecycleScope.launch { Encatch.startSession() // Skip the immediate ping or screen re-track on start: Encatch.startSession( StartSessionOptions( skipImmediatePing = true, skipImmediateTrackScreen = true, ), ) } ``` ```kotlin // Temporarily stop the 30-second background ping (not persisted) Encatch.pauseSession() // Resume the ping interval after pauseSession() Encatch.resumeSession() ``` ```kotlin // Fully suspend SDK activity — stops ping and dismisses open forms. // Persists across app restarts. Re-enable with startSession(). lifecycleScope.launch { Encatch.stopSession() } ``` 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. ```kotlin lifecycleScope.launch { Encatch.resetUser() } ``` Wipes **all** persisted SDK data and resets in-memory state. Stronger than `resetUser()` — also clears session-stopped state and device preferences. Note that on Android `clearAll()` de-initializes the SDK entirely — call `init` (and then `identifyUser`) again afterward. ```kotlin lifecycleScope.launch { Encatch.clearAll() } ``` 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. The offline retry queue is flushed automatically when the app returns to the foreground (via `ProcessLifecycleOwner`, wired by `EncatchFormHost.install`). *** ### Inline Forms [#inline-forms] Inline forms are a way to show Encatch in-app feedback without a modal — the survey renders directly in your layout instead of as a full-screen overlay. `EncatchInlineFormView` renders a form directly inside your view hierarchy instead of as a modal overlay. Place it anywhere — in a `LinearLayout`, `ScrollView`, `RecyclerView` item, or a Compose `AndroidView`. **XML:** ```xml ``` ```kotlin findViewById(R.id.inlineForm).formId = "your-form-slug" // exact match; leave null for wildcard ``` **Or programmatically:** ```kotlin val inlineForm = EncatchInlineFormView(context).apply { formId = "your-form-slug" } container.addView(inlineForm) ``` Then trigger the form from anywhere: ```kotlin lifecycleScope.launch { Encatch.showForm("your-form-slug") } ``` When `showForm` is called, the SDK resolves the presenter in this order: 1. **Exact match** — first attached `EncatchInlineFormView` whose `formId` matches the payload wins. 2. **Wildcard** — first attached `EncatchInlineFormView` with `formId = null` catches anything not exact-matched. 3. **Modal fallback** — the modal dialog (hosted by `EncatchFormHost`) shows the form as the default overlay when no inline slot is registered or none match. Slot registration is tied to the view's attach/detach lifecycle: the slot registers in `onAttachedToWindow` and unregisters in `onDetachedFromWindow`. If your UI keeps off-screen pages attached (e.g. `ViewPager` with page retention), a wildcard slot on a hidden page can intercept a `showForm` meant for the visible one — detach the view while backgrounded, or give it an exact `formId` no other screen uses. In Jetpack Compose, wrap the view in `AndroidView`: ```kotlin import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.ui.Modifier import androidx.compose.ui.viewinterop.AndroidView import com.encatch.android.EncatchInlineFormView @Composable fun FeedbackSlot() { AndroidView( modifier = Modifier.fillMaxWidth(), factory = { context -> EncatchInlineFormView(context).apply { formId = "your-form-slug" } }, ) } ``` Because Compose disposes the underlying view when the composable leaves composition, slot registration follows your navigation naturally — an inline slot on a screen that is no longer composed will not intercept `showForm` calls. The WebView's internal scroll is disabled. The host `ScrollView` (or `NestedScrollView`) provides scrolling. The view height grows automatically via `form:resize` messages from the web form; before the first resize a 300dp loading skeleton is shown, which crossfades away once the form is ready. The host app controls keyboard avoidance — use `android:windowSoftInputMode="adjustResize"` (with edge-to-edge inset handling on API 30+) so content slides above the keyboard. When an in-form overlay opens (QnA with AI, Scheduler), the view freezes its height and reports the change through `onOverlayOpenChange`: ```kotlin inlineForm.onOverlayOpenChange = { open -> // e.g. lock host scrolling while the overlay is open } ``` | Property | Type | Default | Description | | --------------------- | ---------------------- | ------- | ------------------------------------------------------- | | `formId` | `String?` | `null` | Exact form slug/id to match. `null` = wildcard. | | `minHeight` | `Int` | `0` | Minimum height floor in px applied after `form:resize`. | | `onOverlayOpenChange` | `((Boolean) -> Unit)?` | `null` | Called when a QnA/Scheduler overlay opens or closes. | ### 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 Android views or composables and submit responses through the SDK. That keeps typography, spacing, colors, and interaction patterns aligned with the rest of your app, so the survey feels like a native screen rather than an embedded web page. The flow has three parts: intercept the form, render your own UI, then submit through the SDK. **1. Intercept the form.** Set `onBeforeShowForm` in `EncatchConfig` and return `false` to suppress the SDK's WebView. The payload carries everything you need to render natively — `payload.formConfig.feedbackConfigurationId` (required for submission) and `payload.formConfig.questionnaireFields` (the question definitions): ```kotlin import com.encatch.core.ShowFormResponse var pendingNativeForm: ShowFormResponse? = null lifecycleScope.launch { Encatch.init( "your-api-key", EncatchConfig( onBeforeShowForm = { payload -> pendingNativeForm = payload.formConfig // Hand off to your own UI (e.g. post to a StateFlow your screen observes) false // Suppress the SDK's WebView form }, ), ) } ``` **2. Emit lifecycle events (optional).** The WebView normally reports lifecycle events; with a native UI you emit them yourself so dashboards and `Encatch.on` listeners stay accurate: ```kotlin import com.encatch.core.EventPayload import com.encatch.core.EventType val configId = formConfig.feedbackConfigurationId Encatch.emitEvent(EventType.FORM_SHOW, EventPayload(formId = configId, timestamp = 0)) // ... later, as the user interacts: Encatch.emitEvent(EventType.FORM_STARTED, EventPayload(formId = configId, timestamp = 0)) ``` (`emitEvent` stamps the current timestamp for you.) **3. Build and submit the response.** Collect answers from your UI as `NativeFormResponse` entries (`questionId`, question `type` wire value, and the value), then convert them with `buildSubmitRequest` and send with `Encatch.submitForm`: ```kotlin import com.encatch.core.BuildSubmitRequestOptions import com.encatch.core.NativeFormResponse import com.encatch.core.buildSubmitRequest lifecycleScope.launch { val responses = listOf( NativeFormResponse("q1", "rating", 5), NativeFormResponse("q2", "short_answer", "Great product!"), NativeFormResponse("q3", "multiple_choice_multiple", listOf("option-a", "option-b")), NativeFormResponse("q4", "yes_no", true), ) val request = buildSubmitRequest( BuildSubmitRequestOptions( formConfigurationId = formConfig.feedbackConfigurationId, completionTimeInSeconds = 42, ), responses, ) Encatch.submitForm(request) Encatch.emitEvent( EventType.FORM_COMPLETE, EventPayload(formId = formConfig.feedbackConfigurationId, timestamp = 0), ) } ``` `buildSubmitRequest` maps every supported question type (rating, NPS, CSAT, opinion scale, text types, choice types, ranking, yes/no, consent, date, matrix types, and structured types like signature, file upload, phone number, address, video/audio, scheduler, QnA with AI, and UPI payments) to the wire format the backend expects. Numeric scale values are rounded to integers; unknown types fall back to `short_answer` for forward-compatibility. The `value` passed to `NativeFormResponse` depends on the question type: numbers for scales (`rating`, `nps`, `csat`, `opinion_scale`), strings for text types, `String` or `List` for choice/ranking types, `Boolean` for `yes_no`/`consent`, `Map` for matrix types, and the matching Kotlin data class (`SignatureAnswer`, `PhoneNumberAnswer`, `AddressAnswer`, etc.) for structured types. *** All entry points live on the `com.encatch.core.Encatch` singleton. Methods marked `suspend` must be called from a coroutine. | Method | Description | | ------------------------------------------------- | --------------------------------------------------- | | `suspend init(apiKey, config)` | Initialize (or reconfigure) the SDK | | `suspend identifyUser(userName, traits, options)` | Identify a user | | `setLocale(locale)` | Set locale | | `setCountry(country)` | Set country (ISO 3166) | | `setTheme(theme)` | Set form theme | | `suspend trackEvent(eventName)` | Track a custom event | | `suspend trackScreen(screenName)` | Track screen navigation | | `suspend showForm(formId, options)` | Show a form (inline or modal) | | `suspend dismissForm(formConfigurationId)` | Dismiss the current form | | `addToResponse(questionId, value)` | Pre-fill a question answer | | `suspend startSession(options)` | Start a new session | | `pauseSession()` | Pause background ping | | `resumeSession()` | Resume background ping | | `suspend stopSession()` | Suspend SDK activity | | `suspend resetUser()` | Reset user identity | | `suspend clearAll()` | Wipe all persisted SDK data | | `on(callback)` | Subscribe to lifecycle events (returns unsubscribe) | | `off(callback)` | Unsubscribe from events | | `emitEvent(eventType, payload)` | Emit a lifecycle event (custom native forms) | | `suspend submitForm(params)` | Submit a custom native form | | `flushRetryQueue()` | Flush the offline retry queue | | `stop()` | Stop the background ping loop | | `isInitialized` | Whether `init` has completed (read-only property) | Add permissions to your `AndroidManifest.xml`: ```xml ``` `INTERNET` is required for API calls and the form WebView. The other three permissions are required when forms include video/audio capture questions (`video_audio`). The SDK grants WebView media permission requests automatically and, since 0.1.1, shows the runtime permission prompt itself when it's needed — for recording questions and for the camera option in file-upload questions. You can still pre-request the permissions yourself for a smoother first-run experience: ```kotlin import android.Manifest import androidx.activity.result.contract.ActivityResultContracts private val mediaPermissionLauncher = registerForActivityResult( ActivityResultContracts.RequestMultiplePermissions() ) { grants -> if (grants[Manifest.permission.CAMERA] != true || grants[Manifest.permission.RECORD_AUDIO] != true ) { // Handle denied permissions — recording questions will not work } } fun requestEncatchMediaPermissions() { mediaPermissionLauncher.launch( arrayOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO) ) } ``` ## Support [#support] * **Maven Central:** [com.encatch:android](https://central.sonatype.com/artifact/com.encatch/android) * **Issues:** [github.com/get-encatch/encatch-android/issues](https://github.com/get-encatch/encatch-android/issues) # Compose Multiplatform SDK (/docs/sdk-reference/mobile-sdk/compose-multiplatform) The Encatch Compose Multiplatform SDK (`com.encatch:compose-sdk`) lets you collect in-app feedback and surveys from one shared `commonMain` Compose UI targeting Android and iOS. It depends on the [Kotlin Multiplatform SDK](./kotlin-multiplatform) (`com.encatch:kmp-sdk`) for the entire `Encatch` business-logic API — init, identify, track, show/dismiss forms, submit, sessions, events — and adds the one thing a pure KMP consumer wouldn't need: `EncatchInlineForm`, a composable that wraps the platform-native inline form view (`AndroidView`/`UIKitView` interop — no WebView reimplementation, no third-party dependency). Under the hood, `Encatch` calls bridge to the two native Encatch SDKs (the [Android SDK](./android) on Android, the pure-Swift [iOS SDK](./ios) on iOS) — a thin routing layer, not a third implementation. The modal form host installs itself: on iOS when you call `Encatch.init(...)`, on Android the first time `EncatchInlineForm` composes (via Compose's `LocalContext`). There is no `Application.onCreate` setup and no `EncatchFormHost.install()` call to make. *** ## Overview [#overview] * **Package:** `com.encatch:compose-sdk` (Maven Central) * **Version:** 0.1.1 * **Platforms:** Android (minSdk 24), iOS (`iosArm64`, `iosSimulatorArm64`) * **Repository:** [github.com/get-encatch/encatch-android](https://github.com/get-encatch/encatch-android) * **License:** MIT *** ## Installation [#installation] Add the dependency to your shared module's `commonMain` source set: ```kotlin // build.gradle.kts (shared module) kotlin { sourceSets { commonMain.dependencies { implementation("com.encatch:compose-sdk:0.1.1") } } } ``` This transitively brings in `com.encatch:kmp-sdk`'s `Encatch` API — no separate dependency needed. A Compose Multiplatform customer adds only `compose-sdk`. On Android the modal form host installs lazily the first time `EncatchInlineForm` composes. If your app **only uses modal forms and never composes `EncatchInlineForm`**, install the host eagerly in `Application.onCreate` instead: `com.encatch.android.EncatchFormHost.install(this)` (see the [KMP SDK setup notes](./kotlin-multiplatform#platform-setup)). On iOS the host always installs inside `Encatch.init(...)`, so nothing is needed either way. *** ## Quick Start [#quick-start] ### 1. Initialization [#1-initialization] Call `Encatch.init` once at app startup — a `LaunchedEffect` at your root composable is a natural place. It's a `suspend` function; subsequent calls (`identifyUser`, `showForm`, tracking) silently no-op until initialization completes. ```kotlin import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import com.encatch.sdk.Encatch @Composable fun App() { LaunchedEffect(Unit) { if (!Encatch.isInitialized) { Encatch.init("your-api-key") } } // ... your app UI ... } ``` Pass an optional `EncatchConfig` to customize SDK behavior: ```kotlin import com.encatch.sdk.Encatch import com.encatch.sdk.EncatchConfig import com.encatch.sdk.Theme LaunchedEffect(Unit) { Encatch.init( "your-api-key", EncatchConfig( theme = Theme.SYSTEM, debugMode = true, isFullScreen = false, appVersion = "1.2.3", onBeforeShowForm = { payload -> // Return false to prevent the form from showing true }, ), ) } ``` ### 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. `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 = mapOf("display_name" to JsonPrimitive("…"))`). ```kotlin val scope = rememberCoroutineScope() Button(onClick = { scope.launch { Encatch.identifyUser("user@example.com") } }) { Text("Sign in") } ``` Trait values are `kotlinx.serialization` `JsonElement`s — use `JsonPrimitive` for strings, numbers, and booleans: ```kotlin import com.encatch.sdk.UserTraits import kotlinx.serialization.json.JsonPrimitive scope.launch { Encatch.identifyUser( "user@example.com", traits = UserTraits( set = mapOf( "name" to JsonPrimitive("Alice"), "plan" to JsonPrimitive("team"), ), ), ) } ``` ```kotlin import com.encatch.sdk.UserTraits import kotlinx.serialization.json.JsonPrimitive scope.launch { Encatch.identifyUser( "user@example.com", traits = UserTraits( set = mapOf("name" to JsonPrimitive("Alice"), "plan" to JsonPrimitive("team")), setOnce = mapOf("firstSeen" to JsonPrimitive("2026-08-05T12:00:00Z")), increment = mapOf("loginCount" to 1.0), decrement = mapOf("credits" to 5.0), unset = listOf("trialEndDate"), ), ) } ``` **User traits** support the following operations: | Operation | Type | Description | | ----------- | --------------------------- | ---------------------------------------------------- | | `set` | `Map?` | Set user attributes (overwrites existing values) | | `setOnce` | `Map?` | Set user attributes only if they don't already exist | | `increment` | `Map?` | Increment numeric user attributes | | `decrement` | `Map?` | Decrement numeric user attributes | | `unset` | `List?` | Remove user attributes | 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. Pass a server-generated HMAC signature so Encatch can validate the request. `generatedDateTimeInUtc` must be **milliseconds since the Unix epoch** (the string form of your server's epoch-millis timestamp). 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. ```kotlin import com.encatch.sdk.IdentifyOptions import com.encatch.sdk.SecureOptions scope.launch { Encatch.identifyUser( "user@example.com", options = IdentifyOptions( secure = SecureOptions( signature = "your-hmac-signature", generatedDateTimeInUtc = "1741867200000", // ms since epoch (2025-03-13T12:00:00Z) ), ), ) } ``` ### 3. Show a form manually [#3-show-a-form-manually] Show a specific form by slug or ID. If a matching `EncatchInlineForm` is composed, the form renders inline there; otherwise it presents as a modal overlay. ```kotlin import androidx.compose.runtime.rememberCoroutineScope import com.encatch.sdk.Encatch import kotlinx.coroutines.launch @Composable fun FeedbackButton() { val scope = rememberCoroutineScope() Button(onClick = { scope.launch { Encatch.showForm("feedback-form") } }) { Text("Give feedback") } } ``` | ResetMode | Behavior | | ----------------------- | ------------------------------------------------------ | | `ResetMode.ALWAYS` | Reset pre-fill and response data on every form display | | `ResetMode.ON_COMPLETE` | Reset only after the form is completed | | `ResetMode.NEVER` | Never reset response data | Pass caller context when showing a form. Context values use the `ContextValue` sealed class (`StringValue`, `NumberValue`, `BooleanValue`, `DateValue`): ```kotlin import com.encatch.sdk.ContextValue import com.encatch.sdk.ResetMode import com.encatch.sdk.ShowFormOptions scope.launch { Encatch.showForm( "feedback-form", ShowFormOptions( reset = ResetMode.ALWAYS, context = mapOf( "plan" to ContextValue.StringValue("team"), "feature" to ContextValue.StringValue("checkout"), ), ), ) } ``` ### Other actions [#other-actions] Set the user's preferred language. ```kotlin Encatch.setLocale("fr") ``` Set the user's country. ```kotlin Encatch.setCountry("FR") // ISO 3166 country code ``` Set the theme for forms and surveys. ```kotlin import com.encatch.sdk.Theme Encatch.setTheme(Theme.DARK) Encatch.setTheme(Theme.LIGHT) Encatch.setTheme(Theme.SYSTEM) // Follows system preference ``` ```kotlin scope.launch { Encatch.trackEvent("button_clicked") } ``` Track screens as your navigation state changes — a `LaunchedEffect` per screen composable works well: ```kotlin @Composable fun HomeScreen() { LaunchedEffect(Unit) { Encatch.trackScreen("Home") } // ... } ``` Subscribe to form lifecycle events. `on` returns an unsubscribe function — there is no separate `off` in this API; call the returned function instead. In Compose, pair the subscription with a `DisposableEffect` so it unregisters with the composition: ```kotlin import androidx.compose.runtime.DisposableEffect import com.encatch.sdk.Encatch @Composable fun App() { DisposableEffect(Unit) { val unsubscribe = Encatch.on { eventType, payload -> println("Event: ${eventType.wireValue}, formId: ${payload.formId}") } onDispose { unsubscribe() } } // ... } ``` | Event | Description | | -------------------------------- | --------------------------------------------------------------------- | | `EventType.FORM_SHOW` | Fired when a form is displayed | | `EventType.FORM_STARTED` | Fired when a user starts interacting | | `EventType.FORM_SUBMIT` | Fired when a form is submitted | | `EventType.FORM_COMPLETE` | Fired when a form is fully completed | | `EventType.FORM_CLOSE` | Fired when a form is closed | | `EventType.FORM_DISMISSED` | Fired when a form is dismissed without completion | | `EventType.FORM_ERROR` | Fired when an error occurs | | `EventType.FORM_SECTION_CHANGE` | Fired when the visible section changes | | `EventType.FORM_ANSWERED` | Fired when a question is answered | | `EventType.FORM_REMIND_ME_LATER` | Fired when the user taps "Remind me later" | | `EventType.FORM_CTA_TRIGGERED` | Fired when a completion CTA is triggered on thank-you or exit screens | Handle completion CTAs (in-app navigation, internal redirect, or external browser) via `FORM_CTA_TRIGGERED`. Configure actions in the form builder — see [Call to action](/docs/feedback-management/form-builder/call-to-action). The SDK closes the form overlay after emitting the event — your app handles in-app navigation. Event payload data is a `Map`: ```kotlin import com.encatch.sdk.EventType import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.contentOrNull DisposableEffect(Unit) { val unsubscribe = Encatch.on { eventType, payload -> if (eventType == EventType.FORM_CTA_TRIGGERED) { val action = (payload.data?.get("action") as? JsonPrimitive)?.contentOrNull val route = (payload.data?.get("route") as? JsonPrimitive)?.contentOrNull if (action == "app_navigate") { // Map route strings to your app's navigation state when (route) { "billing", "billing/upgrade" -> currentScreen = Screen.Billing } } } } onDispose { unsubscribe() } } ``` For in-app navigation, the SDK closes the form overlay 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. Pre-fill a form response before showing a form. `questionId` may be a question UUID or a question slug. ```kotlin scope.launch { Encatch.addToResponse("question_id", "pre-filled value") Encatch.addToResponse("choice_question_id", listOf("option-a", "option-b")) Encatch.showForm("your-form-slug") } ``` Inspect or clear pending pre-fills with `Encatch.getPendingResponses()` / `Encatch.clearPendingResponses()`. Dismiss the currently displayed form. ```kotlin scope.launch { Encatch.dismissForm() // Or dismiss a specific form configuration: Encatch.dismissForm(formConfigurationId = "config-id") } ``` Use `onBeforeShowForm` in `EncatchConfig` to conditionally block forms from showing. The interceptor is a `suspend` lambda, so it may await anything — user input, a coroutine, a network check — before answering. ```kotlin import com.encatch.sdk.EncatchConfig import com.encatch.sdk.TriggerType Encatch.init( "your-api-key", EncatchConfig( onBeforeShowForm = { payload -> // Inspect payload.formId, payload.triggerType, payload.formConfigJson, etc. if (payload.triggerType == TriggerType.AUTOMATIC && someCondition) { false // Block this form } else { true // Allow } }, ), ) ``` Register a debug hook that receives every completed SDK HTTP call (request + response). Only fires when `EncatchConfig.debugMode` is enabled; the API key header is always masked to its last 5 characters. Assignment-style (last caller wins) and survives re-`init()` — set it once at app startup for in-app network inspectors. ```kotlin Encatch.setOnNetworkLog { entry -> println("${entry.method} ${entry.endpoint} -> ${entry.status} in ${entry.durationMs}ms") } // Pass null to clear: Encatch.setOnNetworkLog(null) ``` Control session lifecycle manually: ```kotlin import com.encatch.sdk.StartSessionOptions scope.launch { Encatch.startSession() // Skip the immediate ping or screen re-track on start: Encatch.startSession( StartSessionOptions( skipImmediatePing = true, skipImmediateTrackScreen = true, ), ) } ``` ```kotlin // Temporarily stop the 30-second background ping (not persisted) Encatch.pauseSession() // Resume the ping interval after pauseSession() Encatch.resumeSession() ``` ```kotlin // Fully suspend SDK activity — stops ping and dismisses open forms. // Persists across app restarts. Re-enable with startSession(). scope.launch { Encatch.stopSession() } ``` 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. ```kotlin scope.launch { Encatch.resetUser() } ``` Wipes **all** persisted SDK data and resets in-memory state. Stronger than `resetUser()` — also clears session-stopped state and device preferences. The SDK remains initialized; call `identifyUser` afterward. ```kotlin scope.launch { Encatch.clearAll() } ``` 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. *** ### Inline Forms [#inline-forms] Inline forms are a way to show Encatch in-app feedback without a modal — the survey renders directly in your layout instead of as a full-screen overlay. `EncatchInlineForm` renders a form directly inside your composition — no modal, no overlay. Place it anywhere in a Compose Multiplatform layout: a `Column`, a `verticalScroll` container, a `Card`, etc. It works identically on Android and iOS from `commonMain`. ```kotlin import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import com.encatch.sdk.Encatch import com.encatch.sdk.compose.EncatchInlineForm @Composable fun FeedbackScreen() { val scope = rememberCoroutineScope() Column(Modifier.verticalScroll(rememberScrollState())) { // ... content above ... Button(onClick = { scope.launch { Encatch.showForm("your-form-slug") } }) { Text("Show form (renders inline below)") } EncatchInlineForm( formId = "your-form-slug", // exact match; omit for wildcard modifier = Modifier.fillMaxWidth(), ) // ... content below ... } } ``` Calling `Encatch.showForm("your-form-slug")` from anywhere in the app then renders the form inside this slot instead of as a modal. When `showForm` is called, the SDK resolves the presenter in this order: 1. **Exact match** — an `EncatchInlineForm` whose `formId` matches the payload wins. 2. **Wildcard** — an `EncatchInlineForm` with `formId = null` (the default) catches anything not exact-matched. 3. **Modal fallback** — the modal overlay shows the form when no inline slot is composed or none match. ```kotlin // Exact slot — only showForm("nps-survey") renders here: EncatchInlineForm(formId = "nps-survey", modifier = Modifier.fillMaxWidth()) // Wildcard slot — catches any form id not exactly claimed elsewhere: EncatchInlineForm(modifier = Modifier.fillMaxWidth()) ``` No fixed height is required — the underlying native view self-sizes (a skeleton placeholder first, then live `form:resize` values from the web form) on both platforms. Give it a width and let the height follow: ```kotlin Column(Modifier.verticalScroll(rememberScrollState())) { EncatchInlineForm( formId = "my-form", modifier = Modifier .fillMaxWidth() .clip(RoundedCornerShape(16.dp)), ) } ``` The host layout provides scrolling and keyboard avoidance — use your scroll container plus `Modifier.imePadding()` as you would for any other content. | Prop | Type | Default | Description | | ---------- | ---------- | ---------- | ------------------------------------------------------------ | | `formId` | `String?` | `null` | Exact form slug/id to match. `null` = wildcard. | | `modifier` | `Modifier` | `Modifier` | Standard Compose modifier for width, clipping, padding, etc. | ### 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 composables and submit responses through the SDK. That keeps typography, spacing, colors, and interaction patterns aligned with the rest of your app, so the survey feels like a native screen rather than an embedded web page. The flow has three parts, all available from `commonMain`: 1. **Intercept** the form with `onBeforeShowForm` and return `false`. The `ShowFormInterceptorPayload` includes `formConfigJson` — the JSON encoding of the full form configuration (including `questionnaireFields`), so you can render your own UI from the real form definition. 2. **Render** your own Compose UI from the payload. 3. **Submit** with `buildSubmitRequest` + `Encatch.submitForm`. ```kotlin import com.encatch.sdk.BuildSubmitRequestOptions import com.encatch.sdk.Encatch import com.encatch.sdk.EncatchConfig import com.encatch.sdk.NativeFormResponse import com.encatch.sdk.buildSubmitRequest // 1. Intercept: queue the blocked form as Compose state instead of letting the SDK render it var blockedForm by mutableStateOf(null) suspend fun initSdk() { Encatch.init( "your-api-key", EncatchConfig( onBeforeShowForm = { payload -> if (payload.formId == "my-native-form") { blockedForm = BlockedForm(payload.formId, payload.formConfigJson) false // block the SDK form — we render our own composable } else { true } }, ), ) } // 2. Render: show your own composable when blockedForm != null // (parse formConfigJson to build the question list) // 3. Submit: convert your composable's answers and post them to Encatch suspend fun submitNativeForm(formConfigurationId: String) { val responses = listOf( NativeFormResponse("q1", "rating", 5), NativeFormResponse("q2", "short_answer", "Great product!"), NativeFormResponse("q3", "multiple_choice_multiple", listOf("option-a", "option-b")), ) val requestJson = buildSubmitRequest( BuildSubmitRequestOptions(formConfigurationId = formConfigurationId), responses, ) Encatch.submitForm(requestJson) } ``` `NativeFormResponse.value`'s expected shape depends on the question `type`: numeric scales (`rating`, `nps`, `csat`, `opinion_scale`) take a `Number` or numeric `String`; text types take `String`; choice and ranking types take `String` or `List`; boolean types (`yes_no`, `consent`) take `Boolean`. All 33 Encatch question types are supported; unknown types fall back to `short_answer` for forward-compatibility. *** Everything from the [Kotlin Multiplatform SDK](./kotlin-multiplatform) is available unchanged, plus one composable: | Member | Description | | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------- | | `EncatchInlineForm(formId, modifier)` | Composable inline form slot (`formId = null` for wildcard) | | `Encatch.init(apiKey, config)` | Initialize the SDK (suspend) | | `Encatch.identifyUser(userName, traits, options)` | Identify a user (suspend) | | `Encatch.showForm(formId, options)` | Show a form (inline or modal) (suspend) | | `Encatch.dismissForm(formConfigurationId)` | Dismiss the current form (suspend) | | `Encatch.trackEvent(eventName)` / `trackScreen(screenName)` | Track events and screens (suspend) | | `Encatch.setLocale(locale)` / `setCountry(country)` / `setTheme(theme)` | Preferences | | `Encatch.addToResponse(questionId, value)` | Pre-fill a question answer | | `Encatch.submitForm(requestJson)` | Submit a custom native form (suspend) | | `Encatch.startSession(options)` / `stopSession()` / `pauseSession()` / `resumeSession()` | Session control | | `Encatch.resetUser()` / `clearAll()` | Identity reset / full data wipe (suspend) | | `Encatch.on(callback)` | Subscribe to lifecycle events; returns unsubscribe function | | `Encatch.emitEvent(eventType, payload)` | Emit an event to listeners | | `Encatch.setOnNetworkLog(callback)` | Debug hook for SDK HTTP calls (debugMode only) | See the [KMP SDK API quick reference](./kotlin-multiplatform) for the complete member list and read-only getters. * [Kotlin Multiplatform SDK](./kotlin-multiplatform) — the `Encatch` business-logic API this module builds on; use it directly if you don't need Compose UI. * [Android SDK](./android) — the native Android SDK this module bridges to on Android. * [iOS SDK](./ios) — the native Swift SDK this module bridges to on iOS. ## Support [#support] * **Maven Central:** `com.encatch:compose-sdk` * **Issues:** [github.com/get-encatch/encatch-android/issues](https://github.com/get-encatch/encatch-android/issues) # Flutter SDK (/docs/sdk-reference/mobile-sdk/flutter) The Encatch Flutter SDK lets you collect in-app feedback and surveys in Flutter apps. Display forms as a modal WebView overlay or inline in your layout, identify users, track screens and events, and submit responses to the Encatch backend. *** ## Overview [#overview] * **Package:** [`encatch_flutter`](https://pub.dev/packages/encatch_flutter) * **Version:** 1.1.2 * **Platforms:** Android, iOS * **Repository:** [github.com/get-encatch/flutter-sdk](https://github.com/get-encatch/flutter-sdk) *** ## Installation [#installation] ```bash flutter pub add encatch_flutter ``` ```yaml dependencies: encatch_flutter: ^1.1.2 ``` *** ## Quick Start [#quick-start] ### 1. Initialization [#1-initialization] Wrap your app's root widget with `EncatchProvider` to initialize the SDK, start a session, and mount the headless `EncatchWebView` listener for modal forms. No navigator key or extra WebView widget is required. ```dart import 'package:encatch_flutter/encatch_flutter.dart'; void main() { runApp( EncatchProvider( apiKey: 'your-api-key', child: MyApp(), ), ); } ``` For inline forms, mount `EncatchInlineForm` in your screen widget tree separately. Pass an optional `EncatchConfig` to customize SDK behavior: ```dart EncatchProvider( apiKey: 'your-api-key', config: EncatchConfig( theme: EncatchTheme.system, debugMode: true, isFullScreen: false, apiBaseUrl: 'https://app.encatch.com', appVersion: '1.2.3', onBeforeShowForm: (payload) async { // Return false to prevent form from showing return true; }, ), child: MyApp(), ) ``` ### 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. `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': '…'}`). ```dart await Encatch.identifyUser('user@example.com'); ``` ```dart await Encatch.identifyUser( 'user@example.com', traits: UserTraits( set: {'name': 'Alice', 'plan': 'team'}, ), ); ``` ```dart await Encatch.identifyUser( 'user@example.com', traits: UserTraits( set: {'name': 'Alice', 'plan': 'team'}, setOnce: {'firstSeen': DateTime.now()}, increment: {'loginCount': 1}, decrement: {'credits': 5}, unset: ['trialEndDate'], ), ); ``` **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 | 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. Pass a server-generated HMAC signature so Encatch can validate the request. `generatedDateTimeinUTC` must be **milliseconds since the Unix epoch** (for example the string form of `DateTime.now().millisecondsSinceEpoch` 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. ```dart await Encatch.identifyUser( 'user@example.com', options: IdentifyOptions( secure: SecureOptions( signature: 'your-hmac-signature', generatedDateTimeinUTC: '1741867200000', // ms since epoch (2025-03-13T12:00:00Z) ), ), ); ``` ### 3. Show a form manually [#3-show-a-form-manually] Show a specific form by slug or ID. ```dart await Encatch.showForm('feedback-form'); await Encatch.showForm('feedback-form', options: ShowFormOptions( reset: ResetMode.always, )); ``` | ResetMode | Behavior | | ---------------------- | ------------------------------------------------------ | | `ResetMode.always` | Reset pre-fill and response data on every form display | | `ResetMode.onComplete` | Reset only after the form is completed | | `ResetMode.never` | Never reset response data | Pass caller context when showing a form: ```dart await Encatch.showForm('feedback-form', options: ShowFormOptions( reset: ResetMode.always, context: {'plan': 'team', 'feature': 'checkout'}, )); ``` ### Other actions [#other-actions] Set the user's preferred language. ```dart Encatch.setLocale('fr'); ``` Set the user's country. ```dart Encatch.setCountry('FR'); // ISO 3166 country code ``` Set the theme for forms and surveys. ```dart Encatch.setTheme(EncatchTheme.dark); Encatch.setTheme(EncatchTheme.light); Encatch.setTheme(EncatchTheme.system); // Follows system preference ``` ```dart await Encatch.trackEvent('button_clicked'); ``` ```dart await Encatch.trackScreen('HomeScreen'); ``` Add `EncatchNavigatorObserver` for automatic screen tracking: ```dart MaterialApp( navigatorObservers: [EncatchNavigatorObserver()], // ... ) ``` Subscribe to form lifecycle events. Returns an unsubscribe function. ```dart final unsubscribe = Encatch.on((eventType, payload) { print('Event: $eventType, payload: ${payload.data}'); }); // Later, to unsubscribe: unsubscribe(); ``` | Event | Description | | ----------------------------- | --------------------------------------------------------------------- | | `EventType.formShow` | Fired when a form is displayed | | `EventType.formStarted` | Fired when a user starts interacting | | `EventType.formSubmit` | Fired when a form is submitted | | `EventType.formComplete` | Fired when a form is fully completed | | `EventType.formClose` | Fired when a form is closed | | `EventType.formDismissed` | Fired when a form is dismissed without completion | | `EventType.formError` | Fired when an error occurs | | `EventType.formSectionChange` | Fired when the visible section changes | | `EventType.formAnswered` | Fired when a question is answered | | `EventType.formRemindMeLater` | Fired when the user taps "Remind me later" | | `EventType.formCtaTriggered` | Fired when a completion CTA is triggered on thank-you or exit screens | Handle completion CTAs (in-app navigation, internal redirect, or external browser) via `formCtaTriggered`. Configure actions in the form builder — see [Call to action](/docs/feedback-management/form-builder/call-to-action). The SDK closes the form overlay after emitting the event — your app handles in-app navigation: ```dart Encatch.on((eventType, payload) { if (eventType != EventType.formCtaTriggered) return; final action = payload.data?['action']; if (action != 'app_navigate') return; final route = payload.data?['route'] as String?; // Map route strings to your app's navigation paths if (route == 'billing' || route == 'billing/upgrade') { navigatorKey.currentState?.pushNamed('/billing'); } }); ``` For in-app navigation, the SDK closes the form overlay 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. Pre-fill a form response before showing a form. `questionId` may be a question UUID or a question slug. ```dart Encatch.addToResponse('question_id', 'pre-filled value'); Encatch.addToResponse('choice_question_id', ['option-a', 'option-b']); await Encatch.showForm('your-form-slug'); ``` Dismiss the currently displayed form. ```dart await Encatch.dismissForm(); // Or dismiss a specific form configuration: await Encatch.dismissForm(formConfigurationId: 'config-id'); ``` Use `onBeforeShowForm` in `EncatchConfig` to conditionally block forms from showing. ```dart EncatchProvider( apiKey: 'your-api-key', config: EncatchConfig( onBeforeShowForm: (payload) async { // Inspect payload.formId, payload.formConfig, payload.triggerType, etc. if (payload.triggerType == TriggerType.automatic && someCondition) { return false; // Block this form } return true; // Allow }, ), child: MyApp(), ) ``` `EncatchProvider` starts a session automatically after initialization. You can also control session lifecycle manually: ```dart await Encatch.startSession(); // Skip the immediate ping or screen re-track on start: await Encatch.startSession( options: StartSessionOptions( skipImmediatePing: true, skipImmediateTrackScreen: true, ), ); ``` ```dart // Temporarily stop the 30-second background ping (not persisted) Encatch.pauseSession(); // Resume the ping interval after pauseSession() Encatch.resumeSession(); ``` ```dart // Fully suspend SDK activity — stops ping and dismisses open forms. // Persists across app restarts. Re-enable with startSession(). await Encatch.stopSession(); ``` 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. ```dart await Encatch.resetUser(); ``` Wipes **all** persisted SDK data and resets in-memory state. Stronger than `resetUser()` — also clears session-stopped state and device preferences. The SDK remains initialized; call `identifyUser` afterward. ```dart await Encatch.clearAll(); ``` 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. *** ### Inline Forms [#inline-forms] Inline forms are a way to show Encatch in-app feedback without a modal — the survey renders directly in your layout instead of as a full-screen overlay. `EncatchInlineForm` renders a form directly inside your widget tree instead of as a full-screen modal overlay. Place it anywhere — in a `Column`, `SingleChildScrollView`, `Card`, etc. ```dart // In your screen's widget tree: SingleChildScrollView( child: Column( children: [ // ... content above ... EncatchInlineForm( formId: 'your-form-slug', // exact match; omit for wildcard enabled: ModalRoute.of(context)?.isCurrent ?? true, ), // ... content below ... ], ), ) ``` Then trigger the form from anywhere: ```dart await Encatch.showForm('your-form-slug'); ``` When `showForm` is called, the SDK resolves the presenter in this order: 1. **Exact match** — first registered `EncatchInlineForm` whose `formId` matches the payload wins. 2. **Wildcard** — first registered `EncatchInlineForm` with no `formId` catches anything not exact-matched. 3. **Modal fallback** — `EncatchWebView` shows the form as the default overlay when no inline slot is registered or none match. A background tab with `EncatchInlineForm` mounted will intercept `showForm` calls even when it is not visible. To prevent this: **Option A — pass `enabled` from `ModalRoute`:** ```dart EncatchInlineForm( formId: 'your-form-slug', enabled: ModalRoute.of(context)?.isCurrent ?? true, ) ``` **Option B — only mount `EncatchInlineForm` on the active route** (e.g. using `IndexedStack` with conditional rendering). **Option C — bottom tabs with GoRouter `StatefulShellRoute`:** Offstage tab branches often do not rebuild when the shell index changes, so `ModalRoute.of(context)?.isCurrent` can stay stale. Sync the active tab index with an `InheritedNotifier` (or similar) and pass `enabled: activeTabIndex == myTabIndex` to each inline slot. The encatch-flutter-tester sample app demonstrates this with `ShellTabIndexScope` and `EncatchInlineForm(enabled: isActive)`. When `enabled: false` the slot is unregistered, so `showForm` falls through to the modal or another active slot. The WebView's internal scroll is disabled. The host `SingleChildScrollView` (or `CustomScrollView`) provides scrolling. The widget height grows automatically via `form:resize` messages from the web form. ```dart SingleChildScrollView( child: Column( children: [ EncatchInlineForm(formId: 'my-form'), ], ), ) ``` The host app controls keyboard avoidance. Wrap the scroll view in `MediaQuery` inset handling or use `Scaffold`'s `resizeToAvoidBottomInset` to slide content above the keyboard. | Prop | Type | Default | Description | | --------------------- | --------------------- | ------- | ------------------------------------------------------------- | | `formId` | `String?` | `null` | Exact form slug/id to match. `null` = wildcard. | | `enabled` | `bool` | `true` | When `false`, unregisters the slot — use for tab/route focus. | | `minHeight` | `double` | `0` | Minimum height floor applied after `form:resize`. | | `decoration` | `BoxDecoration?` | `null` | Outer container decoration. | | `onOverlayOpenChange` | `ValueChanged?` | `null` | Called when a QnA/Scheduler overlay opens or closes. | ### 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 Flutter widgets and submit responses through the SDK. That keeps typography, spacing, colors, and interaction patterns aligned with the rest of your app, so the survey feels like a native screen rather than an embedded web page. Example coming soon. *** | 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 (inline or modal) | | `dismissForm({formConfigurationId})` | Dismiss the current form | | `addToResponse(questionId, value)` | Pre-fill a question answer | | `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 | | `off(callback)` | Unsubscribe from events | | `submitForm(params)` | Submit a custom native form | | `stop()` | Teardown (called by provider on unmount) | Add usage descriptions to `ios/Runner/Info.plist` when forms include video/audio capture: ```xml NSCameraUsageDescription Encatch forms use the camera to record video responses. NSMicrophoneUsageDescription Encatch forms use the microphone to record audio and video responses. ``` No other iOS setup is required. The SDK uses `flutter_inappwebview`, which handles WebView media permission requests once these keys are present. Add permissions to `android/app/src/main/AndroidManifest.xml`: ```xml ``` `INTERNET` is required for API calls and the form WebView. The other three permissions are required when forms include video/audio capture questions (`video_audio`). The SDK grants WebView media permission requests automatically, but Android still requires **runtime** approval before the camera or microphone can be used. Request them at startup (Android only): ```dart import 'package:flutter/foundation.dart'; import 'package:permission_handler/permission_handler.dart'; Future requestEncatchMediaPermissions() async { if (kIsWeb || defaultTargetPlatform != TargetPlatform.android) return; final statuses = await [ Permission.camera, Permission.microphone, ].request(); if (statuses[Permission.camera] != PermissionStatus.granted || statuses[Permission.microphone] != PermissionStatus.granted) { // Handle denied permissions — recording questions will not work } } ``` Add [`permission_handler`](https://pub.dev/packages/permission_handler) to your app for this pattern — it is not a dependency of `encatch_flutter`. ## Support [#support] * **pub.dev:** [encatch\_flutter](https://pub.dev/packages/encatch_flutter) * **Issues:** [github.com/get-encatch/flutter-sdk/issues](https://github.com/get-encatch/flutter-sdk/issues) # Overview (/docs/sdk-reference/mobile-sdk) Encatch mobile and native SDKs let you collect in-app feedback and surveys inside your applications. Display forms as modal overlays or inline in your UI, identify users, track screens and events, and submit responses to the Encatch backend. ## Overview [#overview] * **Platforms:** Android, iOS, and macOS — natively (Kotlin/Swift), via Kotlin Multiplatform or Compose Multiplatform, or via Flutter and React Native * **Form display:** Modal WebView overlay or inline embedded forms * **Capabilities:** User identification, screen and event tracking, session management, and response submission * **Prerequisites:** A [publishable SDK key](/docs/settings/security/publishable-sdk-keys) with your app package or bundle ID listed under **Allowed Domains / Packages** # iOS SDK (/docs/sdk-reference/mobile-sdk/ios) The Encatch iOS SDK lets you collect in-app feedback and surveys in native iOS apps. Display forms as a modal WebView overlay or inline in your layout, identify users, track screens and events, and submit responses to the Encatch backend. The SDK is written in Swift, using `URLSession` for networking, `UserDefaults` for storage, and `WKWebView` for form rendering. It has no dependencies — nothing else to link, no embedded runtimes. *** ## Overview [#overview] * **Package:** [`encatch-swift`](https://github.com/get-encatch/encatch-swift) (Swift Package Manager) * **Version:** 0.1.1 * **Platforms:** iOS 15+, macOS 12+ via Mac Catalyst (see the separate macOS page for Catalyst specifics) * **Repository:** [github.com/get-encatch/encatch-android](https://github.com/get-encatch/encatch-android) (development happens under `swift/` in the cross-platform monorepo; `encatch-swift` is the SPM distribution mirror, updated per release) * **License:** MIT *** ## Installation [#installation] **File → Add Package Dependencies…** and enter the package URL: ``` https://github.com/get-encatch/encatch-swift ``` Set the dependency rule to **Up to Next Minor Version**, then add the `Encatch` library to your app target. ```swift dependencies: [ .package(url: "https://github.com/get-encatch/encatch-swift", from: "0.1.1"), ], targets: [ .target( name: "MyApp", dependencies: [ .product(name: "Encatch", package: "encatch-swift"), ] ), ] ``` While versions are `0.x`, **minor** bumps may contain breaking changes. SPM's `from: "0.1.1"` rule only auto-updates **patch** releases, which is the safe default — review the release notes before moving to a new minor version. *** ## Quick Start [#quick-start] ### 1. Initialization [#1-initialization] Install the modal form host once at app launch with `EncatchFormHost.install()`, then initialize the SDK. `EncatchFormHost.install()` is **required** for modal forms — it mounts the listener that presents the form overlay on the topmost view controller. ```swift import SwiftUI import Encatch @main struct MyApp: App { init() { EncatchFormHost.install() Task { try await Encatch.shared.initialize(apiKey: "your-api-key") } } var body: some Scene { WindowGroup { ContentView() } } } ``` The API is `async/await` — wrap calls in a `Task { }` when calling from synchronous contexts. ```swift import UIKit import Encatch @main class AppDelegate: UIResponder, UIApplicationDelegate { func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { EncatchFormHost.install() Task { try await Encatch.shared.initialize(apiKey: "your-api-key") } return true } } ``` Pass an optional `EncatchConfig` to customize SDK behavior: ```swift try await Encatch.shared.initialize( apiKey: "your-api-key", config: EncatchConfig( theme: .system, isFullScreen: false, debugMode: true, appVersion: "1.2.3", onBeforeShowForm: { payload in // Return false to prevent the form from showing return true } ) ) ``` ### 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. `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": .string("…")]`). ```swift try await Encatch.shared.identifyUser(userName: "user@example.com") ``` ```swift try await Encatch.shared.identifyUser( userName: "user@example.com", traits: UserTraits( set: ["name": .string("Alice"), "plan": .string("team")] ) ) ``` ```swift try await Encatch.shared.identifyUser( userName: "user@example.com", traits: UserTraits( set: ["name": .string("Alice"), "plan": .string("team")], setOnce: ["firstSeen": .string(ISO8601DateFormatter().string(from: Date()))], increment: ["loginCount": 1], decrement: ["credits": 5], unset: ["trialEndDate"] ) ) ``` **User traits** support the following operations: | Operation | Type | Description | | ----------- | ---------------------- | ---------------------------------------------------- | | `set` | `[String: JSONValue]?` | Set user attributes (overwrites existing values) | | `setOnce` | `[String: JSONValue]?` | Set user attributes only if they don't already exist | | `increment` | `[String: Double]?` | Increment numeric user attributes | | `decrement` | `[String: Double]?` | Decrement numeric user attributes | | `unset` | `[String]?` | Remove user attributes | 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. Pass a server-generated HMAC signature so Encatch can validate the request. `generatedDateTimeInUtc` must be **milliseconds since the Unix epoch** (the string form of the epoch-milliseconds timestamp 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. ```swift try await Encatch.shared.identifyUser( userName: "user@example.com", options: IdentifyOptions( secure: SecureOptions( signature: "your-hmac-signature", generatedDateTimeInUtc: "1741867200000" // ms since epoch (2025-03-13T12:00:00Z) ) ) ) ``` ### 3. Show a form manually [#3-show-a-form-manually] Show a specific form by slug or ID. ```swift try await Encatch.shared.showForm("feedback-form") try await Encatch.shared.showForm("feedback-form", options: ShowFormOptions( reset: .always )) ``` | ResetMode | Behavior | | ------------- | ------------------------------------------------------ | | `.always` | Reset pre-fill and response data on every form display | | `.onComplete` | Reset only after the form is completed | | `.never` | Never reset response data | Pass caller context when showing a form. `ContextValue` supports `.string`, `.number`, `.boolean`, and `.date(epochMillis:)`: ```swift try await Encatch.shared.showForm("feedback-form", options: ShowFormOptions( reset: .always, context: [ "plan": .string("team"), "feature": .string("checkout"), "seats": .number(12), "trial": .boolean(false), ] )) ``` ### Other actions [#other-actions] Set the user's preferred language. ```swift Encatch.shared.setLocale("fr") ``` Set the user's country. ```swift Encatch.shared.setCountry("FR") // ISO 3166 country code ``` Set the theme for forms and surveys. ```swift Encatch.shared.setTheme(.dark) Encatch.shared.setTheme(.light) Encatch.shared.setTheme(.system) // Follows system preference ``` ```swift try await Encatch.shared.trackEvent("button_clicked") ``` ```swift try await Encatch.shared.trackScreen("HomeScreen") ``` A common pattern in SwiftUI is tracking from `onAppear`: ```swift struct HomeView: View { var body: some View { content .onAppear { Task { try? await Encatch.shared.trackScreen("HomeScreen") } } } } ``` In UIKit, call it from `viewDidAppear(_:)`. Subscribe to form lifecycle events. Returns an unsubscribe closure. ```swift let unsubscribe = Encatch.shared.on { eventType, payload in print("Event: \(eventType), formId: \(payload.formId ?? "-"), data: \(payload.data ?? [:])") } // Later, to unsubscribe: unsubscribe() ``` | Event | Description | | -------------------- | --------------------------------------------------------------------- | | `.formShow` | Fired when a form is displayed | | `.formStarted` | Fired when a user starts interacting | | `.formSubmit` | Fired when a form is submitted | | `.formComplete` | Fired when a form is fully completed | | `.formClose` | Fired when a form is closed | | `.formDismissed` | Fired when a form is dismissed without completion | | `.formError` | Fired when an error occurs | | `.formSectionChange` | Fired when the visible section changes | | `.formAnswered` | Fired when a question is answered | | `.formRemindMeLater` | Fired when the user taps "Remind me later" | | `.formCtaTriggered` | Fired when a completion CTA is triggered on thank-you or exit screens | Handle completion CTAs (in-app navigation, internal redirect, or external browser) via `.formCtaTriggered`. Configure actions in the form builder — see [Call to action](/docs/feedback-management/form-builder/call-to-action). The SDK closes the form overlay after emitting the event — your app handles in-app navigation: ```swift Encatch.shared.on { eventType, payload in guard eventType == .formCtaTriggered else { return } guard case .string(let action)? = payload.data?["action"], action == "app_navigate" else { return } guard case .string(let route)? = payload.data?["route"] else { return } // Map route strings to your app's navigation paths if route == "billing" || route == "billing/upgrade" { DispatchQueue.main.async { // e.g. push your billing screen via your router / navigation controller } } } ``` For in-app navigation, the SDK closes the form overlay after emitting the event and expects your app to perform navigation. For URL redirect actions, the SDK opens the URL (via `SFSafariViewController` or the system browser) and closes the form automatically. Pre-fill a form response before showing a form. `questionId` may be a question UUID or a question slug. ```swift Encatch.shared.addToResponse(questionId: "question_id", value: "pre-filled value") Encatch.shared.addToResponse(questionId: "choice_question_id", value: ["option-a", "option-b"]) try await Encatch.shared.showForm("your-form-slug") ``` Dismiss the currently displayed form. ```swift try await Encatch.shared.dismissForm() // Or dismiss a specific form configuration: try await Encatch.shared.dismissForm("config-id") ``` Use `onBeforeShowForm` in `EncatchConfig` to conditionally block forms from showing. ```swift try await Encatch.shared.initialize( apiKey: "your-api-key", config: EncatchConfig( onBeforeShowForm: { payload in // Inspect payload.formId, payload.formConfig, payload.triggerType, etc. if payload.triggerType == .automatic && someCondition { return false // Block this form } return true // Allow } ) ) ``` Returning `false` also clears any pending pre-filled responses. This is the entry point for rendering your own native form UI — see [Build Your Own Form UX & UI](#build-your-own-form-ux--ui). `identifyUser` starts a session automatically. You can also control session lifecycle manually: ```swift try await Encatch.shared.startSession() // Skip the immediate ping or screen re-track on start: try await Encatch.shared.startSession(StartSessionOptions( skipImmediatePing: true, skipImmediateTrackScreen: true )) ``` ```swift // Temporarily stop the 30-second background ping (not persisted) Encatch.shared.pauseSession() // Resume the ping interval after pauseSession() Encatch.shared.resumeSession() ``` ```swift // Fully suspend SDK activity — stops ping and dismisses open forms. // Persists across app restarts. Re-enable with startSession(). try await Encatch.shared.stopSession() ``` 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. ```swift try await Encatch.shared.resetUser() ``` Wipes **all** persisted SDK data and resets in-memory state. Stronger than `resetUser()` — also clears session-stopped state and device preferences. Call `initialize` and `identifyUser` again afterward. ```swift try await Encatch.shared.clearAll() ``` 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. *** ### Inline Forms [#inline-forms] Inline forms are a way to show Encatch in-app feedback without a modal — the survey renders directly in your layout instead of as a full-screen overlay. `EncatchInlineFormView` is a `UIView` that claims a form id, so `showForm` for that id renders inline in your layout instead of as a modal. Leave `formId` as `nil` to make it a wildcard slot that catches any form id not claimed elsewhere. The package does not ship a SwiftUI wrapper, so SwiftUI hosts wrap `EncatchInlineFormView` in a `UIViewRepresentable` and drive the frame from `onHeightChange`: ```swift import SwiftUI import Encatch struct InlineFormRepresentable: UIViewRepresentable { let formId: String? @Binding var height: CGFloat func makeUIView(context: Context) -> EncatchInlineFormView { let view = EncatchInlineFormView() view.formId = formId view.onHeightChange = { [binding = $height] newHeight in DispatchQueue.main.async { binding.wrappedValue = newHeight } } return view } func updateUIView(_ uiView: EncatchInlineFormView, context: Context) {} } struct InlineFormSlot: View { let formId: String? @State private var height: CGFloat = 0 var body: some View { InlineFormRepresentable(formId: formId, height: $height) .frame(height: max(height, 64)) .animation(.easeOut(duration: 0.2), value: height) } } ``` Place the slot in a `ScrollView`, then trigger the form from anywhere: ```swift ScrollView { VStack(spacing: 20) { // ... content above ... InlineFormSlot(formId: "your-form-slug") // exact match; pass nil for wildcard // ... content below ... } } ``` ```swift try await Encatch.shared.showForm("your-form-slug") ``` UIKit hosts add `EncatchInlineFormView` directly. With Auto Layout, the view sizes itself via its own height constraint — no `onHeightChange` needed: ```swift import UIKit import Encatch final class FeedbackViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let inlineForm = EncatchInlineFormView() inlineForm.formId = "your-form-slug" // or nil for a wildcard slot inlineForm.minHeight = 64 inlineForm.translatesAutoresizingMaskIntoConstraints = false contentStackView.addArrangedSubview(inlineForm) } } ``` For manual layout, use `onHeightChange` to drive your own frames: ```swift inlineForm.onHeightChange = { newHeight in // update your layout with newHeight } ``` Then trigger the form from anywhere: ```swift try await Encatch.shared.showForm("your-form-slug") ``` When `showForm` is called, the SDK resolves the presenter in this order: 1. **Exact match** — first registered `EncatchInlineFormView` whose `formId` matches the payload wins. 2. **Wildcard** — first registered `EncatchInlineFormView` with `formId == nil` catches anything not exact-matched. 3. **Modal fallback** — `EncatchFormHost` shows the form as the default overlay when no inline slot is registered or none match. Slot registration is tied to the view's window attach/detach lifecycle — a view removed from the window (e.g. its screen popped off the navigation stack) unregisters automatically, and `showForm` falls through to the modal or another active slot. The WebView's internal scroll is disabled. The host scroll view (`ScrollView` in SwiftUI, `UIScrollView`/stack in UIKit) provides scrolling. The view's height grows automatically via `form:resize` messages from the web form: * **Auto Layout hosts** need nothing — the view maintains its own height constraint. * **SwiftUI / manual-layout hosts** bind `onHeightChange` to their own frame instead of hardcoding a height. * `minHeight` sets a floor (in points) applied after resize messages. The host app controls keyboard avoidance — use standard `keyboardLayoutGuide` (UIKit) or SwiftUI's automatic keyboard avoidance to slide content above the keyboard. | Property | Type | Default | Description | | --------------------- | ---------------------- | ------- | ----------------------------------------------------- | | `formId` | `String?` | `nil` | Exact form slug/id to match. `nil` = wildcard. | | `minHeight` | `CGFloat` | `0` | Minimum height floor applied after `form:resize`. | | `onHeightChange` | `((CGFloat) -> Void)?` | `nil` | Called whenever the view's self-sized height changes. | | `onOverlayOpenChange` | `((Bool) -> Void)?` | `nil` | Called when a QnA/Scheduler overlay opens or closes. | ### 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 native views and submit responses through the SDK. That keeps typography, spacing, colors, and interaction patterns aligned with the rest of your app, so the survey feels like a native screen rather than an embedded web page. The flow has two parts: 1. **Intercept the form** with `onBeforeShowForm` and return `false` — the SDK hands you the full form configuration (`payload.formConfig`) and skips its own UI. 2. **Submit responses** with `buildSubmitRequest` + `submitForm` once the user completes your native form. ```swift try await Encatch.shared.initialize( apiKey: "your-api-key", config: EncatchConfig( onBeforeShowForm: { payload in guard payload.formId == "my-native-form" else { return true } // Present your own UI using payload.formConfig // (questionnaireFields, appearanceProperties, etc.) await MyNativeSurveyPresenter.shared.present(config: payload.formConfig) return false // SDK will not render its own form } ) ) ``` When the user finishes, map each answer to a `NativeFormResponse` and build the submit request. `buildSubmitRequest` covers all 33 question types — numeric scales take numbers, choice types take `String` or `[String]`, boolean types take `Bool`, matrix types take dictionaries: ```swift let responses = [ NativeFormResponse(questionId: "q1", type: "rating", value: 5), NativeFormResponse(questionId: "q2", type: "short_answer", value: "Great product!"), NativeFormResponse(questionId: "q3", type: "multiple_choice_multiple", value: ["speed", "design"]), NativeFormResponse(questionId: "q4", type: "yes_no", value: true), ] let request = buildSubmitRequest( BuildSubmitRequestOptions( formConfigurationId: formConfig.feedbackConfigurationId, completionTimeInSeconds: 42 ), responses: responses ) try await Encatch.shared.submitForm(request) ``` *** All methods are called on the `Encatch.shared` singleton. | Method | Description | | ---------------------------------------- | ----------------------------------------------------------- | | `initialize(apiKey:config:)` | Initialize the SDK | | `identifyUser(userName:traits:options:)` | Identify a user | | `setLocale(_:)` | Set locale | | `setCountry(_:)` | Set country (ISO 3166) | | `setTheme(_:)` | Set form theme | | `trackEvent(_:)` | Track a custom event | | `trackScreen(_:)` | Track screen navigation | | `showForm(_:options:)` | Show a form (inline or modal) | | `dismissForm(_:)` | Dismiss the current form | | `addToResponse(questionId:value:)` | Pre-fill a question answer | | `startSession(_:)` | 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(_:)` | Subscribe to lifecycle events (returns unsubscribe closure) | | `emitEvent(_:_:)` | Emit a lifecycle event manually | | `submitForm(_:)` | Submit a custom native form | | `flushRetryQueue()` | Flush the offline retry queue (e.g. on foreground) | | `stop()` | Teardown — stops the ping loop | | `isInitialized` | Whether `initialize` has completed | `EncatchFormHost.install()` (call once at launch) mounts the modal form presenter; `EncatchInlineFormView` renders forms inline. Add usage descriptions to your app's `Info.plist` when forms include video/audio capture questions (`video_audio`): ```xml NSCameraUsageDescription Encatch forms use the camera to record video responses. NSMicrophoneUsageDescription Encatch forms use the microphone to record audio and video responses. ``` No other setup is required. The SDK uses `WKWebView`, which surfaces the system media permission prompts once these keys are present. Network access needs no entitlement in a standard iOS app; Mac Catalyst targets need the **Outgoing Connections (Client)** App Sandbox capability. ## Support [#support] * **Package:** [github.com/get-encatch/encatch-swift](https://github.com/get-encatch/encatch-swift) * **Issues:** [github.com/get-encatch/encatch-android/issues](https://github.com/get-encatch/encatch-android/issues) (development monorepo — issues are welcome in either repo) # Kotlin Multiplatform SDK (/docs/sdk-reference/mobile-sdk/kotlin-multiplatform) The Encatch Kotlin Multiplatform SDK (`com.encatch:kmp-sdk`) lets you collect in-app feedback and surveys from shared `commonMain` code. One `Encatch` object gives you the full SDK — initialize, identify users, track screens and events, show modal forms, and submit responses — with the same call site on Android and iOS and zero platform-bridging code of your own. Under the hood it is a thin platform-routing layer over the two native Encatch SDKs, not a reimplementation: on Android it forwards 1:1 to the native [Android SDK](./android) (Android's native language *is* Kotlin), and on iOS it forwards through Kotlin/Native cinterop to the pure-Swift [iOS SDK](./ios). This module is pure business logic with **no UI layer**. If your app uses Compose Multiplatform and you also want a ready-made inline-form composable, use the [Compose Multiplatform SDK](./compose-multiplatform) (`com.encatch:compose-sdk`) instead — it depends on this module, re-exports the same `Encatch` API, and adds `EncatchInlineForm` plus fully automatic modal-host setup. *** ## Overview [#overview] * **Package:** `com.encatch:kmp-sdk` (Maven Central) * **Version:** 0.1.1 * **Platforms:** Android (minSdk 24), iOS (`iosArm64`, `iosSimulatorArm64`) * **Repository:** [github.com/get-encatch/encatch-android](https://github.com/get-encatch/encatch-android) * **License:** MIT *** ## Installation [#installation] Add the dependency to your shared module's `commonMain` source set: ```kotlin // build.gradle.kts (shared module) kotlin { sourceSets { commonMain.dependencies { implementation("com.encatch:kmp-sdk:0.1.1") } } } ``` ### Platform setup [#platform-setup] Install the modal form host once, typically in your `Application.onCreate`. This module cannot do it for you automatically — it has no `Context`/`Application` reference available from `commonMain` (unlike `com.encatch:compose-sdk`, which can do this lazily via Compose's `LocalContext`): ```kotlin import android.app.Application class MyApplication : Application() { override fun onCreate() { super.onCreate() com.encatch.android.EncatchFormHost.install(this) } } ``` Without this call, `showForm` cannot present the modal overlay on Android. Nothing to do — `Encatch.init(...)` installs the modal form host automatically the first time it's called. *** ## Quick Start [#quick-start] ### 1. Initialization [#1-initialization] Call `Encatch.init` once at app startup from any coroutine scope. It's a `suspend` function — all subsequent calls (`identifyUser`, `showForm`, tracking) silently no-op until initialization completes. ```kotlin import com.encatch.sdk.Encatch // commonMain — same call site on both platforms scope.launch { Encatch.init("your-api-key") } ``` Check `Encatch.isInitialized` to guard against double-initialization, e.g. on process restarts: ```kotlin if (!Encatch.isInitialized) { Encatch.init("your-api-key") } ``` Pass an optional `EncatchConfig` to customize SDK behavior: ```kotlin import com.encatch.sdk.Encatch import com.encatch.sdk.EncatchConfig import com.encatch.sdk.Theme scope.launch { Encatch.init( "your-api-key", EncatchConfig( theme = Theme.SYSTEM, debugMode = true, isFullScreen = false, appVersion = "1.2.3", onBeforeShowForm = { payload -> // Return false to prevent the form from showing true }, ), ) } ``` ### 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. `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 = mapOf("display_name" to JsonPrimitive("…"))`). ```kotlin Encatch.identifyUser("user@example.com") ``` Trait values are `kotlinx.serialization` `JsonElement`s — use `JsonPrimitive` for strings, numbers, and booleans: ```kotlin import com.encatch.sdk.UserTraits import kotlinx.serialization.json.JsonPrimitive Encatch.identifyUser( "user@example.com", traits = UserTraits( set = mapOf( "name" to JsonPrimitive("Alice"), "plan" to JsonPrimitive("team"), ), ), ) ``` ```kotlin import com.encatch.sdk.UserTraits import kotlinx.serialization.json.JsonPrimitive Encatch.identifyUser( "user@example.com", traits = UserTraits( set = mapOf("name" to JsonPrimitive("Alice"), "plan" to JsonPrimitive("team")), setOnce = mapOf("firstSeen" to JsonPrimitive("2026-08-05T12:00:00Z")), increment = mapOf("loginCount" to 1.0), decrement = mapOf("credits" to 5.0), unset = listOf("trialEndDate"), ), ) ``` **User traits** support the following operations: | Operation | Type | Description | | ----------- | --------------------------- | ---------------------------------------------------- | | `set` | `Map?` | Set user attributes (overwrites existing values) | | `setOnce` | `Map?` | Set user attributes only if they don't already exist | | `increment` | `Map?` | Increment numeric user attributes | | `decrement` | `Map?` | Decrement numeric user attributes | | `unset` | `List?` | Remove user attributes | 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. Pass a server-generated HMAC signature so Encatch can validate the request. `generatedDateTimeInUtc` must be **milliseconds since the Unix epoch** (the string form of your server's epoch-millis timestamp). 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. ```kotlin import com.encatch.sdk.IdentifyOptions import com.encatch.sdk.SecureOptions Encatch.identifyUser( "user@example.com", options = IdentifyOptions( secure = SecureOptions( signature = "your-hmac-signature", generatedDateTimeInUtc = "1741867200000", // ms since epoch (2025-03-13T12:00:00Z) ), ), ) ``` ### 3. Show a form manually [#3-show-a-form-manually] Show a specific form by slug or ID. ```kotlin import com.encatch.sdk.ResetMode import com.encatch.sdk.ShowFormOptions Encatch.showForm("feedback-form") Encatch.showForm("feedback-form", ShowFormOptions(reset = ResetMode.ALWAYS)) ``` | ResetMode | Behavior | | ----------------------- | ------------------------------------------------------ | | `ResetMode.ALWAYS` | Reset pre-fill and response data on every form display | | `ResetMode.ON_COMPLETE` | Reset only after the form is completed | | `ResetMode.NEVER` | Never reset response data | Pass caller context when showing a form. Context values use the `ContextValue` sealed class (`StringValue`, `NumberValue`, `BooleanValue`, `DateValue`): ```kotlin import com.encatch.sdk.ContextValue import com.encatch.sdk.ResetMode import com.encatch.sdk.ShowFormOptions Encatch.showForm( "feedback-form", ShowFormOptions( reset = ResetMode.ALWAYS, context = mapOf( "plan" to ContextValue.StringValue("team"), "feature" to ContextValue.StringValue("checkout"), ), ), ) ``` ### Other actions [#other-actions] Set the user's preferred language. ```kotlin Encatch.setLocale("fr") ``` Set the user's country. ```kotlin Encatch.setCountry("FR") // ISO 3166 country code ``` Set the theme for forms and surveys. ```kotlin import com.encatch.sdk.Theme Encatch.setTheme(Theme.DARK) Encatch.setTheme(Theme.LIGHT) Encatch.setTheme(Theme.SYSTEM) // Follows system preference ``` ```kotlin Encatch.trackEvent("button_clicked") ``` ```kotlin Encatch.trackScreen("HomeScreen") ``` Subscribe to form lifecycle events. `on` returns an unsubscribe function — there is no separate `off` in the KMP API; call the returned function instead. ```kotlin val unsubscribe = Encatch.on { eventType, payload -> println("Event: ${eventType.wireValue}, formId: ${payload.formId}") } // Later, to unsubscribe: unsubscribe() ``` | Event | Description | | -------------------------------- | --------------------------------------------------------------------- | | `EventType.FORM_SHOW` | Fired when a form is displayed | | `EventType.FORM_STARTED` | Fired when a user starts interacting | | `EventType.FORM_SUBMIT` | Fired when a form is submitted | | `EventType.FORM_COMPLETE` | Fired when a form is fully completed | | `EventType.FORM_CLOSE` | Fired when a form is closed | | `EventType.FORM_DISMISSED` | Fired when a form is dismissed without completion | | `EventType.FORM_ERROR` | Fired when an error occurs | | `EventType.FORM_SECTION_CHANGE` | Fired when the visible section changes | | `EventType.FORM_ANSWERED` | Fired when a question is answered | | `EventType.FORM_REMIND_ME_LATER` | Fired when the user taps "Remind me later" | | `EventType.FORM_CTA_TRIGGERED` | Fired when a completion CTA is triggered on thank-you or exit screens | Handle completion CTAs (in-app navigation, internal redirect, or external browser) via `FORM_CTA_TRIGGERED`. Configure actions in the form builder — see [Call to action](/docs/feedback-management/form-builder/call-to-action). The SDK closes the form overlay after emitting the event — your app handles in-app navigation. Event payload data is a `Map`: ```kotlin import com.encatch.sdk.EventType import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.contentOrNull Encatch.on { eventType, payload -> if (eventType != EventType.FORM_CTA_TRIGGERED) return@on val action = (payload.data?.get("action") as? JsonPrimitive)?.contentOrNull if (action != "app_navigate") return@on val route = (payload.data?.get("route") as? JsonPrimitive)?.contentOrNull // Map route strings to your app's navigation paths when (route) { "billing", "billing/upgrade" -> navigateTo("/billing") } } ``` For in-app navigation, the SDK closes the form overlay 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. Pre-fill a form response before showing a form. `questionId` may be a question UUID or a question slug. ```kotlin Encatch.addToResponse("question_id", "pre-filled value") Encatch.addToResponse("choice_question_id", listOf("option-a", "option-b")) Encatch.showForm("your-form-slug") ``` Inspect or clear pending pre-fills: ```kotlin val pending: Map = Encatch.getPendingResponses() Encatch.clearPendingResponses() ``` Dismiss the currently displayed form. ```kotlin Encatch.dismissForm() // Or dismiss a specific form configuration: Encatch.dismissForm(formConfigurationId = "config-id") ``` Use `onBeforeShowForm` in `EncatchConfig` to conditionally block forms from showing. The interceptor is a `suspend` lambda, so it may await anything — user input, a coroutine, a network check — before answering. ```kotlin import com.encatch.sdk.EncatchConfig import com.encatch.sdk.TriggerType Encatch.init( "your-api-key", EncatchConfig( onBeforeShowForm = { payload -> // Inspect payload.formId, payload.triggerType, payload.formConfigJson, etc. if (payload.triggerType == TriggerType.AUTOMATIC && someCondition) { false // Block this form } else { true // Allow } }, ), ) ``` Register a debug hook that receives every completed SDK HTTP call (request + response). Only fires when `EncatchConfig.debugMode` is enabled; the API key header is always masked to its last 5 characters. Assignment-style (last caller wins) and survives re-`init()` — set it once at app startup for in-app network inspectors. ```kotlin Encatch.setOnNetworkLog { entry -> println("${entry.method} ${entry.endpoint} -> ${entry.status} in ${entry.durationMs}ms") } // Pass null to clear: Encatch.setOnNetworkLog(null) ``` Control session lifecycle manually: ```kotlin import com.encatch.sdk.StartSessionOptions Encatch.startSession() // Skip the immediate ping or screen re-track on start: Encatch.startSession( StartSessionOptions( skipImmediatePing = true, skipImmediateTrackScreen = true, ), ) ``` ```kotlin // Temporarily stop the 30-second background ping (not persisted) Encatch.pauseSession() // Resume the ping interval after pauseSession() Encatch.resumeSession() ``` ```kotlin // Fully suspend SDK activity — stops ping and dismisses open forms. // Persists across app restarts. Re-enable with startSession(). Encatch.stopSession() ``` 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. ```kotlin Encatch.resetUser() ``` Wipes **all** persisted SDK data and resets in-memory state. Stronger than `resetUser()` — also clears session-stopped state and device preferences. The SDK remains initialized; call `identifyUser` afterward. ```kotlin Encatch.clearAll() ``` 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. *** ### Inline Forms [#inline-forms] Inline forms are a way to show Encatch in-app feedback without a modal — the survey renders directly in your layout instead of as a full-screen overlay. `com.encatch:kmp-sdk` ships no views or composables. Inline forms are rendered by embedding the **platform-native inline form view** in each platform's UI code. If you use Compose Multiplatform, prefer the [Compose Multiplatform SDK](./compose-multiplatform), which wraps both native views in a single `EncatchInlineForm` composable you call from `commonMain`. Embed the native inline view directly in your platform UI code. Routing (exact `formId` match, wildcard, modal fallback) is resolved by the platform SDK the same way on both platforms: 1. **Exact match** — an inline view whose `formId` matches the `showForm` payload wins. 2. **Wildcard** — an inline view with no `formId` catches anything not exact-matched. 3. **Modal fallback** — the modal overlay presents the form when no inline slot is registered or none match. Use `com.encatch.android.EncatchInlineFormView` from the underlying native [Android SDK](./android) — it is available on your classpath transitively: ```kotlin import com.encatch.android.EncatchInlineFormView // In your Activity/Fragment or view code: val inlineForm = EncatchInlineFormView(context).apply { formId = "your-form-slug" // exact match; null = wildcard } container.addView(inlineForm) ``` Then trigger the form from shared code: ```kotlin Encatch.showForm("your-form-slug") ``` Use `EncatchInlineFormView` from the native Swift [iOS SDK](./ios) in your SwiftUI/UIKit host code: ```swift import Encatch // UIKit: let inlineForm = EncatchInlineFormView() inlineForm.formId = "your-form-slug" // exact match; nil = wildcard stackView.addArrangedSubview(inlineForm) ``` Then trigger the form from shared code: ```kotlin Encatch.showForm("your-form-slug") ``` The KMP module does not yet expose a `commonMain` accessor for the inline view type itself (a known gap) — the views above are used from each platform's own UI layer, while all business-logic calls stay in `commonMain`. ### 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 native UI and submit responses through the SDK. That keeps typography, spacing, colors, and interaction patterns aligned with the rest of your app, so the survey feels like a native screen rather than an embedded web page. The flow has three parts, all available from `commonMain`: 1. **Intercept** the form with `onBeforeShowForm` and return `false`. The `ShowFormInterceptorPayload` includes `formConfigJson` — the JSON encoding of the full form configuration (including `questionnaireFields`), so you can render your own UI from the real form definition. 2. **Render** your own UI from the payload. 3. **Submit** with `buildSubmitRequest` + `Encatch.submitForm`. ```kotlin import com.encatch.sdk.BuildSubmitRequestOptions import com.encatch.sdk.Encatch import com.encatch.sdk.EncatchConfig import com.encatch.sdk.NativeFormResponse import com.encatch.sdk.buildSubmitRequest // 1. Intercept: block the SDK's own rendering for this form Encatch.init( "your-api-key", EncatchConfig( onBeforeShowForm = { payload -> if (payload.formId == "my-native-form") { showMyNativeForm(payload.formId, payload.formConfigJson) false // block the SDK form — we render our own } else { true } }, ), ) // 3. Submit: convert your native answers and post them to Encatch suspend fun submitMyNativeForm(formConfigurationId: String) { val responses = listOf( NativeFormResponse("q1", "rating", 5), NativeFormResponse("q2", "short_answer", "Great product!"), NativeFormResponse("q3", "multiple_choice_multiple", listOf("option-a", "option-b")), ) val requestJson = buildSubmitRequest( BuildSubmitRequestOptions(formConfigurationId = formConfigurationId), responses, ) Encatch.submitForm(requestJson) } ``` `NativeFormResponse.value`'s expected shape depends on the question `type`: numeric scales (`rating`, `nps`, `csat`, `opinion_scale`) take a `Number` or numeric `String`; text types take `String`; choice and ranking types take `String` or `List`; boolean types (`yes_no`, `consent`) take `Boolean`. All 33 Encatch question types are supported; unknown types fall back to `short_answer` for forward-compatibility. *** | Member | Description | | ----------------------------------------- | ----------------------------------------------------------- | | `init(apiKey, config)` | Initialize the SDK (suspend) | | `isInitialized` | Whether `init` has completed | | `identifyUser(userName, traits, options)` | Identify a user (suspend) | | `setLocale(locale)` | Set locale | | `setCountry(country)` | Set country (ISO 3166) | | `setTheme(theme)` | Set form theme | | `trackEvent(eventName)` | Track a custom event (suspend) | | `trackScreen(screenName)` | Track screen navigation (suspend) | | `showForm(formId, options)` | Show a form (inline or modal) (suspend) | | `dismissForm(formConfigurationId)` | Dismiss the current form (suspend) | | `addToResponse(questionId, value)` | Pre-fill a question answer | | `getPendingResponses()` | Read pending pre-fills | | `clearPendingResponses()` | Clear pending pre-fills | | `submitForm(requestJson)` | Submit a custom native form (suspend) | | `startSession(options)` | Start a new session (suspend) | | `pauseSession()` / `resumeSession()` | Pause / resume background ping | | `stopSession()` | Suspend SDK activity (suspend) | | `resetUser()` | Reset user identity (suspend) | | `clearAll()` | Wipe all persisted SDK data (suspend) | | `on(callback)` | Subscribe to lifecycle events; returns unsubscribe function | | `emitEvent(eventType, payload)` | Emit an event to listeners | | `setOnNetworkLog(callback)` | Debug hook for SDK HTTP calls (debugMode only) | | `stop()` | Teardown | Read-only getters: `apiKey`, `baseUrl`, `webHost`, `isFullScreen`, `theme`, `locale`, `deviceId`, `sessionId`, `userName`, `userId`, `debugMode`. * [Compose Multiplatform SDK](./compose-multiplatform) — this module plus an `EncatchInlineForm` composable; the form host installs itself, so there is no per-platform setup. * [Android SDK](./android) — the native Android SDK this module forwards to on Android. * [iOS SDK](./ios) — the native Swift SDK this module forwards to on iOS. ## Support [#support] * **Maven Central:** `com.encatch:kmp-sdk` * **Issues:** [github.com/get-encatch/encatch-android/issues](https://github.com/get-encatch/encatch-android/issues) # macOS SDK (/docs/sdk-reference/mobile-sdk/macos) The Encatch Swift SDK runs on macOS through **Mac Catalyst**. It is the same package as the [iOS SDK](./ios) — no separate dependency, no conditional code paths in your integration. This page covers what's specific to the Mac: enabling Catalyst, and building a UI around the SDK that feels like a real Mac app rather than a stretched phone screen. *** ## Overview [#overview] * **Package:** [`encatch-swift`](https://github.com/get-encatch/encatch-swift) — the same Swift Package as iOS * **Version:** 0.1.1 * **Platforms:** iOS 15+, macOS 12+ * **License:** MIT macOS support works in two tiers: | Target type | What works | | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Mac Catalyst** app | Everything — modal form overlay, inline forms, tracking, identify, sessions | | **Plain macOS** (AppKit / SwiftUI-for-Mac) target | Core APIs compile and run — `initialize`, `identifyUser`, `trackEvent`, `trackScreen`, sessions — but the WebView form UI does not, because it requires UIKit | The SDK's form UI (`EncatchFormHost`, `EncatchInlineFormView`, the WebView bridge) is built on UIKit and compiled behind `#if canImport(UIKit)`. Mac Catalyst provides UIKit on macOS, so the full SDK — including forms — works in a Catalyst app with **zero changes**. A plain macOS target gets the headless tracking/identify core only. For the complete API reference — configuration, identify, events, sessions, inline forms, interceptors — see the **[iOS SDK](./ios)** page. The API is identical. *** ## Installation [#installation] ### 1. Enable Mac Catalyst on your app target [#1-enable-mac-catalyst-on-your-app-target] In Xcode, select your iOS app target → **General** → **Supported Destinations** → add **Mac (Mac Catalyst)**. Choose "Optimize Interface for Mac" for native-feeling controls, or "Scaled to Match iPad" for a literal iPad port (not recommended — see [macOS-specific considerations](#macos-specific-considerations) below). ### 2. Add the package [#2-add-the-package] **File → Add Package Dependencies…** → enter: ``` https://github.com/get-encatch/encatch-swift ``` Dependency rule: **Up to Next Minor Version** from `0.1.1`, then add the `Encatch` product to your app target. ```swift dependencies: [ .package(url: "https://github.com/get-encatch/encatch-swift", from: "0.1.1"), ], targets: [ .target( name: "MyApp", dependencies: [.product(name: "Encatch", package: "encatch-swift")] ), ] ``` While versions are `0.x`, minor bumps may contain breaking changes. SPM's `from: "0.1.1"` rule only auto-updates patch releases, which is the safe default. No separate Catalyst build settings are needed — the package builds for the `maccatalyst` destination as-is. *** ## Quick Start [#quick-start] Install the modal form host once at launch, initialize, and show a form. This is exactly the same code as iOS: ```swift import SwiftUI import Encatch @main struct MyMacApp: App { init() { EncatchFormHost.install() } var body: some Scene { WindowGroup { ContentView() .task { try? await Encatch.shared.initialize(apiKey: "YOUR_API_KEY") try? await Encatch.shared.identifyUser(userName: "user@example.com") } } } } ``` Then trigger a form from anywhere — a button, a menu item, a keyboard shortcut: ```swift Task { try await Encatch.shared.showForm("your-form-id") } ``` The API surface is identical to iOS, so refer to the iOS page for: * [Configuration (`EncatchConfig`)](./ios#configuration) — `apiBaseUrl`, `webHost`, `theme`, `isFullScreen`, `debugMode`, `appVersion`, `onBeforeShowForm` * [Identify users](./ios#2-identify-users) — traits, secure identification * [Events and screens](./ios#other-actions) — `trackEvent`, `trackScreen` * [Inline forms](./ios#inline-forms) — `EncatchInlineFormView` * [Form events and CTAs](./ios#other-actions) — `Encatch.shared.on { eventType, payload in … }` * [Sessions](./ios#other-actions) — `startSession`, `pauseSession`, `stopSession`, `resetUser`, `clearAll` *** ## macOS-specific considerations [#macos-specific-considerations] The SDK needs nothing extra to run under Catalyst — but your app around it should behave like a Mac app. The guidance below comes from building a full Catalyst tester app against the SDK; the Catalyst limitations listed are real compiler/runtime behavior verified by building, not assumptions. ### Design Mac-native, don't port the phone UI [#design-mac-native-dont-port-the-phone-ui] Running an iPhone layout unmodified under Catalyst looks like a stretched phone screen. Patterns that translate well: * **Sidebar, not bottom tabs** — replace a `TabView` bottom bar with `NavigationSplitView` (Mail/Xcode-style). A sidebar also gives you a persistent, always-visible place to surface state — for example, a badge count of forms your `onBeforeShowForm` interceptor has queued for custom rendering — where a phone app would need floating chrome. * **System controls over brand theming** — `.borderedProminent`/`.bordered` buttons, `.roundedBorder` text fields, `Form` with `.formStyle(.grouped)`, `LabeledContent`, and `Color.accentColor` (the user's own system accent) instead of a hardcoded brand color. Hardcoded pill/capsule iOS theming is the fastest way to look non-native on the Mac. * **A menu bar** — expose feedback actions as menu commands with keyboard shortcuts: ```swift var body: some Scene { WindowGroup { ContentView() } .commands { CommandMenu("Feedback") { Button("Send Feedback…") { Task { try? await Encatch.shared.showForm("feedback-form") } } .keyboardShortcut("f", modifiers: [.command, .shift]) } } } ``` * **Drop soft-keyboard workarounds** — keyboard-avoidance scroll hacks are meaningless without an on-screen keyboard. Pointer-driven UIs also favor `Menu` dropdowns over tap-target chip grids. ### Settings / Preferences windows [#settings--preferences-windows] SwiftUI's `Settings { }` and `Window(_:id:)` Scene types are **hard-unavailable when compiling for Catalyst** — a real compiler error, not a version gate. If you want a Preferences window (Cmd+,), your options are: 1. **A second `WindowGroup(id:)`** opened via `openWindow(id:)`, with `CommandGroup(replacing: .appSettings)` binding Cmd+,. This requires `UIApplicationSceneManifest.UIApplicationSupportsMultipleScenes = true` in Info.plist — Xcode injects it automatically for SwiftUI-lifecycle apps, but a custom Info.plist path bypasses that, so check yours. 2. **A sidebar destination** — fold settings into the sidebar as a regular row and have Cmd+, select it: ```swift .commands { CommandGroup(replacing: .appSettings) { Button("Preferences…") { sidebarSelection = .settings } .keyboardShortcut(",", modifiers: .command) } } ``` ### Other Catalyst limitations to know about [#other-catalyst-limitations-to-know-about] Also verified by building against the SDK under Catalyst: * `.menuStyle(.borderedButton)` is unavailable under Catalyst — use the default menu style. * `.toolbar` item merging across a switched `NavigationSplitView` detail view can be unreliable (items silently disappearing on some destinations). If toolbar actions must survive detail-pane switches, render them in a persistent header view above the detail content instead. * None of these affect the SDK itself — they only constrain the host app UI you build around it. ### Window sizing and the form overlay [#window-sizing-and-the-form-overlay] The modal form presents over the **topmost view controller of the active window scene**, sized to that window — on the Mac that means it overlays your app's window, not the whole screen. Two implications: * Give your window a sensible floor so forms have room to render: ```swift WindowGroup { ContentView() .frame(minWidth: 900, minHeight: 600) } .defaultSize(width: 1100, height: 720) ``` (`.defaultSize` and `.windowResizability` require a deployment target of iOS 17 / macOS 14 — see the note on targeting below.) * `isFullScreen: true` in `EncatchConfig` makes the overlay fill the window, not the display. The default (`false`) card-style presentation generally looks better on desktop. Inline forms (`EncatchInlineFormView`) size themselves via `onHeightChange` exactly as on iOS and work unchanged in Catalyst layouts. ### Theme [#theme] `Encatch.shared.setTheme(_:)` themes the SDK's own form content. Mac users notice when the form and the window disagree, so mirror the SDK theme onto your window's appearance: ```swift extension Theme { var colorScheme: ColorScheme? { switch self { case .light: return .light case .dark: return .dark case .system: return nil // follow the Mac's own appearance setting } } } // In your root view: ContentView() .preferredColorScheme(currentEncatchTheme.colorScheme) ``` ### Deployment target [#deployment-target] The SDK's floor is iOS 15 / macOS 12, but your Catalyst app can target higher than its dependency's minimum. Targeting iOS 17 gives you `Table` (sortable columns), `.defaultSize`/`.windowResizability`, and the two-parameter `.onChange`; Mac users tend to run current macOS versions, so a higher floor costs little reach. ### Plain macOS (non-Catalyst) targets [#plain-macos-non-catalyst-targets] In an AppKit or SwiftUI-for-Mac target (no UIKit), the SDK's core compiles and runs: ```swift import Encatch try await Encatch.shared.initialize(apiKey: "YOUR_API_KEY") try await Encatch.shared.identifyUser(userName: "user@example.com") try await Encatch.shared.trackEvent("exported_report") try await Encatch.shared.trackScreen("EditorWindow") ``` What is **not** available without UIKit: `EncatchFormHost`, `EncatchInlineFormView`, and the WebView-based form rendering — so `showForm` has no presenter. If you need to collect responses in a plain macOS target, use the `onBeforeShowForm` interceptor pattern to receive the form's `questionnaireFields` and render your own AppKit/SwiftUI form, submitting via `Encatch.shared.submitForm(_:)` — see [Build your own form UX](./ios#build-your-own-form-ux--ui) on the iOS page. For the hosted form experience, ship a Catalyst target. *** ## Support [#support] * **Repository:** [github.com/get-encatch/encatch-swift](https://github.com/get-encatch/encatch-swift) * **Issues:** [github.com/get-encatch/encatch-swift/issues](https://github.com/get-encatch/encatch-swift/issues) * **iOS reference:** [iOS SDK](./ios) — the complete API documentation for this package # React Native SDK (/docs/sdk-reference/mobile-sdk/react-native) The Encatch React Native SDK lets you collect in-app feedback and surveys in React Native and Expo apps. Display forms as a modal WebView overlay or inline in your layout, identify users, track screens and events, and submit responses to the Encatch backend. *** ## Overview [#overview] * **Package:** [`@encatch/react-native-sdk`](https://www.npmjs.com/package/@encatch/react-native-sdk) * **Version:** 1.4.2 * **Platforms:** Android, iOS * **Repository:** [github.com/get-encatch/react-native-sdk](https://github.com/get-encatch/react-native-sdk) *** ## Installation [#installation] ```bash npm install @encatch/react-native-sdk ``` ```bash yarn add @encatch/react-native-sdk ``` ```bash pnpm add @encatch/react-native-sdk ``` The SDK also requires these peer dependencies in your app: ```bash npm install react-native-webview react-native-safe-area-context @react-native-async-storage/async-storage ``` Optional peers for automatic screen tracking and device metadata: `@react-navigation/native`, `expo-router`, `expo-application`, `expo-device`, `expo-localization`, `react-native-device-info`, and `react-native-localize`. *** ## Quick Start [#quick-start] ### 1. Initialization [#1-initialization] Wrap your app's root with `EncatchProvider` to initialize the SDK, start a session, and optionally enable automatic screen tracking. Mount `EncatchWebView` once at the root for modal forms. ```tsx import { EncatchProvider, EncatchWebView } from '@encatch/react-native-sdk'; export default function App() { return ( {/* Your app content */} ); } ``` Use the `useEncatch()` hook inside any child component to access the SDK API. For inline forms, mount `EncatchInlineForm` in your screen component tree separately. Pass an optional `config` object to customize SDK behavior: ```tsx { // Return false to prevent form from showing return true; }, }}> ``` **EncatchProvider props:** | Prop | Type | Default | Description | | ---------------- | --------------------------------------------- | ------- | ---------------------------------- | | `apiKey` | `string` | — | Your Encatch API key (required) | | `config` | `EncatchConfig` | — | SDK configuration | | `navigationType` | `'expo-router' \| 'react-navigation' \| null` | `null` | Enable automatic screen tracking | | `skippedRoutes` | `string[]` | `[]` | Routes to skip for screen tracking | ### 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. `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: '…' }`). ```tsx identifyUser('user@example.com'); ``` ```tsx import { useEncatch } from '@encatch/react-native-sdk'; const { identifyUser } = useEncatch(); identifyUser('user@example.com', { $set: { name: 'Alice', plan: 'team' }, }); ``` ```tsx identifyUser('user@example.com', { $set: { name: 'Alice', plan: 'team' }, $setOnce: { firstSeen: new Date().toISOString() }, $increment: { loginCount: 1 }, $decrement: { credits: 5 }, $unset: ['trialEndDate'], }); ``` **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 | 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. 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. ```tsx identifyUser('user@example.com', undefined, { secure: { signature: 'your-hmac-signature', generatedDateTimeinUTC: '1741867200000', // ms since epoch (2025-03-13T12:00:00Z) }, }); ``` ### 3. Show a form manually [#3-show-a-form-manually] Show a specific form by slug or ID. ```tsx import { useEncatch } from '@encatch/react-native-sdk'; const { showForm } = useEncatch(); showForm('feedback-form'); showForm('feedback-form', { reset: 'always' }); ``` | 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: ```tsx showForm('feedback-form', { reset: 'always', context: { plan: 'team', feature: 'checkout' }, }); ``` ### Other actions [#other-actions] Set the user's preferred language. ```tsx const { setLocale } = useEncatch(); setLocale('fr'); ``` Set the user's country. ```tsx const { setCountry } = useEncatch(); setCountry('FR'); // ISO 3166 country code ``` Set the theme for forms and surveys. ```tsx const { setTheme } = useEncatch(); setTheme('dark'); setTheme('light'); setTheme('system'); // Follows system preference ``` ```tsx const { trackEvent } = useEncatch(); trackEvent('button_clicked'); ``` ```tsx const { trackScreen } = useEncatch(); trackScreen('HomeScreen'); ``` Set `navigationType` on `EncatchProvider` for automatic screen tracking: ```tsx {/* or navigationType="react-navigation" */} ``` Use `skippedRoutes` to exclude routes such as login or splash screens. Subscribe to form lifecycle events. Returns an unsubscribe function. ```tsx const { on } = useEncatch(); useEffect(() => { const unsubscribe = on((eventType, payload) => { console.log('Event:', eventType, payload.data); }); return unsubscribe; }, [on]); ``` | 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" | | `form:ctaTriggered` | Fired when a completion CTA is triggered on thank-you or exit screens | Handle completion CTAs (in-app navigation, internal redirect, or external browser) via `form:ctaTriggered`. Configure actions in the form builder — see [Call to action](/docs/feedback-management/form-builder/call-to-action). The SDK closes the form overlay after emitting the event — your app handles in-app navigation: ```tsx const { on } = useEncatch(); const router = useRouter(); // expo-router useEffect(() => { const handler = (eventType, payload) => { if (eventType !== 'form:ctaTriggered') return; const action = payload.data?.action; if (action !== 'app_navigate') return; const route = payload.data?.route as string | undefined; // Map route strings to your app's navigation paths if (route === 'billing' || route === 'billing/upgrade') { router.push('/billing'); } }; const unsubscribe = on(handler); return unsubscribe; }, [on, router]); ``` For in-app navigation, the SDK closes the form overlay 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. Pre-fill a form response before showing a form. `questionId` may be a question UUID or a question slug. ```tsx const { addToResponse, showForm } = useEncatch(); addToResponse('question_id', 'pre-filled value'); addToResponse('choice_question_id', ['option-a', 'option-b']); showForm('your-form-slug'); ``` Dismiss the currently displayed form. ```tsx const { dismissForm } = useEncatch(); dismissForm(); // Or dismiss a specific form configuration: dismissForm('config-id'); ``` Use `onBeforeShowForm` in `EncatchProvider` config to conditionally block forms from showing. ```tsx { // Inspect payload.formId, payload.formConfig, payload.triggerType, etc. if (payload.triggerType === 'automatic' && someCondition) { return false; // Block this form } return true; // Allow }, }}> ``` `EncatchProvider` starts a session automatically after initialization. You can also control session lifecycle manually via the `Encatch` singleton: ```tsx import { Encatch } from '@encatch/react-native-sdk'; await Encatch.startSession(); // Skip the immediate ping or screen re-track on start: await Encatch.startSession({ skipImmediatePing: true, skipImmediateTrackScreen: true, }); ``` ```tsx // Temporarily stop the 30-second background ping (not persisted) Encatch.pauseSession(); // Resume the ping interval after pauseSession() Encatch.resumeSession(); ``` ```tsx // Fully suspend SDK activity — stops ping and dismisses open forms. // Persists across app restarts. Re-enable with startSession(). await Encatch.stopSession(); ``` 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. ```tsx const { resetUser } = useEncatch(); resetUser(); ``` Wipes **all** persisted SDK data and resets in-memory state. Stronger than `resetUser()` — also clears session-stopped state and device preferences. Call `Encatch.init()` again before further use. ```tsx await Encatch.clearAll(); ``` 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. *** ### Inline Forms [#inline-forms] Inline forms are a way to show Encatch in-app feedback without a modal — the survey renders directly in your layout instead of as a full-screen overlay. `EncatchInlineForm` renders a form directly inside your component tree instead of as a full-screen modal overlay. Place it anywhere — in a `ScrollView`, `View`, card, etc. ```tsx import { EncatchInlineForm, useEncatch } from '@encatch/react-native-sdk'; function FeedbackScreen() { const { showForm } = useEncatch(); return ( {/* ... content above ... */} {/* ... content below ... */} ); } // Then trigger the form from anywhere: showForm('your-form-slug'); ``` When `showForm` is called, the SDK resolves the presenter in this order: 1. **Exact match** — first registered `EncatchInlineForm` whose `formId` matches the payload wins. 2. **Wildcard** — first registered `EncatchInlineForm` with no `formId` catches anything not exact-matched. 3. **Modal fallback** — `EncatchWebView` shows the form as the default overlay when no inline slot is registered or none match. When `@react-navigation/native` is installed, `EncatchInlineForm` registers its inline slot only while the screen is focused (via `useIsFocused`). Background tab screens do not intercept `showForm` calls meant for the modal. If you use a tab navigator that keeps screens mounted in the background, ensure inline slots are on focused screens only. The encatch-expo-tester sample app demonstrates exact and wildcard inline tabs with scroll-into-view when QnA/Scheduler overlays open. When a screen loses focus, its slot is unregistered, so `showForm` falls through to the modal or another active slot. The WebView's internal scroll is disabled. The host `ScrollView` (or `FlatList`) provides scrolling. The widget height grows automatically via `form:resize` messages from the web form. ```tsx ``` The host app controls keyboard avoidance. Use `KeyboardAvoidingView`, `automaticallyAdjustKeyboardInsets`, or scroll-into-view when the keyboard opens — WebView focus is not native, so the SDK does not shrink on keyboard. | Prop | Type | Default | Description | | --------------------- | ------------------------- | ------- | ---------------------------------------------------- | | `formId` | `string` | — | Exact form slug/id to match. Omit for wildcard. | | `style` | `StyleProp` | — | Outer container layout style. | | `minHeight` | `number` | `0` | Minimum height floor applied after `form:resize`. | | `onOverlayOpenChange` | `(open: boolean) => void` | — | Called when a QnA/Scheduler overlay opens or closes. | ### 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 React Native components and submit responses through the SDK. That keeps typography, spacing, colors, and interaction patterns aligned with the rest of your app, so the survey feels like a native screen rather than an embedded web page. Example coming soon. *** | 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 (inline or modal) | | `dismissForm(formConfigurationId?)` | Dismiss the current form | | `addToResponse(questionId, value)` | Pre-fill a question answer | | `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 | | `off(callback)` | Unsubscribe from events | | `submitForm(params)` | Submit a custom native form | | `refineText(params)` | AI text refinement | | `uploadFile(params)` | Upload a file (custom native forms) | | `streamQnaWithAi(params, callbacks)` | Stream Q\&A with AI answers | | `stop()` | Teardown (called by provider on unmount) | Use `useEncatch()` for the same API inside React components. The following are available on the `Encatch` singleton only (not exposed via `useEncatch()`): `init`, `startSession`, `pauseSession`, `resumeSession`, `stopSession`, `clearAll`, `uploadFile`, `streamQnaWithAi`, `stop`. Add usage descriptions to your app's `Info.plist` (or `app.json` for Expo) when forms include video/audio capture: ```xml NSCameraUsageDescription Encatch forms use the camera to record video responses. NSMicrophoneUsageDescription Encatch forms use the microphone to record audio and video responses. ``` Expo `app.json` example: ```json { "expo": { "ios": { "infoPlist": { "NSCameraUsageDescription": "Allow Encatch to capture photos, videos, and signatures for form responses.", "NSMicrophoneUsageDescription": "Allow Encatch to record audio for form responses." } } } } ``` The SDK uses `react-native-webview`, which handles WebView media permission requests once these keys are present. Add permissions to `android/app/src/main/AndroidManifest.xml` (or `app.json` for Expo): ```xml ``` Expo `app.json` example: ```json { "expo": { "android": { "permissions": ["CAMERA", "RECORD_AUDIO", "MODIFY_AUDIO_SETTINGS"] } } } ``` `INTERNET` is required for API calls and the form WebView. The other three permissions are required when forms include video/audio capture questions (`video_audio`). The SDK grants WebView media permission requests automatically, but Android still requires **runtime** approval before the camera or microphone can be used. Request them at startup (Android only): ```tsx import { Camera } from 'expo-camera'; async function requestEncatchMediaPermissions() { const camera = await Camera.requestCameraPermissionsAsync(); const microphone = await Camera.requestMicrophonePermissionsAsync(); if (camera.status !== 'granted' || microphone.status !== 'granted') { // Handle denied permissions — recording questions will not work } } ``` Use [`expo-camera`](https://docs.expo.dev/versions/latest/sdk/camera/) or your preferred permissions library — it is not a dependency of `@encatch/react-native-sdk`. ## Support [#support] * **npm:** [@encatch/react-native-sdk](https://www.npmjs.com/package/@encatch/react-native-sdk) * **Issues:** [github.com/get-encatch/react-native-sdk/issues](https://github.com/get-encatch/react-native-sdk/issues) # Client Reference (/docs/sdk-reference/web) The Encatch Web SDK (`@encatch/web-sdk`) exposes methods to integrate in-app feedback and surveys into your website. Each section below covers one method with sample code you can copy into your project. Before using these methods, [install the SDK](/docs/sdk-reference/web/installation): * [CDN / Script Tag](/docs/sdk-reference/web/installation-methods/cdn-script-tag) * [NPM Package](/docs/sdk-reference/web/installation-methods/npm-package) The npm or CDN package is a **loader stub**. `_encatch.init()` loads the full implementation from `https://form.encatch.com/s/sdk/v1/encatch.js`. Commands sent before that script loads are queued in `_encatch._q` and replayed automatically. Publishable SDK keys belong in client-side code, but restrict them with **Allowed Domains / Packages**. The optional **Secret Key** is for server-side HMAC only — never embed it in your app or commit it to source control. **Publishable SDK key** — [Settings → Security → Publishable SDK Keys](/docs/settings/security/publishable-sdk-keys) with your domain under **Allowed Domains / Packages**. **Form slug or UUID** — **Triggers → Manual Trigger** (slug: 15–100 characters, lowercase letter first, or Feedback Configuration UUID). *** ## Initialize the SDK [#initialize-the-sdk] Call `init()` once with your publishable SDK key. Only the first call runs — duplicate calls log `[Encatch] SDK already initialized. Ignoring init call.` ```javascript import { _encatch } from '@encatch/web-sdk'; _encatch.init('your-publishable-sdk-key'); ``` Optional config: ```javascript _encatch.init('your-publishable-sdk-key', { theme: 'system', // 'light' | 'dark' | 'system' debugMode: false, isFullScreen: false, // full-viewport shareable-style surface webHost: 'https://form.encatch.com', apiBaseUrl: 'https://api.encatch.com', onBeforeShowForm: async (payload) => true, }); ``` | Option | Default | Description | | ------------------ | -------------------------- | ----------------------------------------------------- | | `theme` | `'system'` | Form theme | | `debugMode` | `false` | Log SDK diagnostics to the console (development only) | | `isFullScreen` | `false` | Full-viewport form without modal overlay | | `webHost` | `https://form.encatch.com` | Host for SDK script and form iframes | | `apiBaseUrl` | `https://api.encatch.com` | Encatch API base URL | | `onBeforeShowForm` | — | Return `false` to block the built-in iframe | *** ## Identify & track users [#identify--track-users] Identifying users unlocks targeting, segmentation, and personalized forms. Anonymous mode works, but most apps call `identifyUser()` after login. ### Identify users [#identify-users] Pass a unique `userName` — email, internal ID, or ASCII username (**1–50 chars**: letters, digits, `.`, `_`, `@`, `-` only). ```javascript _encatch.identifyUser('user@example.com'); ``` After a successful `identifyUser()`, Encatch starts a session automatically — you do not need `startSession()` first. ### Import user traits [#import-user-traits] ```javascript _encatch.identifyUser('user@example.com', { $set: { name: 'Alice', plan: 'team' }, $setOnce: { firstSeen: new Date().toISOString() }, $increment: { loginCount: 1 }, $decrement: { credits: 5 }, $unset: ['trialEndDate'], }); ``` | Operation | Description | | --------------------------- | ---------------------------------------- | | `$set` | Set or overwrite attributes | | `$setOnce` | Set only if the attribute does not exist | | `$increment` / `$decrement` | Adjust numeric attributes | | `$unset` | Remove attributes | Store display names with non-ASCII characters as traits (e.g. `$set: { display_name: '…' }`), not as `userName`. ### Verify identity [#verify-identity] Pass a server-generated HMAC signature — never expose your secret key in client code. ```javascript _encatch.identifyUser('user@example.com', undefined, { secure: { signature: 'your-hmac-signature', generatedDateTimeinUTC: '1741867200000', // ms since Unix epoch }, }); ``` Compute `HMAC-SHA256(userName + epochMs, secretKey)` on your server when the publishable key has **Session time (minutes)** configured. Without session time, sign `userName` only. ### Reset users [#reset-users] Clear user identity after logout. In SPAs, call this when the user signs out. ```javascript _encatch.resetUser(); ``` User identity is preserved across `stopSession()` — use `resetUser()` on logout. *** ## Show and hide forms [#show-and-hide-forms] Use [Manual Trigger](/docs/feedback-management/targeting-and-triggers/triggers/manual-trigger) to launch forms from your app code. ### Show form [#show-form] ```javascript _encatch.showForm('customer-satisfaction-survey-2024'); _encatch.showForm('customer-satisfaction-survey-2024', { reset: 'always', // 'always' | 'on-complete' | 'never' selector: '#feedback-slot', // inline host element context: { plan: 'team' }, // attached to submission; use as context.* in logic jumps }); ``` | `reset` | Behavior | | --------------- | ----------------------------------------- | | `'always'` | Clear staged data on every show (default) | | `'on-complete'` | Clear only after completion | | `'never'` | Keep response data | Dashboard trigger rules still apply — a user who already completed the form may not see it again unless your targeting allows it. ### Full-screen and inline placement [#full-screen-and-inline-placement] **Full-screen** — set `isFullScreen: true` at `init()` for a full-viewport shareable-style surface: ```javascript _encatch.init('your-publishable-sdk-key', { isFullScreen: true }); _encatch.showForm('customer-satisfaction-survey-2024'); ``` **Inline** — mount inside a host element with `selector`, or use `
` (optionally `data-encatch-form-id="your-form-slug-or-uuid"`). Falls back to modal when no host matches at show time. ```javascript _encatch.showForm('customer-satisfaction-survey-2024', { selector: '#feedback-slot' }); ``` `isFullScreen` and inline placement are mutually exclusive. In **full-screen mode**, `trackEvent()`, `trackScreen()`, and background ping are disabled — use modal or inline placement when you need session tracking or automatic triggers. *** ## Other actions [#other-actions] ### Locale [#locale] Set the user's preferred language as comma-separated ISO 639-1 codes. Call before `identifyUser()` when possible. ```javascript _encatch.setLocale('fr'); _encatch.setLocale('fr,en,es'); ``` Or pass `locale` in `identifyUser` options: ```javascript _encatch.identifyUser('user@example.com', undefined, { locale: 'fr' }); ``` ### Country [#country] Set a two-letter ISO 3166 country code for country targeting. ```javascript _encatch.setCountry('FR'); ``` Or pass `country` in `identifyUser` options: ```javascript _encatch.identifyUser('user@example.com', undefined, { country: 'FR' }); ``` ### Theme [#theme] Override the theme set at `init()`: ```javascript _encatch.setTheme('dark'); // 'light' | 'dark' | 'system' ``` ### Track events [#track-events] Track custom events for [automatic triggers](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger). Requires a device id from `startSession()` or successful `identifyUser()` — otherwise the call is a no-op. ```javascript _encatch.trackEvent('button_clicked'); ``` Encatch records event occurrence only — attributes cannot be attached to events. ### Track screens [#track-screens] Track page or screen views. With an active session, SPA navigations (`pushState`, `replaceState`, `popstate`) call `trackScreen` with the full page URL automatically. ```javascript _encatch.trackScreen('Dashboard'); ``` Requires a device id from `startSession()` or successful `identifyUser()` — otherwise the call is a no-op. ### Source tracking [#source-tracking] Merge UTM or campaign params into the in-memory source tracking store (web SDK only). Values override URL query params on key collision. Persists for the page session. ```javascript _encatch.addSourceTracking({ utm_campaign: 'spring-sale' }); _encatch.showForm('customer-satisfaction-survey-2024'); ``` On each `showForm()`, Encatch merges URL query params with `addSourceTracking()` values. Filtered keys are auto-injected into `submitForm` for custom UIs. ### Listen to form events [#listen-to-form-events] Subscribe with `_encatch.on()`. Returns an unsubscribe function. ```javascript const unsubscribe = _encatch.on((eventType, payload) => { console.log(eventType, payload.formId, payload.data); }); unsubscribe(); ``` | Event | When it fires | | --------------------- | -------------------------------------------- | | `form:show` | Form displayed | | `form:started` | User starts interacting | | `form:submit` | Form submitted | | `form:complete` | Form fully completed | | `form:close` | Form closed | | `form:dismissed` | Dismissed without completion | | `form:error` | Error occurred | | `form:section:change` | Section changed | | `form:answered` | Question answered | | `form:remindmelater` | "Remind me later" tapped (hides iframe only) | | `form:ctaTriggered` | Completion CTA on thank-you or exit screen | For `form:ctaTriggered`, handle `app_navigate` in your app — the SDK closes the form after emitting the event. `redirect_internal` and `redirect_external` are handled by the SDK. See [Call to action](/docs/feedback-management/form-builder/call-to-action). ```javascript _encatch.on((eventType, payload) => { if (eventType !== 'form:ctaTriggered') return; if (payload.data?.action === 'app_navigate') { router.push(payload.data.route); } }); ``` ### Pre-fill responses [#pre-fill-responses] Stage answers with `addToResponse()` before `showForm()`. Pass the question UUID or slug and the raw answer value (pass `5` for a rating, not `{ rating: 5 }`). ```javascript _encatch.addToResponse('email_question', 'user@example.com'); _encatch.addToResponse('nps_question', 10); _encatch.showForm('customer-satisfaction-survey-2024'); ``` Staged values apply on the next `showForm()`, or immediately if a form iframe is already open. Works for **22 of 27** question types — use option **Value** / data identifier from the form builder, not the label. Test in the builder via [logic jumps](/docs/feedback-management/form-builder/logic-jumps#test-logic-jumps). Not supported: signature, file upload, video/audio/photo, scheduler, Q\&A with AI. ### Dismiss form [#dismiss-form] Close the visible form and report dismissal to the Encatch API. ```javascript _encatch.dismissForm(); _encatch.dismissForm('feedback-configuration-uuid'); ``` Safe to call when no form is visible — it has no effect. ### Form interceptor [#form-interceptor] Return `false` from `onBeforeShowForm` to block the built-in iframe and render your own UI. Staged `addToResponse()` values are cleared when `false` is returned. ```javascript _encatch.init('your-publishable-sdk-key', { onBeforeShowForm: async (payload) => { // payload.formId, payload.formConfig, payload.triggerType, // payload.resetMode, payload.prefillResponses, payload.context if (payload.triggerType === 'automatic' && shouldBlock) return false; return true; }, }); ``` | Payload field | Description | | ------------------ | ----------------------------------------- | | `formId` | Form slug or Feedback Configuration UUID | | `formConfig` | Show-form API response | | `triggerType` | `'manual'` or `'automatic'` | | `resetMode` | `'always'`, `'on-complete'`, or `'never'` | | `prefillResponses` | Values from `addToResponse()` | | `context` | Serialized `showForm` context | ### Session [#session] Control the session lifecycle. Session ids use a **24-hour rolling expiry**. ```javascript _encatch.startSession(); _encatch.startSession({ skipImmediatePing: true, // skip first ping; 30s interval still runs skipImmediateTrackScreen: true, // skip initial trackScreen (default: true) }); ``` ```javascript _encatch.pauseSession(); // pause background ping (not persisted) _encatch.resumeSession(); // resume ping _encatch.stopSession(); // stop ping, URL listeners, dismiss open forms (persists across reloads) _encatch.clearAll(); // wipe all persisted SDK data and reset in-memory state ``` | Method | Effect | | ------------------------------------ | --------------------------------------------------------------------------------------------------- | | `startSession()` | New session id; starts 30s ping interval and URL listeners | | `pauseSession()` / `resumeSession()` | Temporarily pause/resume ping only | | `stopSession()` | Full suspension; identity preserved; re-enable with `startSession()` | | `resetUser()` | Clear user identity (use on logout) | | `clearAll()` | Full reset — stronger than `resetUser()`; tracking stops until `startSession()` or `identifyUser()` | The SDK pings every \~30 seconds to maintain sessions and check for triggered forms. Ping is suppressed while a form is visible. If a prior session or user exists in browser storage, Encatch restores identifiers on load and may restart the session unless it was explicitly stopped. *** ## Advanced options [#advanced-options] ### Build your own form UI [#build-your-own-form-ui] For fixed, predictable question sets, build your own HTML/CSS/JS and submit via `submitForm()`, `emitEvent()`, `refineText()`, `uploadFile()`, and `qnaWithAi()`. Use `onBeforeShowForm` returning `false` to skip the built-in iframe. ### Content Security Policy [#content-security-policy] Whitelist Encatch hosts in your CSP headers. **NPM:** ```http script-src 'self' https://form.encatch.com; connect-src 'self' https://api.encatch.com; frame-src 'self' https://form.encatch.com; ``` **CDN / script tag** — also allow `https://cdn.jsdelivr.net` in `script-src`. If you set custom `webHost` or `apiBaseUrl`, whitelist those hosts instead. *** ## Troubleshooting [#troubleshooting] Forms not appearing? API calls failing silently? See [Troubleshoot](/docs/sdk-reference/web/troubleshoot) for debug mode, console diagnostics, and step-by-step fixes. *** ## API quick reference [#api-quick-reference] | Method | Description | | ------------------------------------------- | ----------------------------------------------------------------------------------------- | | `init(apiKey, config?)` | Initialize with publishable SDK key | | `identifyUser(userName, traits?, options?)` | Identify a user | | `setLocale(locale)` | Set locale (ISO 639-1, comma-separated) | | `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 (modal, inline, or full-screen) | | `dismissForm(formConfigurationId?)` | Dismiss the current form | | `addToResponse(questionId, value)` | Pre-fill a question (22 of 27 types) | | `addSourceTracking(values)` | Merge source tracking params | | `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 | | `init(..., { debugMode: true })` | Enable console diagnostic logs — see [Troubleshoot](/docs/sdk-reference/web/troubleshoot) | | `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 | # Installation (/docs/sdk-reference/web/installation) Before you can collect in-app feedback with Encatch, install the **Encatch Web SDK** (`@encatch/web-sdk`) on your site once. After that, create and configure feedback forms, targeting rules, and [automatic triggers](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger) in the Encatch dashboard without redeploying your app. Publishable SDK keys are designed for client-side use — protect them with **Allowed Domains / Packages**. The optional **Secret Key** for HMAC `identifyUser` signatures is server-side only; never ship it in browser code. Both installation methods ship a **loader stub** (`dist/encatch.iife.js` from CDN or `dist/encatch.es.js` from npm). When you call `_encatch.init('your-publishable-sdk-key')`, Encatch injects the full implementation from `https://form.encatch.com/s/sdk/v1/encatch.js` as a module script. API requests go to `https://api.encatch.com` by default. Commands sent before that remote script finishes loading are **queued** in `_q` and replayed when the implementation loads. *** ## What you need from the Encatch dashboard [#what-you-need-from-the-encatch-dashboard] 1. **Publishable SDK key** — **Settings → Security → [Publishable SDK Keys](/docs/settings/security/publishable-sdk-keys)** → **Create Publishable SDK Key**. Copy **Your Publishable SDK Key** when shown — Encatch displays the full key only once at creation. 2. **Allowed Domains / Packages** — On that key, add your site origin (for example `https://app.example.com`). Up to **10** entries per key (each up to 100 characters). Avoid `*` in production. 3. **Form slug or UUID** — Open your feedback form → **Triggers → Manual Trigger**. Use the **Form Slug** or **Feedback Configuration UUID** in `showForm()`. 4. **Targeting (optional)** — Configure [in-app targeting](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback) and [triggers](/docs/feedback-management/targeting-and-triggers/triggers) for automatic launches. ### Locate your publishable SDK key [#locate-your-publishable-sdk-key] In the Encatch dashboard (**Settings → Security → Publishable SDK Keys**): 1. Open your Encatch project. 2. Click **Create Publishable SDK Key** (or select an existing key under the **Active keys** tab). 3. Fill in **Basic Information** — **Key Name** and **Application Name / Identifier** (each max 25 characters). 4. Expand **Access Configuration** — set **Expiry Period** and **Allowed Domains / Packages** (required). 5. Optionally expand **Security Configuration** — **Secret Key** (server-side only, for HMAC `identifyUser` signatures) and **Session time (minutes)**. Copy **Your Publishable SDK Key** on the confirmation step, then click **Close**. See [Publishable SDK Keys](/docs/settings/security/publishable-sdk-keys). Pass the key to `_encatch.init('your-publishable-sdk-key')`. Only the **first** `init()` call runs — Encatch logs `[Encatch] SDK already initialized. Ignoring init call.` on duplicate calls. *** ## Installation options [#installation-options] Encatch supports two ways to load `@encatch/web-sdk`: Both methods expose the same `_encatch` API — modal form iframes, user identification, `trackScreen` / `trackEvent`, session management, and [source tracking](/docs/sdk-reference/web#source-tracking). Complete setup in one of the method guides below, then use the sections on this page for identify, launch, and troubleshooting. ### Minimal init (either method) [#minimal-init-either-method] ```javascript _encatch.init('your-publishable-sdk-key'); _encatch.startSession(); _encatch.showForm('your-form-slug-or-uuid'); ``` **Form Slug** (from **Triggers → Manual Trigger**) must be **15–100 characters**, start with a lowercase letter, and use only `a–z`, `0–9`, `-`, and `_`. Alternatively pass the **Feedback Configuration UUID** from the same screen. After a successful `identifyUser()`, Encatch calls `startSession()` internally — you do not need `startSession()` before identify. *** ## Identify users [#identify-users] Encatch uses identified users for [in-app targeting](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback), [manual segments](/docs/segmentation/manual), [user traits](/docs/settings/user-data/user-traits), and response attribution. Call `identifyUser` after `init()`: ```javascript _encatch.identifyUser('user@example.com', { $set: { name: 'Alice', plan: 'team' }, }); ``` `userName` must match Encatch server validation: **1–50 characters**, only letters, digits, and `.`, `_`, `@`, `-`. On success, Encatch starts a session automatically. Method-specific examples: * [Identify users with CDN / Script Tag](/docs/sdk-reference/web/installation-methods/cdn-script-tag#identify-users) * [Identify users with NPM Package](/docs/sdk-reference/web/installation-methods/npm-package#identify-users) For `$set`, `$setOnce`, `$increment`, secure HMAC signatures (optional **Secret Key** on the publishable SDK key), and full rules, see [Identify & track users](/docs/sdk-reference/web#identify--track-users). *** ## Launch feedback forms [#launch-feedback-forms] **Manual launch** — `showForm()` with the slug or UUID from **Triggers → Manual Trigger**: ```javascript _encatch.showForm('your-form-slug-or-uuid'); _encatch.showForm('your-form-slug-or-uuid', { reset: 'always', context: { plan: 'team', feature: 'checkout' }, }); ``` **Automatic launch** — enable an [Automatic Trigger](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger) in the dashboard. The SDK evaluates launch rules (page visit, tracked event, delay, and more) without a manual `showForm()` call. Subscribe to lifecycle events with `_encatch.on()` — for example `form:show`, `form:submit`, `form:complete`, `form:ctaTriggered`. See [Client Reference](/docs/sdk-reference/web) for all event types. *** ## Track pages and events [#track-pages-and-events] ```javascript _encatch.trackScreen('Dashboard'); _encatch.trackEvent('checkout_completed'); ``` Both calls are **no-ops until a device id exists** — establish one with `startSession()` or a successful `identifyUser()` first. With an active session, SPA navigations (`pushState`, `replaceState`, `popstate`) also trigger `trackScreen` with the full page URL. Merge UTM and campaign params with `addSourceTracking()` before `showForm()` — see [source tracking](/docs/sdk-reference/web#source-tracking). *** ## Troubleshoot installation [#troubleshoot-installation] If Encatch forms do not appear or API calls fail: 1. **Publishable key** — Value in `init()` must match an **Active** key (**Settings → Security → Publishable SDK Keys** → **Active keys** tab). Check the key is not **Expired**, **Deleted**, or **Inactive** (shown in **Info and Actions** on the key row). 2. **Allowed Domains / Packages** — Page origin must match an entry on that key (for example `https://your-app.com`). Avoid `*` in production. 3. **Form published** — Publish the feedback form in the dashboard before testing. Slug must pass validation (15–100 chars, rules above) or use the configuration UUID. 4. **Client-side only** — Call `init()` in the browser after `window` is available (not during SSR). See [NPM Package — Next.js](/docs/sdk-reference/web/installation-methods/npm-package#nextjs). 5. **Init timing** — Call `init()` early. Encatch queues calls until `form.encatch.com/s/sdk/v1/encatch.js` loads. 6. **Content Security Policy** — Allow `form.encatch.com` and `api.encatch.com`; add `cdn.jsdelivr.net` only for [CDN / Script Tag](/docs/sdk-reference/web/installation-methods/cdn-script-tag). See [Content Security Policy](/docs/sdk-reference/web#content-security-policy). 7. **Session stopped** — After `stopSession()`, call `startSession()` or `identifyUser()` again. `stopSession()` persists across reloads until you restart tracking. 8. **Silent tracking** — `trackEvent` / `trackScreen` do nothing (no error) if no device id exists yet — call `startSession()` or `identifyUser()` first. Step-by-step setup: [CDN / Script Tag](/docs/sdk-reference/web/installation-methods/cdn-script-tag) · [NPM Package](/docs/sdk-reference/web/installation-methods/npm-package) *** ## Rate limits [#rate-limits] When using the **Encatch Web SDK** to track user data and collect feedback responses, these limits apply to **production** projects: | Limit scope | Requests per minute | | --------------------- | ------------------- | | Per project | 40,000 | | Per contact / user ID | 100 | | Per IP address | 300 | [Sandbox projects](/docs/sandbox-limits/rate-limits) use **50 / 10 / 50** per minute (project / contact / IP). Encatch returns `429 Too Many Requests` when exceeded, with `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` on API responses. See [SDK Rate Limits](/docs/sandbox-limits/rate-limits). *** ## Next steps [#next-steps] * [Client Reference](/docs/sdk-reference/web) — full `_encatch` API (`addToResponse`, themes, session control, custom form UX) * [Troubleshoot](/docs/sdk-reference/web/troubleshoot) — debug mode, console logs, and common fixes when forms do not appear * [CDN / Script Tag](/docs/sdk-reference/web/installation-methods/cdn-script-tag) · [NPM Package](/docs/sdk-reference/web/installation-methods/npm-package) — detailed install and init * [Build a feedback form](/docs/feedback-management/form-builder/build-feedback-form) * [Automatic Trigger](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger) — launch forms from dashboard rules without code changes # Troubleshoot (/docs/sdk-reference/web/troubleshoot) The Encatch Web SDK includes a built-in **Debug Mode** to help you track down installation, targeting, and form-display issues. When activated, the SDK writes diagnostic messages to your browser console so you can see whether the client loaded, whether users are identified, and whether API calls succeed. For publishable key, allowed domains, CSP, and init timing, see [Troubleshoot installation](/docs/sdk-reference/web/installation#troubleshoot-installation). Enable `debugMode` only in local or staging environments — console output can include SDK and user state. When sharing logs with support, redact `X-Api-Key` and `X-User-Signature` from Network screenshots. The optional **Secret Key** on a publishable SDK key is for server-side HMAC only — never ship it in client code. *** ## Debug Mode [#debug-mode] When Debug Mode is on, Encatch emits extra `console.warn` messages prefixed with `[Encatch]`, `[IFRAME-MANAGER]`, `[EVENT-HANDLER]`, or `[Encatch API]`. Use these logs together with the checks in [Debug Panel](#debug-panel) below to confirm your installation is healthy. Encatch does **not** show a floating on-page debug overlay. Inspect state in DevTools and subscribe to form events with `_encatch.on()` instead. ### Activate Debug Mode [#activate-debug-mode] The simplest way to enable Debug Mode is to pass `debugMode: true` when you call `init()`: ```javascript import { _encatch } from '@encatch/web-sdk'; _encatch.init('your-publishable-sdk-key', { debugMode: true, }); ``` CDN / script tag: ```html ``` You can also enable Debug Mode from the browser console **after** `init()` has run on the current page: ```javascript window._encatch._config.debugMode = true; ``` Debug Mode stays active for the rest of that **page session** (until you reload or close the tab). It is useful while debugging SPA navigation or [automatic triggers](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger) on the same page. After a full page reload, pass `debugMode: true` in `init()` again — a console toggle does not persist across reloads. To disable Debug Mode on the current page: ```javascript window._encatch._config.debugMode = false; ``` Or pass `debugMode: false` (the default) on your **first** `init()` call when the page loads. A second `init()` is ignored — Encatch logs `[Encatch] SDK already initialized. Ignoring init call.` and does not change config. Unlike some other SDKs, Encatch does not support a `?debug=true` URL flag. Pass `debugMode: true` in `init()` or toggle `window._encatch._config.debugMode` in the console. ### Debug Panel [#debug-panel] Encatch does not render a visual debug panel in the corner of the browser. Use the following DevTools checks as your debug panel — they tell you whether the client installed correctly, whether you are identifying users, and whether the remote SDK loaded. **1. Confirm the SDK is on the page** ```javascript typeof window._encatch // Expected: "object" ``` **2. Confirm `init()` ran** ```javascript window._encatch._initialized // Expected: true ``` **3. Check identification mode** ```javascript localStorage.getItem('encatch_user_name') // null → anonymous (Visitors targeting) // non-null string → identified after a successful identifyUser() (Logged-in Users targeting) ``` **4. Subscribe to form lifecycle events** ```javascript const off = _encatch.on((eventType, payload) => { console.log('[Encatch event]', eventType, payload); }); // Later: off(); ``` **5. Confirm the remote SDK script loaded** After `init()`, Encatch injects `https://form.encatch.com/s/sdk/v1/encatch.js`. In **Network**, filter for `encatch.js` and confirm status **200**. If checks 1–2 pass but no requests reach `api.encatch.com`, reload the page and try again. If it still fails, see [Debug Tip #1](#debug-tip-1-check-if-sdk-is-loaded) below. ### Debug Logs [#debug-logs] In addition to the checks above, enabling Debug Mode generates detailed logs in the browser console. Open **Developer Tools → Console**: | Browser | Windows / Linux | macOS | | ------------- | ------------------ | ---------------- | | Chrome / Edge | `Ctrl + Shift + J` | `Option + ⌘ + J` | | Firefox | `Ctrl + Shift + K` | `Option + ⌘ + K` | Filter by `Encatch` to narrow results. **What Debug Mode logs** | Prefix | Typical topics | | ------------------ | ---------------------------------------------------- | | `[Encatch]` | Selectors, localStorage, session restore, API errors | | `[IFRAME-MANAGER]` | Form iframe messaging and visibility | | `[EVENT-HANDLER]` | Form iframe postMessage handling | | `[Encatch API]` | User ID persistence | **Messages that can appear even when Debug Mode is off** | Message | When | | -------------------------------------------------------- | ----------------------------------------- | | `[Encatch] SDK already initialized. Ignoring init call.` | Second `init()` call (loader stub) | | `[Encatch] Failed to initialize SDK:` | Loader stub when remote script load fails | | `[Encatch] Failed to load SDK from …` | Script `onerror` in the loader | | `[SDK] showForm requires a formId` | `showForm()` called without an ID | | `[SDK] show-form API error:` | Show-form request failed | When contacting support, a screenshot of the Console and Network tabs is helpful — redact `X-Api-Key` and any signature headers first. *** ## Troubleshooting Tips [#troubleshooting-tips] ### Debug Tip #1: Check if SDK is loaded [#debug-tip-1-check-if-sdk-is-loaded] If forms do not appear and you see no Encatch logs, the client was most likely not loaded into your page. Open the **Elements** tab in Developer Tools and search for `encatch`. With the [CDN / Script Tag](/docs/sdk-reference/web/installation-methods/cdn-script-tag) method you should see a jsDelivr script tag. With the [NPM Package](/docs/sdk-reference/web/installation-methods/npm-package) method, the stub is bundled into your app JavaScript. In the **Console**, confirm: ```javascript window._encatch?._initialized === true ``` If this is `false` or `window._encatch` is `undefined`, verify your install steps and that `init()` runs in the browser — not during server-side rendering. *** ### Debug Tip #2: Test with a newly opened Incognito Window [#debug-tip-2-test-with-a-newly-opened-incognito-window] The Encatch Web SDK uses **localStorage** to persist device IDs, session state, and user identity between page loads. That cached state can affect whether a form shows again after you change targeting or throttling in the dashboard. Always test Encatch in a **newly opened Incognito / Private window** when debugging targeting or throttling. Alternatively, call `_encatch.clearAll()` in the console (see [Debug Tip #4](#debug-tip-4-reset-user-data-in-your-account-to-start-over)). *** ### Debug Tip #3: Check if you are using the audience type [#debug-tip-3-check-if-you-are-using-the-audience-type] The Web SDK runs in one of two modes: | Mode | How it is set | Dashboard targeting | | -------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Anonymous** | No `encatch_user_name` in localStorage (or after `resetUser()`) | Enable [Visitors](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/visitors) | | **Identified** | Successful `identifyUser()` stores `encatch_user_name` | Enable [Logged-in Users](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/logged-in-users) (and optional [segments](/docs/segmentation/overview)) | When you can identify your users in code, **Logged-in Users** is the right audience choice. When you cannot identify users — for example on a marketing site — enable **Visitors**. Check your current mode in the console: ```javascript localStorage.getItem('encatch_user_name') ``` Also review [country](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/country), [device type](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/device-type), [user language](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/user-language), and [past interaction](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/past-interaction) — any of these can prevent a form from launching. *** ### Debug Tip #4: Reset user data in your account to start over [#debug-tip-4-reset-user-data-in-your-account-to-start-over] You will often want to test a feedback form again after you already completed or dismissed it. Dashboard rules such as [throttling](/docs/feedback-management/advanced-options/throttling), [response limit](/docs/feedback-management/advanced-options/response-limit), and [past interaction](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/past-interaction) can block repeat views. You have two ways to start with a blank slate: **1. Reset in the browser (fastest for local testing)** ```javascript _encatch.clearAll(); ``` This wipes persisted SDK data and stops background ping. Call `startSession()` or `identifyUser()` before testing [automatic triggers](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger) again. For logout flows — clear identity but keep the device: ```javascript _encatch.resetUser(); ``` **2. Reset in the Encatch dashboard** * Remove or filter out test responses in **Reports** for that form, or * Relax throttling and past-interaction rules while testing. In both cases, open a **new Incognito window** for further testing so no old browser state remains. *** ### Debug Tip #5: Inspect network tab [#debug-tip-5-inspect-network-tab] Use Developer Tools → **Network** to inspect communication between your browser and Encatch servers. Set the filter to **Fetch/XHR** and search for `encatch` or `api.encatch.com`. You should see requests such as: | Request | When it fires | | --------------- | -------------------------------------------------------------------------- | | `identify-user` | After `identifyUser()` | | `track-screen` | After `trackScreen()`, or on SPA navigation when a session is active | | `track-event` | After `trackEvent()` | | `ping` | After `startSession()` or successful `identifyUser()` (\~every 30 seconds) | | `show-form` | When a form is displayed | | `dismiss-form` | When a form is dismissed | The remote SDK script loads separately as a module script (not XHR): `https://form.encatch.com/s/sdk/v1/encatch.js` after `init()`. Successful responses return **200** or **201**. Encatch returns **429** when [rate limits](/docs/sandbox-limits/rate-limits) are exceeded. If any request returns a **4xx** or **5xx** error, click it and read the response body. For key, domain, session, and CSP issues, work through [Troubleshoot installation](/docs/sdk-reference/web/installation#troubleshoot-installation). `trackEvent()` and `trackScreen()` send **no request** until a device ID exists — call `startSession()` or `identifyUser()` first. This is expected behavior. When contacting support, capture the status code and response body. Redact `X-Api-Key` and signature headers before sharing. *** ## Related [#related] * [Installation — Troubleshoot installation](/docs/sdk-reference/web/installation#troubleshoot-installation) * [Client Reference](/docs/sdk-reference/web) — `clearAll()`, `resetUser()`, session control, event subscriptions * [Content Security Policy](/docs/sdk-reference/web#content-security-policy) * [Targeting](/docs/feedback-management/targeting-and-triggers/targeting) # AI Topics (/docs/settings/global-settings/ai-topics) **AI Topics** helps you organize open-text feedback across your project. You set up **groups** and **topics** here—the AI handles the rest. When people leave written answers, it finds **aspects** (specific things they mention), maps them to your setup, and uses that for sentiment, summary reports, and Feedback Studio. ## Where to find it [#where-to-find-it] 1. Open your project in the encatch dashboard. 2. Go to **Settings**. 3. Under **Global Settings**, open **AI Topics**. Don't see **AI Topics**? Ask your organization admin—you might need access, or the feature may not be turned on for your environment yet. **Page description:** Create groups, organize topics, and control which group each topic belongs to. Aspects are managed automatically by the system. ## How it fits together [#how-it-fits-together] Think of AI Topics in three layers: | Level | Who sets it up | What it's for | | ---------- | -------------- | ------------------------------------------------------------------------------ | | **Group** | You | Big themes—like Product, Support, or Billing. | | **Topic** | You | Smaller themes inside a group—like Checkout or Onboarding. | | **Aspect** | AI | Specific things people actually say—like "slow loading" or "confusing layout". | You only manage groups and topics on this page. Aspects show up on their own when the AI reads responses—you don't create or edit them here. ## What you'll see on the page [#what-youll-see-on-the-page] Groups are listed in expandable sections. Each header shows the group name and how many topics are inside. * **Group** — Add a new top-level group. * **+** (on a group row) — Add a topic to that group. * **Pencil** (on a group or topic) — Edit the name or description. If you haven't created anything yet, you'll see **No groups yet** and a **Create group** button to get started. ### Uncategorized [#uncategorized] **Uncategorized** is a built-in group for topics that aren't in a custom group yet. New topics with no group land here, and topics you move out of a group end up here too. Drag them into the right group whenever you're ready—or leave them here if that works for you. ## Create or edit a group [#create-or-edit-a-group] 1. Click **Group**, the **+** on a group row, or **Create group** if you're starting from scratch. 2. Fill in the dialog: * **Name** (required) — What you want to call this group. * **Description** (optional) — A short note about what belongs here. It shows under the group name and helps the AI sort responses into the right place. 3. Click **Save**. ## Create or edit a topic [#create-or-edit-a-topic] 1. Click **+** on the group where the topic should go (including **Uncategorized**). 2. In the **Add topic** dialog: * **Name** (required) — What you want to call this topic. * **Description** (optional) — Shows under the topic on each card. You can write up to **8,000** characters. 3. Click **Save**. When responses are analyzed, the AI attaches aspects to your topics automatically. ## Move topics between groups [#move-topics-between-groups] Grab a topic by the handle on the left and drag it to another group. You can drop it on other topics or on an empty area that says **Drop topics here**. After you move things around, a bar appears at the bottom: * **Discard** — Undo your moves and go back to the last saved layout. * **Save changes** — Keep the new arrangement. Names and descriptions save right away when you edit them in a dialog. Only drag-and-drop moves need **Save changes**. ## User and AI badges [#user-and-ai-badges] Some topics show a small badge for how they were created: | Badge | Meaning | | -------- | ------------------------------------------------ | | **User** | Someone on your team added it. | | **AI** | The system created it while analyzing responses. | Either way, you can rename topics and move them between groups like any other. ## Where your setup shows up [#where-your-setup-shows-up] Once groups and topics are in place, they feed into AI analysis across the project. ### AI text insights on text questions [#ai-text-insights-on-text-questions] In the form builder, turn on **AI text insights** for **long answer** or **short answer** questions. The summary report then includes: * **Aspects & sentiment** — Maps answers to your AI Topics. Each aspect gets a sentiment score and a salience score (basically, how much that aspect stands out). Salience also affects overall sentiment in summaries and per-response views. * **Word cloud** — A quick view of the words that come up most often. You can optionally pick **Groups** on the question to limit aspects & sentiment to certain groups only. Those groups are the ones you set up here. Each time analysis runs, it uses **1 AI Credit**. ### Feedback Studio [#feedback-studio] Open **Feedback Studio → AI Topic intelligence** to browse groups, topics, and aspects for the whole project—how often they're mentioned, how people feel, and the responses behind them. ### Summary report [#summary-report] Each text question's summary uses the same setup, filtered by your date range and any group filters on that question. ## Who can use this [#who-can-use-this] What you can do depends on your role. Some people can view groups and topics only; others can create, edit, and move them. If AI Topics isn't enabled in your environment, the page shows **Feature unavailable** instead of the settings. ## Tips [#tips] * Start small—pick a few groups that match how your team already talks about feedback (product areas, journeys, teams). * Add descriptions where you can. They really help the AI place free-text answers in the right spot. * Check **Uncategorized** now and then and drag stray topics where they belong. * On text questions, leave **Groups** empty to use everything, or tick specific groups to narrow the analysis. ## Best practices [#best-practices] * Use clear, consistent names so reports and Feedback Studio are easy to scan. * Try not to duplicate the same theme in multiple groups—it splits your numbers. * If you've moved topics around, hit **Save changes** before you leave the page. # Experiments (/docs/settings/global-settings/experiments) **Experiments** let you define A/B/N rollout groups for your project. Each experiment has variants with named percentile ranges so you can control how users are bucketed—for example a control group and one or more test groups. ## Where to find it [#where-to-find-it] 1. Open your project in the encatch dashboard. 2. Go to **Settings**. 3. Under **Global Settings**, open **Experiments**. If you do not see **Experiments**, contact your organization administrator—you may need additional access. **Page description:** Configure A/B/N rollout. Define variants with named percentile ranges to control feature rollouts. ## Experiments list [#experiments-list] The left panel shows all experiments in the project and how many exist. Select an experiment to edit it on the right, or create a new one. * **New Experiment** / **Create Experiment** — Opens the create dialog (subject to your plan’s experiment limit). * If the list is empty, you see **No experiments yet** with a prompt to create your first experiment for A/B/N rollouts. * When nothing is selected on the right, the page prompts you to **Select an experiment from the list or create your first experiment**. Each list item shows the experiment **name** and **slug**. If you reach your plan’s experiment limit, you will see **Experiments limit reached** and need to upgrade before creating more. ## Create an experiment [#create-an-experiment] 1. Click **New Experiment** or **Create Experiment**. 2. In the **Create Experiment** dialog, fill in: * **Slug** (required) — Lowercase letters, numbers, and underscores only. Cannot be changed after creation. * **Name** (optional) — Display name. * **Description** (optional). 3. Click **Create**. You are taken to the experiment detail view to configure variants and ranges. ## Experiment details [#experiment-details] After selecting an experiment, the **Experiment Details** panel includes: | Field | Description | | --------------- | ------------------------------------ | | **Slug** | Read-only system identifier. | | **Name** | Editable display name. | | **Description** | Optional notes about the experiment. | Click **Save** to apply changes to name, description, and variants. Use the **⋮** menu for: * **Details** — View name, description, variant summary, created/updated timestamps, and who created or last updated the experiment. * **Delete experiment** — Permanently remove the experiment (cannot be undone). If the experiment is in use as an active master reference, you may see a notice that editing this document does not automatically change live feedback—you need to update the experiment in **Advanced Options** on the relevant form for changes to take effect there. ## Variants and ranges [#variants-and-ranges] Under **Variants & Ranges**, define how users are split (up to **10 variants** per experiment). 1. Click **Add Variant** to add a variant group. 2. For each variant, set: * **Variant name** — e.g. Default, Variant A. * **Ranges** — One or more named slices with **start** and **end** percentages (0–100). Use **Add Range** inside a variant to add another range row. Each range has a name (e.g. Control, Test) and a percent band such as `0`–`50` and `50`–`100`. Ranges within a variant must: * Start at **0%** for the first range. * Be **contiguous** (no gaps or overlaps between ranges). * Have start less than end, and end not above **100%**. * Cover up to 100% total (partial coverage such as 0–50% only is allowed). If validation fails, an error message appears before you can save—for example missing ranges, overlapping bands, or end above 100%. Use **Remove variant** or the trash icon on a range row to delete items you no longer need. ## Typical workflow [#typical-workflow] 1. Create an experiment with a stable **slug**. 2. Add variants and percentile ranges that match your rollout design. 3. **Save** the experiment. 4. Attach the experiment in feedback **Advanced Options** where you want A/B/N behavior (update there when you change variant definitions used in production). ## Best practices [#best-practices] * Use clear slugs (e.g. `checkout_rollout_v1`) and do not change them after the experiment is referenced elsewhere. * Keep range names meaningful (Control, Treatment A) so reports and targeting are easy to understand. * Start with two variants and two contiguous ranges (e.g. 0–50% and 50–100%) for a simple A/B split. # Global Throttling (/docs/settings/global-settings/global-throttling) **Global Throttling** lets you limit how often feedback forms can be shown and submitted. Use it to reduce survey fatigue, protect response quality, and cap usage of AI-powered **Refine text** on long-answer fields. ## Where to find it [#where-to-find-it] 1. Open your project in the encatch dashboard. 2. Go to **Settings**. 3. Under **Global Settings**, open **Global Throttling**. If you do not see **Global Throttling**, contact your organization administrator—you may need additional access. **Page description:** Configure throttling settings to control feedback views and responses globally, per user, or per feedback. ## Save your changes [#save-your-changes] After editing any section, click **Save settings** to apply. Use **Reset** to discard unsaved changes and restore the last saved values. You will see a confirmation when settings are saved successfully. On plans where throttling is not included, the **Throttle globally**, **Throttle per user**, and **Throttle per feedback** cards show as locked. Upgrade your plan to configure those limits. **Throttle AI Refine Text** remains available to configure. ## Throttle globally [#throttle-globally] Limits apply across the whole project for the selected time window. Turn the section **Enabled**, then set: | Setting | Description | | --------------------------- | --------------------------------------------------------------- | | **Time frame** | Rolling window for the limits (from 15 minutes up to 365 days). | | **Max. views** | Maximum number of feedback form views allowed in that window. | | **Max. feedback responses** | Maximum number of feedback submissions allowed in that window. | **Apply these limits on** — Choose where the rule applies (at least one required): * **Shareable** — Shareable link experiences. * **Manual** — Manually launched feedback. * **Auto** — Automatically triggered feedback. ## Throttle per user [#throttle-per-user] Limits apply separately to each user. Turn the section **Enabled**, then set **Time frame**, **Max. views**, and **Max. feedback responses** as above. Additional option: ### Gap time between views [#gap-time-between-views] | Setting | Description | | -------------------------- | ---------------------------------------------------------------------------- | | **Gap time between views** | Minimum minutes between two feedback views for the same user (up to 7 days). | **Gap time between views** applies only to **Auto** (automatically triggered) feedback. It does not affect **Shareable** or **Manual** feedback, even if those options are selected under **Apply these limits on**. Gap time between views must be less than or equal to the selected **Time frame** when **Auto** is enabled. For example, if the time frame is 15 minutes, gap time cannot be 30 minutes. This field is only shown when **Auto** is checked under **Apply these limits on**. Use **Apply these limits on** to choose **Shareable**, **Manual**, and/or **Auto** (at least one required). The gap-time cooldown is enforced only when feedback is shown via an automatic trigger. ## Throttle per feedback [#throttle-per-feedback] Limits apply per feedback form (each form has its own counters). Turn the section **Enabled**, then set **Time frame**, **Max. views**, **Max. feedback responses**, and **Apply these limits on** (**Shareable**, **Manual**, **Auto** — at least one required). There is no gap-time setting for this section. ## Throttle AI Refine Text [#throttle-ai-refine-text] This section is always **Enabled**. It limits how often users can use **Refine text** on long text response fields (Refine text must be turned on in your form configuration). | Setting | Description | | ---------------------------- | ------------------------------------------------------------------------- | | **Window** | Fixed at **5 minutes** from the first Refine text click. | | **Per identified users** | Maximum attempts per signed-in or identified user in that window (1–100). | | **Visitors / unknown users** | Maximum attempts per visitor in that window, counted by IP (1–100). | From the first Refine text click, identified users and visitors each get up to their configured number of attempts within the 5-minute window. ## Time frame options [#time-frame-options] When a throttle section is enabled, **Time frame** can be set to: * 15 minutes, 30 minutes, 45 minutes * 1 hour, 12 hours, 24 hours * 7 days, 14 days, 30 days, 90 days, 180 days, 365 days ## Tips [#tips] * Enable only the throttle types you need. **Throttle per user** is a common choice to avoid showing the same person too many surveys in a short period. * For **Throttle per user**, combine a **Time frame** with **Gap time between views** so users are not prompted again immediately after dismissing an automatically triggered form. Remember that gap time applies to **Auto** feedback only. * Under **Apply these limits on**, select only the delivery types you want to restrict (for example **Auto** only). * Keep **Max. feedback responses** at or below **Max. views** when both matter for your use case. # Pause Feedbacks (/docs/settings/global-settings/pause-feedbacks) Use **Pause Feedbacks** to temporarily stop all feedback forms from showing for a given app in your project. This is useful when you need to disable surveys on one channel (for example web only) while keeping them active on others. ## Where to find it [#where-to-find-it] 1. Open your project in the encatch dashboard. 2. Go to **Settings**. 3. Under **Global Settings**, open **Pause Feedbacks**. If you do not see **Pause Feedbacks**, contact your organization administrator—you may need additional access. **Page description:** Manage feedback configuration for each app in your project. Edit settings per row and save when ready. ## Pause feedbacks by app [#pause-feedbacks-by-app] The table lists each app configured for your project. Use the **Pause Feedbacks** switch on a row to pause or resume all feedback forms for that app. | Column | Description | | ------------------- | -------------------------------------------------------------------------------------------------------- | | **App** | The application name (from your [publishable SDK keys](/docs/settings/security/publishable-sdk-keys)). | | **Pause Feedbacks** | When **Yes**, all feedback forms are paused for that app. When **No**, feedback forms can show as usual. | Apps are grouped into: * **Shareable** — shareable link experiences. * **In App** — in-app SDK experiences. ### Pause all in-app feedbacks [#pause-all-in-app-feedbacks] Under **In App**, the **All** row lets you pause or resume feedback forms for every in-app app at once. When **All** is set to **Yes**, individual in-app rows are disabled until you turn **All** back to **No**. If your product runs on multiple channels (for example Android, iOS, and web) with a separate app name per channel, you can pause feedback only for the web app while Android and iOS keep showing forms. App names are defined when you create API keys. ## Save your changes [#save-your-changes] 1. Turn **Pause Feedbacks** on or off for the apps you need. 2. Changed rows are highlighted until you save. 3. Click **Save all** to apply. Use **Reset** to discard unsaved changes and restore the last saved values. Pausing feedback for one app does not affect other apps in the same project. ## Before you can configure apps [#before-you-can-configure-apps] If no apps appear, you need at least one app configured for the project (typically by creating a [publishable SDK key](/docs/settings/security/publishable-sdk-keys) with an application name). The page shows **No app is configured yet** until apps are available. # Retention (/docs/settings/global-settings/retention) **Retention** controls when encatch automatically removes old user profiles and their associated data—such as feedback responses, traits, and activity records—from your project environment. ## Where to find it [#where-to-find-it] 1. Open your project in the encatch dashboard. 2. Go to **Settings**. 3. Under **Global Settings**, open **Retention**. If you do not see **Retention**, contact your organization administrator—you may need additional access. **Page description:** Automatically remove old user profiles and all associated data (feedback responses, traits, activity records) from this environment. ## Data retention policy [#data-retention-policy] The **Data Retention Policy** card has two settings. Each uses the same list of retention periods. ### Users with feedback responses [#users-with-feedback-responses] How long to keep user profiles that have submitted at least one feedback response. ### All other user profiles [#all-other-user-profiles] How long to keep user profiles that have **not** submitted feedback (for example users who were identified or tracked but never responded). ## Retention period options [#retention-period-options] For each setting, choose one of: | Option | Meaning | | -------------------------------- | --------------------------------------------------------------------------------- | | **Until plans retention period** | Follow your subscription plan’s default retention (no project-specific override). | | **Remove after 30 days** | Delete profiles after 30 days. | | **Remove after 90 days** | Delete profiles after 90 days. | | **Remove after 180 days** | Delete profiles after 180 days. | | **Remove after 1 year** | Delete profiles after one year. | | **Remove after 2 years** | Delete profiles after two years. | | **Remove after 3 years** | Delete profiles after three years. | You can set different periods for users with feedback responses and for all other user profiles—for example, keep respondents longer for reporting while removing inactive profiles sooner. Deleting user profiles removes associated feedback responses, traits, and activity for those users in this environment. Review your compliance and reporting needs before shortening retention. ## Save your changes [#save-your-changes] 1. Choose a retention period for **Users with feedback responses** and **All other user profiles**. 2. Click **Save policy** to apply. You will see a confirmation when the policy is saved successfully. 3. Click **Reset** to discard unsaved changes and restore the last saved policy. # Admin API Keys (/docs/settings/security/admin-api-keys) **Admin API keys** authenticate trusted server-side requests to Encatch. Keep them on your backend and never include them in browser code, mobile apps, or client SDK configuration. ## Create an admin API key [#create-an-admin-api-key] 1. Open **Settings → Admin API Keys**. 2. Select **New**. 3. Enter a key name, optional description, and application identifier. 4. Choose the expiry period. 5. Set the contact creation policy described below. 6. Create the key and copy its value when it is shown. ## Contact creation policy [#contact-creation-policy] Each Admin API key can control whether a request using that key may create a contact that does not already exist. * **Allow contact creation** — The key can create new contacts and update existing contacts. * **Existing contacts only** — The key can update contacts that already exist without creating new records. Use **Existing contacts only** for integrations that should enrich records already managed by another system. Enable contact creation when Encatch is an intended entry point for new contacts. The policy is attached to the key, so separate integrations can use different rules. Rotate or replace a key when an integration's responsibility changes. ## Security practices [#security-practices] * Store the key in a server-side secret manager. * Give each integration its own key and descriptive application identifier. * Use the shortest practical expiry and rotate before it ends. * Delete a key immediately if it is exposed. For client-side SDK credentials, use [Publishable SDK Keys](/docs/settings/security/publishable-sdk-keys). # Publishable SDK Keys (/docs/settings/security/publishable-sdk-keys) **Publishable SDK keys** authenticate your encatch SDKs with our servers so you can collect in-app and web feedback securely. Keys are meant for client-side SDK integration; pair them with a server-side secret only when you use signature validation. ## Where to find it [#where-to-find-it] 1. Open your project in the encatch dashboard. 2. Go to **Settings**. 3. Under **Security**, open **Publishable SDK Keys**. If you do not see **Publishable SDK Keys**, contact your organization administrator—you may need additional access. **Page description:** Manage your project's publishable SDK keys. Create, view, and delete publishable SDK keys for secure access to your services. ## Keys list [#keys-list] The table shows keys for the selected tab: | Tab | Description | | ---------------- | ------------------------------------------------- | | **Active keys** | Keys currently in use. | | **Deleted keys** | Keys you have deleted (see retention note below). | | Column | Description | | -------------------- | ----------------------------------------------------------------- | | **App name** | Application name / identifier linked to the key. | | **Key identifier** | The name you gave the key when creating it. | | **Expires In** | When the key expires, or **Never** if no expiry. | | **Key Suffix** | Short suffix to cross-reference with the full key (`..._suffix`). | | **Info and Actions** | Open details, view status, or delete an active key. | Use **Create Publishable SDK Key** at the top to add a new key (subject to your plan’s publishable SDK key limit). If you reach your plan limit, you will see **Publishable SDK Keys limit reached** and need to upgrade before creating more. ### Deleted keys [#deleted-keys] On the **Deleted keys** tab, deleted or expired keys are listed. They are **permanently removed after 15 days** and cannot be restored. ## Create a publishable SDK key [#create-a-publishable-sdk-key] 1. Click **Create Publishable SDK Key**. 2. Fill in the dialog sections below, then click **Create**. **Dialog description:** Publishable SDK keys authenticate your SDKs with our servers, enabling secure communication for in-app feedback collection. ### Basic information [#basic-information] | Field | Description | | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Key name** (required) | Descriptive name (max 25 characters), e.g. `Production SDK`. | | **Description** (optional) | Notes about the key (max 100 characters). | | **Application name / identifier** (required) | Short id for the app (max 25 characters), e.g. `myapp` or `shop01`. Links feedback forms and settings such as [Pause Feedbacks](/docs/settings/global-settings/pause-feedbacks) to this app. | A warning may appear if you use a reserved application name—use those identifiers only when intended (for example shareable or in-app reserved names). ### Access configuration [#access-configuration] | Field | Description | | ----------------------------------------- | ------------------------------------------------------------------------- | | **Expiry period** (required) | 1 day, 1 week, 1 month, 3 months, 6 months, 1 year, or a **custom date**. | | **API key prefix** | Read-only prefix shown on the generated key (depends on environment). | | **Allowed domains / packages** (required) | Origins or app bundle ids allowed to use this key. Add up to 10 entries. | Examples for allowed domains / packages: * `*` — all origins (not recommended for production) * `https://app.example.com` * `https://*.example.com` * Android: `com.mycompany.myapp` Using `*` in **Allowed domains / packages** allows all domains to access this publishable SDK key. ### Security configuration (optional) [#security-configuration-optional] | Field | Description | | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | **Secret key** | Generate a secret for hashing user IDs and signature validation. **Never expose this on the client**—store it only on your server. | | **Session time (minutes)** | Session timeout for validation. Set to **0** to disable (default). | ### After creation [#after-creation] You see **Your Publishable SDK Key** once. Copy it immediately—you will not be able to view the full key again. Use the show/hide and copy controls, then click **Close**. If you lose a key, create a new one with the same **application name** and update your app, then delete the old key. ## Key details and delete [#key-details-and-delete] Open **Info and Actions** (⋮) on a row to see: * **Status** — Active, Expired, Deleted, or Inactive * **Allowed domains / packages** * **Created by** / **Updated by** with timestamps Active, non-expired keys can be deleted via **Delete Publishable SDK Key** (confirmation required). ## Best practices [#best-practices] * Restrict **Allowed domains / packages** to your real sites and app bundle ids; avoid `*` in production. * Rotate keys before **Expiry period** ends; keep the same **application name** when replacing a key. * Publishable keys are safe to embed in client apps, but treat optional **secret keys** as server-only credentials. * Test keys follow your plan’s test/production rules and may not count the same toward usage limits. For rate limits on SDK and API traffic, see [Rate Limits](/docs/sandbox-limits/rate-limits). # Cache Management (/docs/settings/feedback-settings/cache-management) Encatch caches feedback configurations so your SDK can load them quickly. When you update forms or settings and need those changes to show up right away in your app, use **Cache Management** to reset the application cache for your project. ## Where to find it [#where-to-find-it] 1. Open your project in the encatch dashboard. 2. Go to **Settings**. 3. Under **Feedback Settings**, open **Cache Management**. If you do not see **Cache Management**, contact your organization administrator—you may need additional access to reset cache. ## Reset application cache [#reset-application-cache] The **Cache management** page lets you reset cache for the current project. **Page description:** Reset application cache to refresh data sources and fix display issues. Your configurations and saved data will not be affected. ### Cache reset information [#cache-reset-information] Before you reset, read the notice on the page: > Resetting the cache will clear all stored data and changes will be instantly visible. This action is useful when you need to refresh data sources or fix display issues. Your configurations and saved data will not be affected. ### How to reset cache [#how-to-reset-cache] 1. In the **Reset cache** card, find **Reset Application Cache**. 2. Click **Reset Cache**. 3. In the confirmation dialog, review the message: resetting clears cached data but does not affect your configurations. 4. Note the warning that this action cannot be undone, then confirm with **Reset Cache**. After a successful reset, you will see a success message. If reset fails, try again or contact support. The system will automatically rebuild necessary caches as needed—you do not need to change anything in your application code. Resetting cache does not delete your feedback forms or saved responses. Only cached copies are cleared so the latest configurations can be loaded again. ## When to use cache reset [#when-to-use-cache-reset] Use **Reset cache** when: * You changed feedback forms or project settings and your SDK still shows older content. * You need to refresh data sources or fix display issues in your app. If your changes are not urgent, you can wait for your SDK’s next config sync instead of resetting cache immediately. # Data Settings (/docs/settings/user-data/data-settings) Data Settings controls which automatic fields encatch collects from your users — things like device type, browser, or country. You pick what goes on the **user profile** and what gets **attached to survey responses**. Use this page to stay within your PII policy. Only turn on fields you actually need. ## Where to find it [#where-to-find-it] 1. Open your project in the encatch dashboard. 2. Go to **Settings**. 3. Under **User Data**, open **Data Settings**. If you do not see **Data Settings**, contact your organization administrator — you may need additional access. ## Contact Info & Feedback Response [#contact-info--feedback-response] The table lists fields encatch can capture automatically. Each row has two optional checkboxes: | Column | What it does | | --------------------- | ----------------------------------------------------------------------------------- | | **Contact Info** | Saved on the user's profile when they are identified or interact with your app. | | **Feedback Response** | Sent along with each survey submission. Useful when filtering responses in Reports. | A dash (—) means that field cannot be used for that column. Changes are not applied until you click **Save settings**. Use **Reset** to undo unsaved edits.

Contact Info

Turn this on when you want the field stored on the user's contact profile — for example, their device OS, browser, or country code. This is separate from traits you manage on the [User Traits](/docs/settings/user-data/user-traits) page. Contact Info here is for built-in device and session metadata only.

Feedback Response

Turn this on when you want the field included with survey responses. You can then filter or group answers by it in Reports. Some of these fields (device OS, browser, URL or screen name, and similar) are **only** controlled here — not from the User Traits table. If a trait shows "Controlled by Data Settings" on the User Traits page, change it here instead. ## Available fields [#available-fields] | Field | Contact Info | Feedback Response | | ------------------ | ------------ | ----------------- | | Device OS | ✓ | ✓ | | Device OS Version | ✓ | ✓ | | Device Type | ✓ | ✓ | | Device Size | ✓ | ✓ | | App | ✓ | ✓ | | App Version | ✓ | ✓ | | Browser | ✓ | ✓ | | Browser Version | ✓ | ✓ | | SDK Version | ✓ | ✓ | | Device Language | ✓ | ✓ | | User Language | ✓ | ✓ | | URL or Screen Name | — | ✓ | | Preferred Theme | ✓ | ✓ | | Country Code | ✓ | ✓ | | Timezone | ✓ | ✓ | ## How this relates to User Traits [#how-this-relates-to-user-traits] * **User Traits** — custom attributes you define (plan, role, signup date, etc.). You can also choose which traits appear in feedback responses, up to a project limit. * **Data Settings** — built-in device and session metadata. Same kind of checkboxes, but for system fields only. If you need a custom field in Reports, create or enable it under User Traits. If you need device or browser info, configure it here. ## Best practices [#best-practices] * Start with the fields you will actually use in Reports or on user profiles. You can always add more later. * Leave sensitive fields off if your team does not need them. * **URL or Screen Name** is only available for Feedback Response — useful when you want to know which page or screen a response came from. # Tracked Events (/docs/settings/user-data/tracked-events) Tracked events let you capture behavioral data about your users—for example when they use a feature, view a page, or complete an action. You can use this data to [segment users](/docs/segmentation/overview) and to trigger feedback at the right moment (e.g. show a survey after a specific event). Events are created in two ways: * **Automatically** when your app or backend sends event data (e.g. via SDK or API), if **Allow new events from clients** is enabled for the project. * **Manually** in the Tracked Events table by clicking **Create Event**, so you can define events before sending data or use them in segments. ## Where to find it [#where-to-find-it] 1. Open your project in the encatch dashboard. 2. Go to **Settings**. 3. Under **User Data**, open **Tracked Events**. If you do not see **Tracked Events**, contact your organization administrator—you may need additional access. The page heading is **Tracked Events** with the description: *Manage tracked events for this project.* ## How to track events [#how-to-track-events] Events are sent from your application using the encatch SDK or API. You must identify users with a unique identifier (user ID or email) so that events can be associated with the right user. Whatever method you use, the event is identified by a **slug** (e.g. `button_click`, `page_view`, `form_submit`). If that slug does not exist yet and **Allow new events from clients** is on, a new tracked event is created automatically. ## How to use event data [#how-to-use-event-data] Tracked events are used mainly for [segmentation](/docs/segmentation/overview) and for triggering feedback. ### Segmenting users [#segmenting-users] When building a [data-driven segment](/docs/segmentation/data-driven), choose **Tracked Events** from **Add condition**. You can group users based on actions they have performed, for example “users who performed `feature_used` in the last 7 days” or “users who never performed `checkout_completed`”. See [Data-driven segments: Tracked Events](/docs/segmentation/data-driven#tracked-events) for operators and timeframes. ### Triggering feedback [#triggering-feedback] You can configure feedback forms to show when a user performs a specific tracked event. Use the targeting and trigger settings for your form to select a **Tracked Event** as the trigger, so the survey appears right after that action. ## Event properties [#event-properties] Each tracked event has: | Property | Description | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Slug** | System identifier used in API/SDK and storage. Lowercase letters, numbers, and underscores only (e.g. `button_click`, `page_view`). Must be unique in the project. | | **Name** | Display name shown in the dashboard (e.g. "Button Click", "Page View"). You can rename this at any time. | | **Last Usage** | When the event was last received for any user (helps you see if the event is still being sent). | | **Status** | Active (enabled), Disabled (paused), or Deleted. | ## Project options [#project-options] At the top of the Tracked Events page: ### Allow new events from clients [#allow-new-events-from-clients] Controls whether new events can be created automatically when event data is sent from your app or API. * **Enabled** – Any event slug you send can create a new tracked event if it does not already exist. * **Disabled** – Only **existing** event slugs are recorded; unknown events are ignored. Use this when you want strict control over which events are tracked. You can still create events manually regardless of this setting. ### Allow event tracking for visitors [#allow-event-tracking-for-visitors] Controls whether events can be tracked for visitors (users who are not fully identified). Enable this when you need behavioral data from anonymous or pre-login sessions; disable it if you only want events tied to identified users. ## Managing events [#managing-events] ### Create an event [#create-an-event] 1. Go to **Settings → User Data → Tracked Events** for the project. 2. Click **Create Event**. 3. In the **Create New Event** dialog, enter: * **Slug** – Lowercase, letters, numbers, and underscores only. Must be unique in the project. Examples: `button_click`, `page_view`, `form_submit`. * **Name** – Human-readable label (e.g. "Button Click", "Page View"). 4. Click **Create**. ### Rename an event [#rename-an-event] Edit the **Name** field in the table and save. The slug (system identifier) does not change. ### Usage information [#usage-information] The **In Use** column shows whether an event is used in **segments** (e.g. in segment filters). Click the indicator to see which segments reference it. Events that are **in use** cannot be disabled or deleted until they are removed from those segments. ### Disable an event [#disable-an-event] Use the **Pause** (disable) action. Disabled events are ignored for new incoming data and are not shown in other parts of the dashboard (e.g. trigger or segment options). Use **Play** to enable again. Events that are in use in segments cannot be disabled until removed from those segments. ### Delete an event [#delete-an-event] Use the **Delete** action for events that are **not** in use. Deleting removes the event from the project. Events that are in use cannot be deleted. ## Best practices [#best-practices] * **Slugs**: Use clear, stable slugs (e.g. `signup_completed`, `plan_upgraded`). Keep naming consistent between your app and the dashboard. * **Allow new events**: Turn **Allow new events from clients** off if you want to restrict which events are stored and avoid accidental event proliferation. * **Last usage**: Use the **Last Usage** column to spot events that are no longer sent from your app and clean them up or disable them if needed. # User Traits (/docs/settings/user-data/user-traits) User traits are the attributes that describe your users in encatch. You can think of them as columns in a spreadsheet: each trait holds one kind of information (e.g. email, plan, country). Traits are used for [segmentation](/docs/segmentation/overview), personalization, and for including user context in feedback responses. Traits are created in two ways: * **Automatically** when you identify users and send data (e.g. via SDK or API), if **Allow new traits from clients** is enabled for the project. * **Manually** in the User Traits table by clicking **Create Trait**, so you can define traits before connecting a data source or use them in segments. ## Where to find it [#where-to-find-it] 1. Open your project in the encatch dashboard. 2. Go to **Settings**. 3. Under **User Data**, open **User Traits**. If you do not see **User Traits**, contact your organization administrator—you may need additional access. The page heading is **User Traits** with the description: *Manage user traits for this project.* ## Trait properties [#trait-properties] Each trait has the following properties: | Property | Description | | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Slug** | System identifier used in API/SDK and storage. Lowercase letters, numbers, and underscores only (e.g. `plan`, `phone_number`). For system-generated traits, the slug cannot be changed. | | **Name** | Display name shown in the dashboard (e.g. "Plan", "Phone Number"). You can rename this at any time. | | **Data type** | The kind of value the trait holds: **Text**, **Numeric**, **Datetime**, or **Boolean**. | | **Include in feedback response** | When enabled, this trait is included in feedback response payloads so you can filter or group feedback by it in Reports. A project limit applies (see below). | ## Data types [#data-types] encatch supports these data types for traits: * **Text** – String values (e.g. name, email, free text). * **Numeric** – Numbers (e.g. login count, score). * **Datetime** – Dates/times (e.g. first seen, last login). * **Boolean** – True/false values. When creating a trait manually, you choose the data type. For traits created from client data (identify calls), the type is inferred from the payload. ## System-generated traits [#system-generated-traits] Each project is initialized with a set of **system-generated** traits. These represent core user and activity metadata: | Slug | Name | Description | | -------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `user_name` | Username | User's unique identifier. When set via [`identifyUser`](/docs/sdk-reference/web#2-identify-users), must be ASCII (letters, digits, `.`, `_`, `@`, `-`; 1–50 chars). When adding users to a manual segment, usernames must not contain spaces and are limited to 255 characters. | | `display_name` | Display Name | Display name | | `email` | Email | Email address | | `first_seen_at` | First seen at | When the user was first seen | | `last_seen_at` | Last seen at | When the user was last seen | | `feedback_views_count` | Feedback Views Count | Number of times the user saw a feedback form | | `last_feedback_view` | Last Feedback View | When the user last saw a feedback form | | `last_feedback_submission` | Last Feedback Submission | When the user last submitted feedback | | `feedback_response_count` | Feedback Response Count | Total number of feedback submissions | For system-generated traits: * The **slug** is fixed (locked) and cannot be changed. * The **name** can be edited. * **Include in feedback response** can be toggled only where the trait is available for feedback response. * System traits **cannot be deleted** or **disabled**. ## Allow new traits from clients [#allow-new-traits-from-clients] At the top of the User Traits page, the **Allow new traits from clients** option controls whether new traits can be created automatically when user data is sent (e.g. via identify calls from your app or API). * **Enabled** – Any attribute you send when identifying a user can create a new trait if it does not already exist. * **Disabled** – Only values for **existing** traits are stored; unknown attributes are ignored. Use this when you want strict control and no new columns from client data. You can still create traits manually regardless of this setting. Some fields (such as device and session metadata) are controlled from [Data Settings](/docs/settings/user-data/data-settings) under **Feedback Response**, not from the User Traits table. ## Managing traits [#managing-traits] ### Create a trait [#create-a-trait] 1. Go to **Settings → User Data → User Traits** for the project. 2. Click **Create Trait**. 3. In the **Create New Trait** dialog, enter: * **Slug** – Lowercase, letters, numbers, and underscores only. Must be unique in the project. * **Name** – Human-readable label. * **Data type** – Text, Numeric, Datetime, or Boolean. * **Include in feedback response** – Optional; subject to the project limit (see below). 4. Click **Create**. ### Rename a trait [#rename-a-trait] Edit the **Name** field in the table and save. The slug (system identifier) does not change. System-generated traits can be renamed; only the display name is updated. ### Include in feedback response [#include-in-feedback-response] Use the **Feedback Response** checkbox for each trait to include it in feedback response payloads. This is useful for filtering or grouping feedback in Reports. * A maximum of **25** traits per project can be included in the feedback response. Once the limit is reached, you must uncheck another trait before checking a new one. * Some system traits may not be available for feedback response. * Traits reserved for [Data Settings](/docs/settings/user-data/data-settings) show as controlled by Data Settings and cannot be toggled here. ### Usage information [#usage-information] The **In Use** column shows whether a trait is referenced in: * **Segments** – Used in [data-driven segment](/docs/segmentation/data-driven) conditions (User Traits and System fields). * **Feedback** – Used in feedback-related configuration. Click the usage indicator to see details. Traits that are **in use** cannot be disabled or deleted until they are removed from those usages. ### Disable a trait [#disable-a-trait] For traits that support it, use the **Pause** (disable) action. Disabled traits are ignored for new incoming data. System-generated traits and traits that are in use cannot be disabled. Use **Play** to enable again. ### Delete a trait [#delete-a-trait] Use the **Delete** action for custom traits that are **not** in use. Deleting removes the trait from the project. System-generated traits cannot be deleted. ## Feedback response limit [#feedback-response-limit] Only a limited number of traits per project can be marked as **Include in feedback response** (up to 25). Choose the traits that are most useful for filtering and reporting. You can change which traits are included at any time within the limit. ## Best practices [#best-practices] * **Slugs**: Use clear, stable slugs (e.g. `plan`, `country`, `signup_date`). Avoid changing them in your app after traits are in use. * **Allow new traits**: Turn **Allow new traits from clients** off if you want to restrict which attributes are stored and avoid accidental trait proliferation. * **Feedback response**: Only include traits you actually need in reports and integrations to stay within the feedback response limit. # undefined (/docs/administrative-guide/form-builder/appearance) # Consent (/docs/feedback-management/question-types/choice/consent) The **Consent** element collects agreement to terms, a privacy policy, or other acknowledgement text you write in markdown. It is a fixed **agree / disagree** pattern **without** custom option labels (unlike **[Yes / No](/docs/feedback-management/question-types/choice/yes-no)**, where you can rename both choices). In the form builder it appears under **Choice** as **Consent**. ## When to use [#when-to-use] * Privacy policy, terms of service, or data-processing notices * Mandatory checkboxes before continuing the form * Any short legal or compliance copy where respondents must explicitly agree ## Customization options [#customization-options] When editing a Consent question, you can configure the following properties: | Option | Description | | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Internal display label** | Required label used in the builder and internal lists (not the main legal copy). You can insert variables from the picker where supported. | | **Consent content** | Required body text shown to respondents; **markdown** is supported (up to 500 characters in the editor). This is where you place the terms, policy summary, or acknowledgement wording. | | **Slug** | Optional URL-friendly identifier for the question. | | **Error Message** | The message shown when validation fails (e.g. required consent not given). Keep it clear and actionable. | | **Next button label** | Label for the button that advances past this question after the respondent agrees. | | **Consent alignment** | **Left** — content aligned to the start. **Justify** — full-width justified block text (often better for long paragraphs than centering). | | **Required field** | When enabled, respondents must agree before continuing. | | **Hidden question** | When enabled, the question can be hidden from respondents where your form logic allows. | ## Viewing responses [#viewing-responses] Consent responses appear in the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) for your form. You can see who agreed or did not, filter by time period or segment, and audit acknowledgement over time. # Multiple Choice (/docs/feedback-management/question-types/choice/multiple-choice) The **Multiple Choice** element lets respondents select one or more options from a predefined list (e.g. checkboxes). Use it when you need to capture multiple selections—such as "Which devices do you use to access this application?", "What features do you use most?", or "Select all that apply"—that you can analyze and visualize in charts. ## When to use [#when-to-use] * "Select all that apply" questions * Feature usage, interests, or multi-select preferences * Questions where respondents may legitimately choose several options ## Customization options [#customization-options] When editing a Multiple Choice question, you can configure the following properties: | Option | Description | | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Question Text** | The main question displayed to the respondent (required). | | **Description** | Optional helper text or context below the question (up to 100 characters). | | **Answer Options** | The list of choices (required). Each option has an **Option Label** (what respondents see) and an **Option Value** (what gets stored). Use "+ Add Option" to add more choices, or the trash icon to remove one. | | **Error Message** | The message shown when validation fails (e.g. required field not filled, invalid selection). Keep it clear and actionable for better user experience. Default: "Please complete this required question". | | **Required field** | When enabled, the respondent must select at least one option before submitting the form. | | **Minimum Selections** | The minimum number of options the respondent must select (e.g. 0 for optional, 1+ for required). | | **Maximum Selections** | The maximum number of options the respondent can select (e.g. 2 to limit choices). | | **Display Mode** | How the options are presented—e.g. **Checkboxes** or **List**. Choose the style that fits your form layout. | | **Allow "Other" option** | When enabled, respondents can choose "Other" and provide a custom response outside the predefined options. | ## Viewing responses [#viewing-responses] Multiple-choice responses appear in the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) for your form. You can view them as bar charts or pie charts, filter by time period or user segment, and track trends over time. # Nested Selection (/docs/feedback-management/question-types/choice/nested-selection) The **Nested Selection** element lets respondents choose from hierarchical dropdown options—selecting a parent category first, then drilling down into child options. Use it when you need structured, multi-level choices—such as "Select your department and the main function you use in the application", "Choose your region and office", or "Pick a product category and subcategory"—that you can analyze and visualize in charts. ## When to use [#when-to-use] * Department and function selection within an organization * Region and location hierarchies * Product or service category trees * Any question where options are logically grouped under parent categories ## Customization options [#customization-options] When editing a Nested Selection question, you can configure the following properties: | Option | Description | | ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Question Text** | The main question displayed to the respondent (required). | | **Description** | Optional helper text or context below the question (up to 100 characters). | | **Placeholder Text** | The text shown in the dropdown before a selection is made. Default: "Select an option". | | **Error Message** | The message shown when validation fails (e.g. required field not filled, invalid selection). Keep it clear and actionable for better user experience. Default: "Please complete this required question". | | **Required field** | When enabled, the respondent must make a selection before submitting the form. | | **Show parent labels in selection** | When enabled, the selected option displays its parent label(s) in the dropdown for clarity (e.g. "Parent Option 1 › Child Option A"). | | **Dropdown Options** | The hierarchical list of choices (required). Each option has a **Label** (what respondents see), **Option Hint Text** (optional helper text), and **Value** (what gets stored). Use "+ Add Option" to add top-level options, the "+" icon next to an option to add child options, or the trash icon to remove an option. Options can be expanded or collapsed to manage the hierarchy. | ## Managing dropdown options [#managing-dropdown-options] * **Add Option** — Creates a new top-level parent option. * **Add Child Option** — Adds a nested option under the selected parent. Use the expand/collapse arrow to reveal child options. * **Label** — The text displayed to respondents in the dropdown. * **Option Hint Text** — Optional hint shown below the label to provide additional context. * **Value** — The value stored for analytics and reporting. ## Viewing responses [#viewing-responses] Nested selection responses appear in the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) for your form. You can view them as bar charts or pie charts, filter by time period or user segment, and track trends over time. # Picture Choice (/docs/feedback-management/question-types/choice/picture-choice) The **Picture choice** element (labeled **Picture Choice** in the form builder) shows respondents a grid of options defined by an **image**, **label**, and optional **hint** per option. Respondents tap one or more images depending on your settings. ## When to use [#when-to-use] * Visual preference tests, product concepts, logos, or mood boards * When images communicate choices faster than text alone ## Customization options [#customization-options] | Option | Description | | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | | **Question Text** | Main question (required). | | **Description** | Optional markdown. | | **Error Message** | Validation failure message. | | **Required field** | At least one selection required when enabled. | | **Options** | Up to **30** options. For each: image (asset picker), internal value, label, optional hint. Reorder via drag handle. | | **Allow multiple selections** | When on, respondents can pick more than one image. | | **Supersize images** | Larger image presentation in the form. | | **Show labels** | Toggle visibility of option labels under images. | | **Randomize option order** | Shuffle options per session. | | **Allow Other** | Adds an “Other” path with configurable placeholder text for free-text follow-up (translations supported). | | **Next button label**, **Show question title**, **Text alignment**, **Slug** | Standard question chrome. | | **Secondary settings** | Validations and visibility where supported. | ## Viewing responses [#viewing-responses] Selections appear with your other choice-type questions in [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary). For global form options, see [Other Fields Configuration](/docs/feedback-management/question-types/other-fields-configuration). # Ranking (/docs/feedback-management/question-types/choice/ranking) The **Ranking** element asks respondents to order a list of items (for example features, priorities, or preferences). You define the options; respondents assign ranks. ## When to use [#when-to-use] * Priority lists, feature voting, or “order these from most to least important” * When relative order matters more than a single score per item ## Customization options [#customization-options] | Option | Description | | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | **Question Text** | Main question (required). | | **Description** | Optional markdown context. | | **Error Message** | Shown when validation fails. | | **Required field** | A complete ranking may be required before submit. | | **Options** | Add, remove, and reorder items (up to **30** options). Each option has a value and label (labels support translations). | | **Randomize option order** | Shuffle the initial order shown to each respondent. | | **Display style** | **Drag and drop** or **↑ ↓ arrows** to change order. | | **Limit ranking to top N items** | Optional: respondents rank only their top *N* choices instead of the full list. | | **Next button label**, **Show question title**, **Text alignment**, **Slug** | Same patterns as other question types. | | **Secondary settings** | Validations and visibility where supported. | ## Viewing responses [#viewing-responses] Ranking data is reflected in your form’s reporting; use [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) to review collected answers. See also [Other Fields Configuration](/docs/feedback-management/question-types/other-fields-configuration) for global form display options. # Single Choice (/docs/feedback-management/question-types/choice/single-choice) The **Single Choice** element lets respondents select exactly one option from a predefined list (e.g. radio buttons or a list). Use it when you need structured, comparable answers—such as "How many departments in your organization?", "Where did you hear about us?", or "What is your preferred method of interacting with the application?"—that you can analyze and visualize in pie and bar charts. ## When to use [#when-to-use] * Demographics, category selection, or preference questions * When only one answer is valid (e.g. "Which plan are you on?") * Questions where you need comparable, structured data across respondents ## Customization options [#customization-options] When editing a Single Choice question, you can configure the following properties: | Option | Description | | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Question Text** | The main question displayed to the respondent (required). | | **Description** | Optional helper text or context below the question (up to 100 characters). | | **Answer Options** | The list of choices. Each option has a **Label** (what respondents see) and a **Value** (what gets stored). Use "+ Add Option" to add more choices, or the trash icon to remove one. | | **Error Message** | The message shown when validation fails (e.g. required field not filled). Keep it clear and actionable for better user experience. | | **Required field** | When enabled, the respondent must select an option before submitting the form. | | **Display Style** | How the options are presented—e.g. **Radio Button** or dropdown. Choose the style that fits your form layout. | | **Allow "Other" option** | When enabled, respondents can choose "Other" and provide a custom response outside the predefined options. | ## Viewing responses [#viewing-responses] Single-choice responses appear in the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) for your form. You can view them as bar charts or pie charts, filter by time period or user segment, and track trends over time. # Yes / No (/docs/feedback-management/question-types/choice/yes-no) The **Yes / No** element collects a **binary** answer: two options you label yourself (defaults **Yes** and **No**). Use it for quick confirmations, screening questions, or any clear either/or decision. In the form builder it appears under **Choice** as **Yes / No**. It is similar to **[Single Choice](/docs/feedback-management/question-types/choice/single-choice)** with exactly two options, but optimized for a simple affirmative/negative pattern. For terms or policy text with a standard agree/disagree flow and no custom button labels, use **[Consent](/docs/feedback-management/question-types/choice/consent)** instead. ## When to use [#when-to-use] * Quick filters or qualifiers (“Do you currently use feature X?”) * Simple confirmations before follow-up questions * Any question that should read naturally as yes/no rather than a longer option list ## Customization options [#customization-options] When editing a Yes / No question, you can configure the following properties: | Option | Description | | --------------------- | --------------------------------------------------------------------------------------------------------- | | **Question Text** | The main question displayed to the respondent (required). | | **Description** | Optional helper text below the question; supports markdown (up to 500 characters in the editor). | | **Slug** | Optional URL-friendly identifier for the question. | | **Yes label** | Text for the affirmative option (default: "Yes"). Up to 100 characters. | | **No label** | Text for the negative option (default: "No"). Up to 100 characters. | | **Error Message** | The message shown when validation fails (e.g. required field not answered). Keep it clear and actionable. | | **Display style** | **Horizontal** — both options in a row. **Vertical** — options stacked. | | **Next button label** | Label for the button that advances past this question. | | **Text alignment** | How the question block is aligned (e.g. left or center). | | **Required field** | When enabled, the respondent must choose Yes or No before continuing. | | **Hidden question** | When enabled, the question can be hidden from respondents where your form logic allows. | ## Viewing responses [#viewing-responses] Yes / No responses appear in the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) for your form. You can view counts and splits between the two options, filter by time period or segment, and track trends over time. # Address (/docs/feedback-management/question-types/contact/address) The **Address** element collects a **structured postal address**: lines for street and unit, **city**, **state or region**, **postal code**, and **country**. Each sub-field can be **enabled**, marked **required**, and given its own **caption** and **placeholder** (with translations per language). ## When to use [#when-to-use] * Shipping, billing, physical service areas, or compliance where you need separate fields ## Customization options [#customization-options] ### Address lines [#address-lines] For **Address line 1**, **Address line 2**, **City**, **State / region**, **Postal code**, and **Country**: * **Enabled** — Whether the sub-field appears. * **Required** — Whether the respondent must fill it (only meaningful when enabled). * **Caption** and **placeholder** — Labels and hints for each line (translatable). ### Default country [#default-country] You can set a **default country** used when the form loads (primary language configuration in the editor). ### Standard question fields [#standard-question-fields] **Question text**, **description**, **error message**, **required** (for the question as a whole), **next button label**, **show question title**, **text alignment**, **hidden question**, and **secondary settings** follow the same patterns as other blocks. ## Viewing responses [#viewing-responses] Structured address fields export and display alongside other contact data; review them in [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary). For numbering, titles, and button labels across the form, see [Other Fields Configuration](/docs/feedback-management/question-types/other-fields-configuration). # Email (/docs/feedback-management/question-types/contact/email) The **Email** element collects a single email address. The runtime validates the format; you can set a **placeholder** and **pre-filled value** to reduce friction. ## When to use [#when-to-use] * Login identifiers, support contacts, newsletter opt-in, or any workflow that needs a deliverable address ## Customization options [#customization-options] | Option | Description | | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | | **Question Text** | Main question (required). | | **Description** | Optional markdown. | | **Placeholder** | Hint inside the field (per language, up to **150** characters in the editor). | | **Pre-filled value** | Optional default email shown to the respondent (they can change it). | | **Error Message** | Shown when the address is missing or invalid. | | **Required field** | Must be filled before submit. | | **Next button label**, **Show question title**, **Text alignment**, **Slug** | Standard chrome. | | **Secondary settings** | Validations and visibility where supported. | ## Viewing responses [#viewing-responses] Email values appear with other responses in [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary). See [Other Fields Configuration](/docs/feedback-management/question-types/other-fields-configuration) for form-wide labels and display options. # Phone Number (/docs/feedback-management/question-types/contact/phone-number) The **Phone number** element collects a telephone number with an international **country code**. Respondents can pick or change the country when **Allow country change** is enabled; otherwise the field stays on the configured default. ## When to use [#when-to-use] * Callback numbers, SMS consent flows, or regional support routing ## Customization options [#customization-options] | Option | Description | | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------- | | **Question Text** | Main question (required). | | **Description** | Optional markdown. | | **Placeholder** | Hint text in the national number input (per language). | | **Default country code** | Optional **ISO-style two-letter** code used as the initial prefix (normalised in the editor). | | **Allow country change** | When off, respondents cannot switch away from the default country (useful for single-country campaigns). | | **Pre-filled value** | Optional default national number. | | **Error Message** | Shown when validation fails. | | **Required field** | Must be completed before submit. | | **Next button label**, **Show question title**, **Text alignment** | Standard chrome. | | **Hidden question** | Hide the block while still storing configuration (where supported). | | **Secondary settings** | Validations and visibility where supported. | ## Viewing responses [#viewing-responses] Phone answers are listed with your other contact fields in [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary). For global form options, see [Other Fields Configuration](/docs/feedback-management/question-types/other-fields-configuration). # Signature (/docs/feedback-management/question-types/contact/signature) The **Signature** element collects a legally oriented **signature**. Respondents can **draw**, **type**, or **upload** a signature depending on which **modes** you allow. You can tune drawing **colours**, **pen width**, **canvas height**, and optional **signer email** collection. ## When to use [#when-to-use] * Terms acceptance with a captured signature, contracts, or field paperwork ## Customization options [#customization-options] ### Modes and defaults [#modes-and-defaults] | Option | Description | | ----------------- | -------------------------------------------------------------------------------- | | **Allowed modes** | Toggle **Draw**, **Type**, and **Upload**; order reflects tab order in the form. | | **Default mode** | Which tab opens first (must be one of the allowed modes). | ### Draw and upload copy [#draw-and-upload-copy] | Option | Description | | -------------------------------------- | ---------------------------------------------------- | | **Hint on empty draw canvas** | Message when the canvas is blank. | | **Upload tab — idle prompt** | Text when no file is selected. | | **Upload tab — prompt while dragging** | Text during drag-over. | | **Clear button label** | Label for clearing the canvas (for example “Clear”). | ### Drawing appearance (primary configuration) [#drawing-appearance-primary-configuration] | Option | Description | | ---------------------------- | ----------------------------------- | | **Pen colour** | Stroke colour for drawn signatures. | | **Canvas background colour** | Colour behind the stroke. | | **Pen width** | Thickness of the pen. | | **Canvas height** | Vertical size of the drawing area. | ### Other [#other] | Option | Description | | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | | **Collect signer email address** | Optional extra field to store an email with the signature. | | **Placeholder** | Hint for typed-name mode (per language). | | **Question Text**, **Description**, **Error Message**, **Required**, **Next button label**, **Show question title**, **Text alignment**, **Secondary settings** | Same patterns as other questions. | ## Viewing responses [#viewing-responses] Signature assets and metadata appear in your form’s reporting; open [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) for the submission list. See [Other Fields Configuration](/docs/feedback-management/question-types/other-fields-configuration) for global form chrome. # Website (/docs/feedback-management/question-types/contact/website) The **Website** element collects a **URL**. Use it when you need a web address rather than arbitrary text. ## When to use [#when-to-use] * Portfolio links, company homepages, or referral URLs ## Customization options [#customization-options] | Option | Description | | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | | **Question Text** | Main question (required). | | **Description** | Optional markdown. | | **Placeholder** | Hint inside the field (per language, up to **150** characters in the editor). | | **Pre-filled value** | Optional default URL (for example your domain). | | **Error Message** | Shown when the value fails validation. | | **Required field** | Must be provided before submit. | | **Next button label**, **Show question title**, **Text alignment**, **Slug** | Standard chrome. | | **Secondary settings** | Validations and visibility where supported. | ## Viewing responses [#viewing-responses] URLs appear with other answers in [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary). See [Other Fields Configuration](/docs/feedback-management/question-types/other-fields-configuration) for form-wide display settings. # File Upload (/docs/feedback-management/question-types/advanced/file-upload) The **File upload** element lets respondents attach **one or more files**. You can restrict **MIME types and extensions** using presets or custom entries, cap **size per file**, and limit how many files are accepted when **multiple** uploads are enabled. ## When to use [#when-to-use] * Screenshots, receipts, résumés, or any evidence that belongs with the response ## Customization options [#customization-options] ### Types and size [#types-and-size] | Option | Description | | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Allowed file types** | Toggle presets for **Images**, **Documents**, **Video**, and **Audio**; each adds a curated list of MIME types or extensions. Leave all presets off and add nothing to accept **any** file type. | | **Custom types** | Add arbitrary entries (for example `application/json` or `.csv`); shown as removable tags. | | **Max file size (MB)** | **Required** upper bound per file. | | **Allow multiple files** | When on, respondents can upload more than one file. | | **Max files** | When multiple is on, optional cap on the number of files. | ### Copy and behaviour [#copy-and-behaviour] | Option | Description | | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------- | | **Upload area placeholder** | Text inside the drop zone (per language). | | **Question Text**, **Description**, **Error Message**, **Required**, **Next button label**, **Show question title**, **Text alignment**, **Hidden question** | Standard chrome. | | **Secondary settings** | Validations and visibility where supported. | ## Viewing responses [#viewing-responses] Uploaded files are linked from [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) alongside the rest of the submission. See [Other Fields Configuration](/docs/feedback-management/question-types/other-fields-configuration) for global form options. # Q&A with AI (/docs/feedback-management/question-types/advanced/qna-with-ai) The **Q\&A with AI** element adds a **conversational block** where respondents ask questions and receive answers grounded in a **knowledge base** text you provide. You control chat **limits**, **button labels**, and several **status messages** for empty states and usage counters. ## When to use [#when-to-use] * Product FAQs, policy clarifications, or onboarding help without building a full chatbot elsewhere ## Customization options [#customization-options] ### Knowledge and input [#knowledge-and-input] | Option | Description | | -------------------- | ------------------------------------------------------------------------------ | | **Knowledge base** | Long-form text the model uses to answer (character count shown in the editor). | | **Placeholder** | Hint inside the ask field (per language). | | **Ask button label** | Optional label for the submit action (per language, up to **50** characters). | ### Chat UI copy (per language) [#chat-ui-copy-per-language] | Option | Description | | ------------------------- | ------------------------------------------------------------ | | **Empty chat hint** | Message before the first exchange. | | **Counter — under limit** | Template when the respondent still has Q\&A pairs remaining. | | **Counter — at limit** | Template when the exchange cap is reached. | ### Limits (primary language) [#limits-primary-language] | Option | Description | | ----------------------- | ------------------------------------------------------------------------ | | **Max response length** | Optional cap on answer length in **characters**. | | **Max Q\&A exchanges** | Optional cap on how many question–answer **pairs** a respondent may use. | ### Standard fields [#standard-fields] **Question text**, **description**, **error message**, **required**, **next button label**, **show question title**, **text alignment**, **hidden question**, and **secondary settings** behave like other questions. ## Viewing responses [#viewing-responses] Chat transcripts are stored with the submission; review them in [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary). See [Other Fields Configuration](/docs/feedback-management/question-types/other-fields-configuration) for form-wide display settings. # Scheduler (/docs/feedback-management/question-types/advanced/scheduler) The **Scheduler** element embeds a live booking experience using either **Google Calendar** or **Calendly**. You paste the **calendar or event URL**, configure optional **intro** behaviour, and can **autofill** name and email from earlier questions. ## When to use [#when-to-use] * Sales demos, support calls, interviews, or any workflow that ends in a booked slot ## Customization options [#customization-options] ### Provider and URL [#provider-and-url] | Option | Description | | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | **Provider** | **Google Calendar** or **Calendly**. | | **Google booking page link** | For Google: paste the appointment **booking page URL** from Calendar (the editor reminds you to use Appointment schedule → Save, then copy the link). | | **Calendly embed URL** | For Calendly: paste the full **event-type URL** (for example `https://calendly.com/you/30min`). | ### Respondent experience [#respondent-experience] | Option | Description | | ------------------------------------- | ---------------------------------------------------------------------------- | | **Show intro screen before calendar** | When on, respondents see an intermediate step before the embedded scheduler. | | **Schedule a meeting — button text** | Optional label for the primary scheduling action (per language). | | **Placeholder** | Hint when the scheduler area is loading or idle (per language). | ### Autofill [#autofill] | Option | Description | | -------------------------------- | ----------------------------------------------------------------------- | | **Autofill name from question** | Pick an earlier question whose answer fills the scheduler’s name field. | | **Autofill email from question** | Pick an earlier question for the email field. | ### Standard fields [#standard-fields] **Question text**, **description**, **error message**, **required**, **next button label**, **show question title**, **text alignment**, **hidden question**, and **secondary settings** follow the same patterns as other blocks. ## Viewing responses [#viewing-responses] Booking outcomes appear with the submission in [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary). For global button labels and layout options, see [Other Fields Configuration](/docs/feedback-management/question-types/other-fields-configuration). # Video / Audio / Photo (/docs/feedback-management/question-types/advanced/video-audio) The **Video/Audio/Photo** element (builder label **Video/Audio/Photo**) collects **video**, **audio**, **photo**, or **text** responses depending on which **modes** you enable. You can set a **default mode**, tune **recording duration**, allow **file upload** as an alternative to the camera or mic, and customize many on-screen labels. ## When to use [#when-to-use] * Verbal feedback, video testimonials, photo proof, or async user research clips ## Customization options [#customization-options] ### Modes and defaults [#modes-and-defaults] | Option | Description | | ----------------- | -------------------------------------------------------------------------------------------------- | | **Allowed modes** | Enable any combination of **Video**, **Audio**, **Photo**, and **Text**; order controls tab order. | | **Default mode** | Which experience opens first (must be allowed). | ### Recording and upload [#recording-and-upload] | Option | Description | | -------------------------------- | -------------------------------------------------------------------------------- | | **Limit max recording duration** | Optional cap for **video and audio**; set minutes and seconds. | | **Allow upload** | When on, respondents may upload a file instead of only recording in the browser. | | **Max file size (MB)** | Applies when upload is allowed. | ### Labels and hints (per language) [#labels-and-hints-per-language] Examples include: **Record** button, **Upload file** button, idle hints over the video or photo areas, **Use camera**, **Upload image**, and related prompts. These let you match your brand voice. ### Other [#other] **Question text**, **description**, **placeholder**, **error message**, **required**, **next button label**, **show question title**, **text alignment**, **hidden question**, and **secondary settings** behave like other question types. ## Viewing responses [#viewing-responses] Media attachments and metadata surface in [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary). See [Other Fields Configuration](/docs/feedback-management/question-types/other-fields-configuration) for form-wide controls. # Matrix (multiple per row) (/docs/feedback-management/question-types/matrix/matrix-multiple-choice) The **Matrix (multiple per row)** element is a **grid** of **rows** and **columns** where respondents may select **more than one column per row**—similar to **[Multiple Choice](/docs/feedback-management/question-types/choice/multiple-choice)** (“select all that apply”), but repeated for each row with the same column headers. In the form builder it appears under **Matrix** as **Matrix (multiple per row)**. Compare with **[Matrix (single per row)](/docs/feedback-management/question-types/matrix/matrix-single-choice)**, which allows only **one** column selection per row. ## When to use [#when-to-use] * Each row is a topic or item, and respondents may tick **several** applicable columns (for example features used, issues seen, or reasons that apply) * You want one matrix instead of many separate multiple-choice questions with the same options ## Customization options [#customization-options] When editing a Matrix (multiple per row) question, you can configure the following properties: | Option | Description | | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Question Text** | The main question displayed to the respondent (required). | | **Description** | Optional helper text below the question; supports markdown (up to 500 characters in the editor). | | **Slug** | Optional URL-friendly identifier for the question. | | **Error Message** | The message shown when validation fails (e.g. required rows not completed, or min/max selection rules not met). Default: "Please complete this required question". | | **Rows** | The left-hand labels in the grid. Each row has a **label** (what respondents see) and an **identifier** (stored value for that row). Use **Add row** to add rows; remove extras with the trash control when more than one row exists. | | **Columns** | The options shown across the top (shared by all rows). Each column has a **label** and an **identifier**. Use **Add column** to add columns; remove extras with the trash control when more than one column exists. | | **Min selections per row** | Minimum number of columns that must be selected in **each** row (0 or higher). Leave empty to clear the minimum. | | **Max selections per row** | Maximum number of columns selectable per row. Leave empty for no explicit maximum (subject to how many columns exist). | | **Randomize rows** | When enabled, row order is shuffled for each respondent. | | **Randomize columns** | When enabled, column order is shuffled for each respondent. | | **Next button label** | Label for the button that advances past this question. | | **Text alignment** | How the question block is aligned (e.g. left or center). | | **Required field** | When enabled, respondents must satisfy validation for every row (including any min/max rules you set) before continuing. | | **Hidden question** | When enabled, the question can be hidden from respondents where your form logic allows. | ## Viewing responses [#viewing-responses] Matrix (multiple per row) responses appear in the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) for your form. You can analyze which columns were chosen **per row**, filter by time period or segment, and compare selection patterns across rows. # Matrix (single per row) (/docs/feedback-management/question-types/matrix/matrix-single-choice) The **Matrix (single per row)** element presents a **grid** of **rows** and **columns**. For each row, the respondent picks **exactly one** column—like a **[Single Choice](/docs/feedback-management/question-types/choice/single-choice)** per row, but with a shared set of column options. In the form builder it appears under **Matrix** as **Matrix (single per row)**. Use it when every row needs one answer from the same column labels (for example “Poor / Fair / Good” per feature). This differs from **[Rating matrix](/docs/feedback-management/question-types/matrix/rating-matrix)**, which applies one numeric or Likert **scale** to each statement rather than arbitrary column labels. ## When to use [#when-to-use] * Each row is a scenario, feature, or statement, and columns are mutually exclusive answers * You want a compact matrix instead of many separate single-choice questions * “Pick one option per line” from a fixed column set ## Customization options [#customization-options] When editing a Matrix (single per row) question, you can configure the following properties: | Option | Description | | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Question Text** | The main question displayed to the respondent (required). | | **Description** | Optional helper text below the question; supports markdown (up to 500 characters in the editor). | | **Slug** | Optional URL-friendly identifier for the question. | | **Error Message** | The message shown when validation fails (e.g. required rows not answered). Default: "Please complete this required question". | | **Rows** | The left-hand labels in the grid. Each row has a **label** (what respondents see) and an **identifier** (stored value for that row). Use **Add row** to add more rows. When more than one row exists, you can remove a row with the trash control. | | **Columns** | The choices shown across the top (shared by all rows). Each column has a **label** and an **identifier**. Use **Add column** to add columns; remove extras with the trash control when more than one column exists. | | **Randomize rows** | When enabled, row order is shuffled for each respondent. | | **Randomize columns** | When enabled, column order is shuffled for each respondent. | | **Next button label** | Label for the button that advances past this question. | | **Text alignment** | How the question block is aligned (e.g. left or center). | | **Required field** | When enabled, respondents must select one column for every row before continuing. | | **Hidden question** | When enabled, the question can be hidden from respondents where your form logic allows. | ## Viewing responses [#viewing-responses] Matrix (single per row) responses appear in the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) for your form. You can analyze selections **per row** and **per column**, filter by time period or segment, and compare how often each column is chosen for each row. # Rating matrix (/docs/feedback-management/question-types/matrix/rating-matrix) The **Rating matrix** element shows several **statements** (rows) that share the same **scale** (columns). Respondents rate each statement in one pass—for example agreement with multiple UX statements on one Likert or star scale. In the form builder it appears under **Matrix** as **Rating matrix**. It is faster than adding a separate **[Rating](/docs/feedback-management/question-types/scale/rating)** question for every row. ## When to use [#when-to-use] * Several related items should use the **same** scale (satisfaction, agreement, importance) * UX or product surveys with multiple Likert-style statements * Any case where you want a compact grid instead of repeated rating blocks ## Customization options [#customization-options] When editing a Rating matrix question, you can configure the following properties: | Option | Description | | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Question Text** | The main question displayed to the respondent (required). | | **Description** | Optional helper text below the question; supports markdown (up to 500 characters in the editor). | | **Slug** | Optional URL-friendly identifier for the question. | | **Error Message** | The message shown when validation fails (e.g. required rows not completed). Default: "Please complete this required question". | | **Scale** | **Likert scale** — typically two endpoints (e.g. disagree / agree), shown as radio-style choices per row. **Rating scale** — numeric/star-style scale with default labels such as Poor through Excellent (depending on point count). **Custom scale** — you define each column’s **label** (what respondents see) and **identifier** (value stored for each option). | | **Scale points** | Number of points on the shared scale: **2**, **3**, **4**, or **5**. | | **Scale labels** | For each column, the text respondents see. On **Custom scale**, you can also set the stored **identifier** per column (numeric or other value, depending on what you enter). | | **Statements** | The rows to rate. Each statement has a **label** (shown in the grid) and an **identifier** (stored value for that row). Use **Add statement** to add rows (up to **10** statements). Remove extra rows with the trash control when more than one statement exists. | | **Randomize statement order** | When enabled, the order of statement rows is shuffled for each respondent. | | **Next button label** | Label for the button that advances past this question. | | **Text alignment** | How the question block is aligned (e.g. left or center). | | **Required field** | When enabled, respondents must provide a rating for each statement before continuing. | | **Hidden question** | When enabled, the question can be hidden from respondents where your form logic allows (e.g. for prefilled or conditional flows). | ## Viewing responses [#viewing-responses] Rating matrix responses appear in the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) for your form. You can analyze ratings **per statement** (row), filter by time period or segment, and view distributions across the shared scale. # Exit form (/docs/feedback-management/question-types/panels/exit-form) The **Exit form** is a **silent** end marker: respondents **do not** see a screen when they reach it. In the form builder it appears under **Panels** as **Exit form**. Use it as the **Go to** target in a **[Logic jumps](/docs/feedback-management/form-builder/logic-jumps)** rule when a condition should **end the form immediately** without showing a **[Thank you screen](/docs/feedback-management/question-types/panels/thank-you-screen)**. ## When to use [#when-to-use] * Screening or branching: send disqualified or “not applicable” respondents straight to the end * Any flow where the form should stop with **no** closing UI for that path ## Placement and limits [#placement-and-limits] In the builder, exit forms live only in the **Thank you & Exit Section** at the end of the form (the same terminal area as thank-you screens). The product enforces: * **At most one** Exit form per form. * **Order:** keep **all thank-you screens before** the Exit form when both exist in that section. The Exit form should be the **last** step for paths that hit it. ## Customization options [#customization-options] The Exit form has **no respondent-visible UI**. In the builder you configure: | Option | Description | | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Title** | Builder-only label (up to **200** characters) so you can tell exit forms apart in the outline and logic jumps canvas. Not shown to respondents. | | **Call to action** | Optional silent action when a logic jump routes here — close, redirect, or in-app navigation. Requires **Enable call to action**. See [Call to action](/docs/feedback-management/form-builder/call-to-action). | The list label in the builder stays **Exit form** so you can recognize the marker in the outline. ## Viewing responses [#viewing-responses] The Exit form does **not** collect answers. Responses are still stored for questions the respondent answered **before** the jump ended the session; see the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary). # Message panel (/docs/feedback-management/question-types/panels/message-panel) The **Message panel** is a **non-question** screen you can place **between** other steps. It shows a **title**, optional **markdown** body, and a **continue** button so respondents read context or instructions before going on. In the form builder it appears under **Panels** as **Message panel**. It uses the same editor pattern as the **[Welcome Panel](/docs/feedback-management/question-types/panels/welcome-screen)** and **[Thank you screen](/docs/feedback-management/question-types/panels/thank-you-screen)**, but it is meant for **mid-flow** content (disclaimers, section intros, rich notes)—not as the opening or closing screen of the form. ## When to use [#when-to-use] * Instructions or context before a block of questions * Disclaimers or “please read” copy without collecting an answer * A styled pause between sections while keeping a single continue action ## Customization options [#customization-options] When editing a Message panel, you can configure the following properties: | Option | Description | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Title** | Main heading on the panel (required). Up to **200** characters. You can insert variables from the picker where supported. | | **Description** | Optional body text; **markdown** is supported (up to **500** characters in the editor). | | **Slug** | Optional URL-friendly identifier for this panel. | | **Next button label** | Text on the button that continues the form (required). Up to **200** characters. The default placeholder is **Next**; you can override it (for example “Continue” or “I understand”). | | **Title & description alignment** | **Left** or **Center** for the title and description block. | Message panels are **not** used to store structured answers; the editor keeps them non-required. ## Viewing responses [#viewing-responses] The Message panel does **not** collect responses. Analytics and exports reflect answers from **question** elements before and after the panel; see the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary). # Thank you screen (/docs/feedback-management/question-types/panels/thank-you-screen) The **Thank you screen** is the **Thank you** panel type in the form builder (**Panels** → **Thank you screen**). It is shown when someone **finishes** your feedback form. Use it to thank respondents, confirm submission, or share a short next step. In the builder, thank-you content lives in the **Thank you & Exit Section** at the end of the form. You can only add thank-you screens there, and they must stay in that terminal section (you cannot place them in the middle of survey pages). That section can also include an optional **[Exit form](/docs/feedback-management/question-types/panels/exit-form)** after your thank-you screens—a silent end marker you can target from **[Logic jumps](/docs/feedback-management/form-builder/logic-jumps)** when a branch should end without a thank-you screen. ## When to use [#when-to-use] * Thank people for completing the form * Confirm that their responses were received * Point to support, a coupon, or a follow-up link in the description (markdown) ## Customization options [#customization-options] When editing a Thank you screen, you can configure the following properties (same editor pattern as the **Welcome screen** panel): | Option | Description | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Title** | Main heading shown on the screen (required). Up to **200** characters. You can insert variables from the picker where supported. | | **Description** | Optional body text below the title; **markdown** is supported (up to **500** characters in the editor). | | **Slug** | Optional URL-friendly identifier for this panel. | | **Next button label** | Text on the primary action button (required). Up to **200** characters. The default placeholder for thank-you screens is **Close**; you can override it (for example “Done” or “Return to app”). Used as the close button when no [Call to action](/docs/feedback-management/form-builder/call-to-action) is configured. | | **Title & description alignment** | **Left** or **Center** for the title and description block. | | **Call to action** | Optional post-submit behavior — button labels, in-app navigation, redirects, auto-trigger, and secondary button. See [Call to action](/docs/feedback-management/form-builder/call-to-action). | Thank you panels are **not** treated as required “questions” in the same way as data fields; the editor keeps them non-required by design. ## Viewing responses [#viewing-responses] The thank-you screen does not collect answers. Response data comes from the questions **before** this screen; see the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) for submissions and analytics. # Welcome Panel (/docs/feedback-management/question-types/panels/welcome-screen) The **Welcome Panel** is the first screen respondents see when they start your feedback form. Use it to set context, explain the purpose of the survey, and set expectations. ## When to use [#when-to-use] * Introduce the feedback topic or campaign * Show estimated time to complete * Display branding or a short instruction ## Configuration [#configuration] You can customize the welcome screen appearance and behavior from the **Edit Welcome Screen** dialog. The following options are available: ### Welcome Title [#welcome-title] The main heading shown on the welcome screen. Use this to greet respondents and introduce your feedback form. **Example:** "Welcome to our application!" ### Welcome Description [#welcome-description] The description body shown to users. Use this to explain the purpose of the feedback form, set expectations, or provide any additional context before respondents begin. **Example:** "We're glad you're here. This feedback will help us serve you better." ### Welcome Button Text [#welcome-button-text] The text displayed on the welcome button that respondents click to start the feedback form. **Example:** "Get Started" # CSAT (Rating) (/docs/feedback-management/question-types/scale/csat-rating) The **CSAT (Rating)** element collects customer satisfaction on a short 1-to-N scale, where N is 2, 3, 4, or 5. Respondents pick one option—emoji faces by default, or text buttons if you switch the display style. In the form builder it sits under **Scale** with **[Rating](/docs/feedback-management/question-types/scale/rating)**, **[NPS](/docs/feedback-management/question-types/scale/nps)**, and **[Opinion scale](/docs/feedback-management/question-types/scale/opinion-scale)**. CSAT is its own question type in the form and in reporting. It is built around satisfaction scoring, not generic star or icon ratings. ## When to use [#when-to-use] * After a support ticket, chat, or call (transactional CSAT) * After onboarding, checkout, or another key journey moment * Quick “How satisfied were you?” checks where emoji or labeled buttons fit better than NPS * Pairing with a follow-up **[Long Answer](/docs/feedback-management/question-types/text/long-answer)** (for example, “What influenced your score?”) ## Customization options [#customization-options] When editing a CSAT question in the form builder: | Option | Description | | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | **Question Text** | Main question shown to the respondent (required). | | **Description** | Optional markdown helper text below the question. | | **Error Message** | Shown when validation fails. Default: "Please complete this required question". | | **Required field** | Respondent must pick a score before continuing. | | **Scale** | Number of points: **2**, **3**, **4**, or **5**. 2- and 4-point scales have no neutral middle; 5-point gives the most granularity. | | **Display Style** | **Emoji** (default) shows a face or icon per point. **Text** shows labeled buttons instead. | | **Custom emojis** | When display style is Emoji, turn this on to pick a different emoji for each scale point. See [Custom emojis](#custom-emojis) below. | | **Multicolor scale** | Colors low, middle (on 3- and 5-point scales), and high scores differently—similar to NPS. | | **Negative / Neutral / Positive colors** | Customize the three sentiment colors when multicolor is on. | | **Show labels** | Show a label under each option. Always on for text style; optional for emoji style. | | **Scale labels** | Text for each active point (for example “Very Unsatisfied” through “Very Satisfied” on a 5-point scale). Editable per language. | | **Next button label** | Continue button text (per language when translations are enabled). | | **Show question title** | Toggle title visibility. | | **Text alignment** | Alignment for title and description. | | **Slug** | Stable identifier for integrations or exports. | ## Custom emojis [#custom-emojis] Out of the box, each scale size uses a standard set of satisfaction faces—unhappy at the low end, happy at the high end. If those defaults do not match your brand or the moment you are measuring, turn on **Custom emojis** in the question settings. Custom emojis only work when **Display Style** is **Emoji**. Switching to **Text** turns them off. ### How to set them up [#how-to-set-them-up] 1. Add or edit a CSAT question and leave **Display Style** on **Emoji**. 2. Enable **Custom emojis**. 3. A preview strip appears with one emoji per scale point, ordered left to right from lowest to highest satisfaction. 4. Click a point in the strip to open the emoji picker. Pick a replacement from the available categories: Unhappy, Neutral, Happy, Gestures, Hearts, Symbols, and Celebration. 5. Repeat for any other points you want to change. Each point gets its own emoji. The picker draws from a fixed CSAT palette—you cannot paste in arbitrary characters. If you change the **Scale** size while custom emojis are on, Encatch keeps your picks for overlapping points and fills new slots with defaults. Turning **Custom emojis** off brings back the standard faces for that scale size. ### Default emoji sets [#default-emoji-sets] When custom emojis are off, respondents see: | Scale | Default emojis (low → high) | | ------- | --------------------------- | | 2-point | 😡 😄 | | 3-point | 😡 😐 😄 | | 4-point | 😡 😕 🙂 😄 | | 5-point | 😡 😕 😐 🙂 😄 | Custom emojis change how the question looks—they do not change the score itself, which is still a number from 1 through N on an N-point scale. ## Viewing responses [#viewing-responses] CSAT responses appear in the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) for your form. You can view distribution across the scale, filter by time period or segment, and track trends over time. # Net Promoter Score (NPS) (/docs/feedback-management/question-types/scale/nps) The **NPS** (Net Promoter Score) element measures customer loyalty by asking respondents how likely they are to recommend your product or service on a scale of 0–10. ## What is NPS? [#what-is-nps] The NPS question type in Encatch lets you measure customer loyalty through a single, industry-standard question. When you add an NPS element to your feedback form, respondents see a 0–10 scale and answer: > How likely are you to recommend our product or service to a friend or colleague? Encatch records each response and surfaces the data in the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary), so you can track loyalty over time and across segments. ## How NPS is calculated [#how-nps-is-calculated] Encatch uses the standard NPS methodology: responses are grouped into three buckets: * **Detractors (0–6)** — Unlikely to recommend; may share negative experiences. * **Passives (7–8)** — Satisfied but not enthusiastic; unlikely to actively promote. * **Promoters (9–10)** — Highly likely to recommend; strong advocates. The score is derived by subtracting the share of Detractors from the share of Promoters: ``` NPS = % Promoters – % Detractors ``` Scores range from -100 (everyone is a Detractor) to +100 (everyone is a Promoter). ## When to use [#when-to-use] * Measure overall satisfaction and loyalty * Track NPS over time or by segment * Follow up with a qualitative question (e.g. "Why did you choose this score?") * Compare feedback across user segments (e.g. plan type, region, lifecycle stage) ## Configuration [#configuration] The NPS methodology is based on a standardized 0–10 scale. In Encatch, you can customize the question to fit your context: | Option | Description | | ------------------ | ------------------------------------------------------------------- | | **Question title** | The main question text (e.g. "How likely are you to recommend us?") | | **Description** | Optional helper text or context below the question | | **Min label** | Label for 0 (default: "Not at all likely") | | **Max label** | Label for 10 (default: "Extremely likely") | | **Required** | Whether the question must be answered before submission | ## Viewing NPS results [#viewing-nps-results] NPS responses appear in the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) for your form. For NPS questions, you can: * View **average score** and **distribution** across the 0–10 scale * Filter by **time period**, **user segment**, or **response value** * Track **trends** over time * Segment results by user attributes (e.g. subscription plan, region) Consider adding a follow-up question (e.g. a [Long Answer](/docs/feedback-management/question-types/text/long-answer) such as "What could we improve?") after the NPS question to capture qualitative feedback from detractors or promoters. # Opinion Scale (/docs/feedback-management/question-types/scale/opinion-scale) The **Opinion scale** element collects a single value from a horizontal row of numbered buttons. The range is more flexible than NPS: you choose whether the scale starts at **0** or **1**, and how many **steps** (points) it has. ## When to use [#when-to-use] * Agreement, likelihood, or satisfaction when you need a custom range (for example 1–5, 1–7, or 0–10) * When NPS’s fixed 0–10 wording does not fit your survey ## Customization options [#customization-options] When editing an Opinion scale question, you can configure the following properties: | Option | Description | | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Question Text** | The main question shown to the respondent (required). | | **Description** | Optional markdown helper text below the question. | | **Error Message** | Message shown when validation fails (for example if the question is required). | | **Required field** | Respondent must pick a value before continuing. | | **Start value** | **0** or **1** — the lowest number on the scale. | | **Steps** | Number of points on the scale: **5** through **11**. The visible range is *start* through *start + steps − 1* (for example start 0 and 11 steps → 0–10). | | **Minimum / Maximum labels** | Optional text at the low and high ends of the scale. | | **Next button label** | Label for the continue action (per language when translations are enabled). | | **Show question title** | Toggle visibility of the question title. | | **Text alignment** | Alignment for title and description. | | **Slug** | Stable identifier for integrations or exports. | | **Secondary settings** | Validations and visibility rules where supported. | ## Viewing responses [#viewing-responses] Scale responses appear in the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) for your form, alongside other quantitative questions. For form-wide controls such as numbering and default button labels, see [Other Fields Configuration](/docs/feedback-management/question-types/other-fields-configuration). # Rating (/docs/feedback-management/question-types/scale/rating) The **Rating** element collects feedback on a scale, such as stars (e.g. 1–5), hearts, emojis, or other visual icons. Use it when you want a quick, visual scale instead of NPS or single choice. ## When to use [#when-to-use] * Satisfaction, quality, or likelihood ratings * When you want a quick, visual scale instead of NPS or single choice ## Customization options [#customization-options] When editing a Rating question, you can configure the following properties: | Option | Description | | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Question Text** | The main question displayed to the respondent (required). | | **Description** | Optional helper text or context below the question (up to 100 characters). | | **Error Message** | The message shown when validation fails (e.g. required field not filled, invalid selection). Keep it clear and actionable for better user experience. Default: "Please complete this required question". | | **Required field** | When enabled, the respondent must select a rating before submitting the form. | | **Show labels** | When enabled, displays the minimum and maximum rating labels (e.g. "Poor" and "Excellent") at the ends of the scale. | | **Minimum Rating Label** | The label shown for the lowest rating value (e.g. "Poor"). | | **Maximum Rating Label** | The label shown for the highest rating value (e.g. "Excellent"). | | **Number of Ratings** | The number of rating points on the scale (default: 5). | | **Display Style** | The icon type used for the rating scale: **Star**, **Emoji**, **Heart**, **Diamond**, or **Thumbs Up**. | | **Size of Rating Icons** | The size of the rating icons: **Small**, **Medium**, or **Large** (default: Medium). | ## Viewing responses [#viewing-responses] Rating responses appear in the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) for your form. You can view them as charts, filter by time period or user segment, and track trends over time. If you add the question from the builder as **[CSAT (Rating)](/docs/feedback-management/question-types/scale/csat-rating)**, it is still a Rating question in the form and in reporting—the name only helps you pick a satisfaction-oriented block from the **Scale** group. # Date (/docs/feedback-management/question-types/text/date) The **Date** element collects a structured date from respondents. You control how segments are ordered, which separator is used, whether **time** is included, and optional **minimum** and **maximum** dates. ## When to use [#when-to-use] * Birth dates, deadlines, booking preferences, or any calendar-based answer * When you need a consistent format instead of free-text dates ## Customization options [#customization-options] ### Format and display [#format-and-display] | Option | Description | | ---------------- | ------------------------------------------------------------------------------------ | | **Date format** | **DD/MM/YYYY**, **MM/DD/YYYY**, or **YYYY/MM/DD**. | | **Separator** | **/**, **-**, or **.** — applied in the displayed format string. | | **Include time** | When enabled, respondents can also provide a time with the date. | | **Placeholder** | Hint text in the input (per language). | ### Segment labels [#segment-labels] | Option | Description | | ------------------------------------- | ------------------------------------------------------------------------------ | | **Day / Month / Year segment labels** | Accessible labels for each segment (defaults: Day, Month, Year). Translatable. | ### Bounds [#bounds] | Option | Description | | ---------------- | --------------------------------------- | | **Minimum date** | Earliest selectable date (date picker). | | **Maximum date** | Latest selectable date. | ### Common question fields [#common-question-fields] **Question text**, **description** (markdown), **error message**, **required**, **next button label**, **show question title**, **text alignment**, **slug**, and **secondary settings** (validations, visibility) follow the same patterns as other elements. ## Viewing responses [#viewing-responses] Date answers flow into [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) with your other structured fields. See [Other Fields Configuration](/docs/feedback-management/question-types/other-fields-configuration) for form-wide display and button defaults. # Long Answer (/docs/feedback-management/question-types/text/long-answer) The **Long Answer** element lets respondents provide detailed, multi-line text responses (e.g. comments, suggestions, or open-ended feedback). Use it when you need richer qualitative input—such as "Please describe your overall experience using this application. What works well and what could be improved?"—that goes beyond short answers. ## When to use [#when-to-use] * Open-ended feedback, comments, or suggestions * Detailed qualitative responses that require more than a few words * When you want respondents to elaborate on their experience ## Customization options [#customization-options] When editing a Long Answer question, you can configure the following properties: | Option | Description | | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Question Text** | The main question displayed to the respondent (required). | | **Description** | Optional helper text or context below the question (up to 100 characters). | | **Placeholder Text** | The hint text shown in the text area before the respondent types (e.g. "Enter your answer here"). | | **Error Message** | The message shown when validation fails (e.g. required field not filled). Keep it clear and actionable for better user experience. Default: "Please complete this required question". | | **Required field** | When enabled, the respondent must provide an answer before submitting the form. | | **Minimum Characters** | The minimum number of characters the respondent must enter. Leave empty for no minimum. | | **Maximum Characters** | The maximum number of characters allowed in the response. Default: 5000. | | **Number of Rows** | The initial visible height of the text area (number of rows). Default: 4. | | **Enable AI Response Enhancement** | When enabled, AI can enhance or refine the respondent's answer. | ## Viewing responses [#viewing-responses] Long answer responses appear in the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) for your form. You can view them as text, filter by time period or user segment, and export for further analysis. # Number (/docs/feedback-management/question-types/text/number) The **Number** element collects a single numeric value. You can allow **decimals** and **negative** values, set **minimum** and **maximum**, add a short **unit** label (for example `%` or `kg`), and optionally **pre-fill** the field. ## When to use [#when-to-use] * Quantities, scores, percentages, ages, or any answer that must be numeric * When validation should reject non-numeric input ## Customization options [#customization-options] | Option | Description | | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | **Question Text** | Main question (required). | | **Description** | Optional markdown. | | **Placeholder** | Hint inside the input (per language). | | **Error Message** | Shown when validation fails. | | **Required field** | Value must be present and valid before submit. | | **Minimum value** / **Maximum value** | Optional inclusive bounds. | | **Allow decimals** | Permits fractional values (placeholder text in the editor adapts). | | **Allow negative values** | Permits values below zero when bounds allow. | | **Unit** | Short suffix next to the field (max **10** characters). | | **Pre-filled value** | Optional default number shown to the respondent (respects decimal vs integer mode). | | **Next button label**, **Show question title**, **Text alignment**, **Slug** | Standard chrome. | | **Secondary settings** | Validations and visibility where supported. | ## Viewing responses [#viewing-responses] Numeric responses appear in reporting alongside other fields; see [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary). For global form options, see [Other Fields Configuration](/docs/feedback-management/question-types/other-fields-configuration). # Short Answer (/docs/feedback-management/question-types/text/short-answer) The **Short Answer** element captures a single line of text (e.g. name, email, or a brief reply). Use it when you need a concise, one-line response that you can validate and optionally enhance with AI. ## When to use [#when-to-use] * Email, name, or short open-ended answers * When you need a concise, one-line response * When you want to enforce character limits or regex validation ## Customization options [#customization-options] When editing a Short Answer question, you can configure the following properties: | Option | Description | | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Question Text** | The main question displayed to the respondent (required). | | **Description** | Optional helper text or context below the question (up to 100 characters). | | **Placeholder Text** | The hint text shown inside the input field before the respondent types (e.g. "Enter your answer here"). | | **Error Message** | The message shown when validation fails (e.g. required field not filled, invalid selection). Keep it clear and actionable for better user experience. Default: "Please complete this required question". | | **Required field** | When enabled, the respondent must provide an answer before submitting the form. | | **Minimum Characters** | The minimum number of characters the respondent must enter. Leave empty for no minimum. | | **Maximum Characters** | The maximum number of characters allowed (e.g. 200). Responses exceeding this limit will fail validation. | | **Enable Regex Validation** | When enabled, you can apply custom regex patterns to validate the response format (e.g. email, phone number). | | **Enable AI Response Enhancement** | When enabled, AI can enhance or refine the respondent's answer before it is stored. | ## Viewing responses [#viewing-responses] Short answer responses appear in the [Response Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) for your form. You can view them as text, filter by time period or user segment, and track trends over time. # Channel Distribution (/docs/feedback-management/reports-and-export/charts/channel-distribution) ## Channel Distribution [#channel-distribution] This report shows how your feedback is distributed across different **channels**, such as web, mobile web, iOS, Android, and other platforms. ### What You'll See [#what-youll-see] * **Channel breakdown** — Percentage or count of views and submissions per channel * **Comparison** — How each channel performs relative to others ### Use Cases [#use-cases] * Understand which platforms drive the most feedback * Prioritize improvements for high-traffic channels * Identify channels with low engagement for targeted optimization # Country Distribution (/docs/feedback-management/reports-and-export/charts/country-distribution) ## Country Distribution [#country-distribution] This report shows how feedback is distributed across **countries**, based on user location or IP-derived geography. ### What You'll See [#what-youll-see] * **Country breakdown** — Percentage or count of views and submissions per country * **Top regions** — Which countries account for the most feedback ### Use Cases [#use-cases] * Understand your audience's geographic spread * Identify regional differences in engagement * Plan region-specific campaigns or localization # Engagement (/docs/feedback-management/reports-and-export/charts/engagement) ## Engagement [#engagement] The Engagement report provides metrics on how users interact with your feedback forms, including view-to-submission conversion and completion rates. ### Key Metrics [#key-metrics] * **Conversion rate** — Percentage of views that result in a submission * **Completion rate** — Percentage of started forms that are fully completed * **Drop-off points** — Where users abandon forms before submitting ### Use Cases [#use-cases] * Identify forms with low conversion and optimize them * Understand user behavior and friction points * Compare engagement across different forms or segments # Language Distribution (/docs/feedback-management/reports-and-export/charts/language-distribution) ## Language Distribution [#language-distribution] This report shows how feedback is distributed across the **languages** your users have configured or that are detected from their environment. ### What You'll See [#what-youll-see] * **Language breakdown** — Percentage or count of views and submissions per language * **Top languages** — Which languages account for the most feedback ### Use Cases [#use-cases] * Understand your audience's language mix * Prioritize localization for high-volume languages * Identify underserved language segments # Submissions by Time (Daily) (/docs/feedback-management/reports-and-export/charts/submissions-by-time-daily) ## Submissions by Time (Daily) [#submissions-by-time-daily] This report shows the number of **submitted** feedback responses on a daily basis. A submission is counted when a user completes and submits a feedback form. ### What You'll See [#what-youll-see] * **Daily submission counts** — How many responses were received each day * **Trend over time** — Whether submission volume is increasing, decreasing, or stable * **Date range filtering** — Filter by custom date ranges to focus on specific periods ### Use Cases [#use-cases] * Track response volume and completion rates over time * Compare submission volume before and after campaigns or product changes * Identify peak periods for user feedback # Views by Time (Daily) (/docs/feedback-management/reports-and-export/charts/views-by-time-daily) ## Views by Time (Daily) [#views-by-time-daily] This report shows the number of times your feedback forms were **viewed** on a daily basis. A view is counted when a form is displayed to a user, whether or not they submit a response. ### What You'll See [#what-youll-see] * **Daily view counts** — How many times forms were shown each day * **Trend over time** — Whether view volume is increasing, decreasing, or stable * **Date range filtering** — Filter by custom date ranges to focus on specific periods ### Use Cases [#use-cases] * Track form visibility and reach over time * Compare view volume before and after campaigns or product changes * Identify seasonal patterns in form exposure # External Insights (/docs/feedback-management/reports-and-export/feedback-studio/external-insights) ## Introduction [#introduction] External Insights transforms your feedback data into actionable insights with powerful analytics. Whether your feedback comes from app stores, play stores, product reviews, YouTube comments, Instagram comments, or any other source, you can import it and start analyzing immediately. The feature supports any CSV or JSON file, so you are never locked into a single platform or format. Think of External Insights as your AI-powered feedback analyst. Instead of manually sifting through spreadsheets or writing custom scripts, you upload your data, ask questions in plain English, and receive clear answers with charts and summaries. The system uses DuckDB to run analytical queries directly on your device, which means your raw data stays local and private while you still get the full power of AI-driven analysis. Welcome to Review Insights — upload area and three-step workflow *** ## Benefits [#benefits] **Turn any feedback source into insights.** External Insights accepts CSV and JSON files from virtually anywhere. App store reviews, social media comments, survey exports, support tickets, NPS responses, or custom feedback dumps from your own tools—all of these can be loaded and analyzed in one place. You no longer need separate workflows for each platform. **AI-powered analytics without the complexity.** You do not need to write SQL or learn a BI tool. Simply describe what you want to know in natural language. For example, you might ask for a dashboard on feedback categories for the last month, or a breakdown of ratings by feature area. The AI translates your questions into queries, runs them locally via DuckDB, and returns aggregated results. Charts and summaries appear in a live report panel as you ask questions, and the report builds up dynamically. **Data privacy by design.** Your feedback data is loaded and processed on your device. Only aggregated results (summaries, counts, averages) are sent to the server for AI summarisation. Granular, row-level data stays local unless you explicitly ask the AI for specific details. This makes External Insights suitable for sensitive feedback and environments with strict data policies. **Beautiful, shareable reports.** Once you are satisfied with the analysis, you can ask the AI to generate a report in HTML format. The report is self-contained and responsive, so it works on desktop, tablet, and mobile. You can save it as a file, share it with your team, or reuse the visuals for slides by taking screenshots. The HTML is editable, so you can tweak it further in any editor if needed. **No pipelines or setup.** External Insights is ideal for ad-hoc analysis, board presentations, quarterly reviews, or quick explorations. There is no need to spin up a data pipeline, configure a warehouse, or wait for scheduled reports. Upload your file, start a conversation with the AI, and get insights in minutes. *** ## How to Use External Insights [#how-to-use-external-insights] ### Step 1: Open External Insights [#step-1-open-external-insights] In the encatch admin, go to **Feedback Studio** in the left navigation. Expand the Feedback Studio section and select **External Insights**. You will see the welcome screen with the upload area and a brief overview of the three-step workflow: upload your data, analyze it with AI, and generate visualizations. External Insights in the Feedback Studio navigation ### Step 2: Upload Your Feedback Data [#step-2-upload-your-feedback-data] Use the upload area to add your CSV or JSON file. You can drag and drop the file into the dashed box or click **Browse files** to select it from your computer. Files up to 50 MB are supported. Once uploaded, the file name and size will appear, and you can remove it with the trash icon if you need to switch to a different dataset. If you want to explore the feature without your own data, use the **Sample data** button to load example feedback. This is useful for first-time users or demos. ### Step 3: Verify the Loaded Data [#step-3-verify-the-loaded-data] After uploading, the system loads your data on your device. Take a moment to verify that the sample or preview looks correct. This ensures the columns and structure match what you expect before you start asking questions. ### Step 4: Start a Conversation with the AI [#step-4-start-a-conversation-with-the-ai] In the message input area, type your question or request in plain English. For example, you might ask to create a dashboard for your presentation on the various categories of feedback from the uploaded data for the last month. Messages are processed in real time, so you will see responses and visualizations appear as the AI works. Feedback Analytics — AI conversation interface and data privacy notice You can ask for specific types of analysis, such as a bar-plus-line combo showing platform breakdown (feedback count as bars, average rating as line), or any other visualization that helps you understand your data. The AI will aggregate the data, run the appropriate queries, and present the results. ### Step 5: Build Your Report [#step-5-build-your-report] As you ask questions, the AI adds charts and summaries to a live report panel. You can refine your analysis by asking follow-up questions or requesting additional data points. Once you are satisfied, ask the AI to generate the final report in HTML format. Feedback Analytics — generated dashboard preview with KPIs and charts ### Step 6: Save and Share [#step-6-save-and-share] The generated report is a standalone HTML file. Open it in any modern browser—it is responsive for desktop, tablet, and mobile. You can save it to your computer, email it to your team, or modify it further in any HTML editor. If you need visuals for slides or documents, take screenshots of the charts, or keep the interactive HTML as a live artifact for deeper exploration. Feedback Dashboard — KPIs, feedback by feature area, and average rating charts *** ## Example Use Cases [#example-use-cases] **Analyze feedback from social and review platforms.** You might have reviews from app stores, play stores, YouTube comments, Instagram comments, Glassdoor, or Twitter. Export that data to CSV or JSON and load it into External Insights to identify themes, sentiment trends, and areas for improvement. **Go beyond standard encatch reports.** If the built-in encatch reports do not answer your questions, export your encatch data to CSV and analyze it with External Insights. You can slice the data by custom dimensions, time windows, or categories that are not available in the default dashboards. **Ad-hoc analysis for presentations.** When you need quick insights for a board meeting, product review, or stakeholder update, External Insights lets you upload your latest feedback export and generate a tailored dashboard in minutes, without waiting for scheduled reports or setting up new pipelines. # Private Insights (/docs/feedback-management/reports-and-export/feedback-studio/private-insights) ## Introduction [#introduction] Private Insights lets you analyze and explore your feedback data using AI that runs entirely on your own device. Unlike cloud-based AI tools that send your data to external servers, Private Insights keeps everything local. Your feedback data is stored on your machine, and the Large Language Model (LLM) that powers the analysis runs in your browser. No API calls are made for data processing, which means your sensitive feedback never leaves your computer. Think of Private Insights as a confidential analyst sitting on your desk. You provide the data, choose the AI model that runs locally, and ask questions in plain English. The AI analyzes your feedback, identifies patterns, and answers your questions—all without sending a single byte of data over the network. This makes Private Insights ideal for teams working with confidential feedback, internal product discussions, or any scenario where data privacy is non-negotiable. Private Insights in the Feedback Studio navigation *** ## Benefits [#benefits] **Complete data privacy.** The most important benefit of Private Insights is that your data never leaves your device. Everything—from the raw feedback you load to the AI analysis—happens locally in your browser. There are no API calls for data processing, no server logs, and no retention of your feedback on external systems. If you work with customer support tickets, internal surveys, or sensitive product feedback, Private Insights ensures that confidential information stays exactly where it belongs: on your machine. **No vendor lock-in or usage limits.** Because the LLM runs on your device, you are not subject to per-request pricing, rate limits, or usage caps. You can analyze as much feedback as your machine can handle, ask as many questions as you like, and iterate on your analysis without worrying about costs or quotas. This is especially useful for teams that need to explore large feedback datasets or run repeated analyses during product planning cycles. **Flexibility in model choice.** Private Insights supports multiple on-device LLMs, so you can pick the one that best fits your needs. If you want the simplest setup with no downloads, you can use Browser Native Chat (Chrome's built-in AI). If you need more capable analysis and have the disk space and RAM, you can choose from models like Falcon, SmolLM, TinyLlama, or DeepSeek R1 Distill. Each model has different trade-offs between speed, capability, and resource usage, so you can tailor the experience to your hardware and workload. **Natural language analysis.** You do not need to write queries or learn a query language. Simply type your questions in plain English—for example, "Which is the common category of issue reported?" or "What are the main themes in the feedback for the Dashboard feature?" The AI reads your context data, understands the structure, and returns clear answers with explanations. You can ask follow-up questions to dig deeper, and the conversation builds on itself so you can explore your feedback iteratively. **Works with structured feedback.** Private Insights is designed to work with structured feedback data. You can load feedback that includes fields like FeedbackID, UserID, UserType, Platform, AppVersion, FeatureArea, Rating, FeedbackText, BugReport, Screenshot, and Date. The AI uses this structure to understand your data and provide relevant insights. You can edit the data before analysis to add, remove, or refine entries, ensuring the AI has the right context for your questions. *** ## System Requirements [#system-requirements] Before you start, make sure your machine meets the requirements for running local models. Private Insights needs a modern Chrome browser with sufficient resources to load and run an LLM on your device. **Browser.** Use a recent version of Chrome (139 or newer). Some models, such as Browser Native Chat, rely on Chrome's built-in on-device AI capabilities, so an up-to-date browser is essential. **Memory and storage.** Your machine should have at least 16 GB of RAM and enough free disk space for the model you choose. Smaller models like SmolLM2 360M require around 0.7 GB of disk space, while larger models like DeepSeek R1 Distill 7B need about 3.1 GB. Plan accordingly based on the model you select. **GPU support.** For smoother performance, especially with larger models, a machine with GPU support is recommended. This helps the model run faster and reduces the load on your CPU. For more details on Chrome's on-device models and compatibility, follow the "Learn more about Chrome on-device models" link shown on the Private Insights page. *** ## How to Use Private Insights [#how-to-use-private-insights] ### Step 1: Open Private Insights [#step-1-open-private-insights] In the encatch admin, go to **Feedback Studio** in the left navigation. Expand the Feedback Studio section and select **Private Insights**. You will see the main page with the tagline "Analyze and explore your private feedback insights," along with an information banner explaining that data is stored on your device and no API calls are made for processing. Private Insights welcome and LLM selection ### Step 2: Choose an LLM [#step-2-choose-an-llm] The first step is to select which Large Language Model will power your analysis. Click the **Select an LLM** dropdown to see the available options. **Browser Native Chat (Chrome Browser 139+-144).** This option uses Chrome's built-in AI capabilities. It requires no download and supports up to 25,000 characters of context. It is the easiest option if you want to get started quickly and your Chrome version supports it. **SmolLM2 360M Instruct.** A lightweight model requiring about 0.7 GB of disk space. Best for fast responses, lightweight tasks, and low-memory environments. Supports up to 15,000 characters. **Falcon 1B.** Requires around 2.0 GB of disk space. Good for general chat, classification, and basic generation. Slightly slower than SmolLM but more capable. Supports up to 15,000 characters. **TinyLlama 1.1B Chat.** Requires about 2.2 GB of disk space. Best for conversational agents, chatbots, and natural-sounding dialogue. Supports up to 15,000 characters. **DeepSeek R1 Distill 7B.** Requires about 3.1 GB of disk space. Best for small-reasoning tasks and more complex analysis. Supports up to 15,000 characters. Each model lists its disk space requirement, character capacity, and provider. Choose the one that matches your hardware and the complexity of analysis you need. Once selected, the model loads on your device and is ready for use. ### Step 3: Add or Edit Your Context Data [#step-3-add-or-edit-your-context-data] The **Context Data** section shows the feedback data that the AI will analyze. Add Content modal for editing feedback data ### Step 4: Ask Questions and Explore Insights [#step-4-ask-questions-and-explore-insights] In the chat area, type your question in the input field. For example, you might ask "Which is the common category of issue reported on Zendesk?" or "What are the main pain points mentioned in the Dashboard feedback?" Press Enter or click the send button to submit your question. The AI reads your context data, understands the structure, and responds with an analysis. It might identify that bug reports are the most common category, list which feedback entries support that finding, and explain its reasoning. You can ask follow-up questions to drill down—for example, "Which feature areas have the most bug reports?" or "Summarize the feedback for the Login feature." Private Insights chat interface with AI analysis A token counter (for example, "Tokens left: 7,600 (1,616/9,216)") shows how much of the model's context window you have used. If you want to start fresh, click **New Chat** to begin a new conversation. The AI can make mistakes, so always double-check important findings before acting on them. ### Step 5: Iterate and Refine [#step-5-iterate-and-refine] Use the conversational interface to explore your feedback from different angles. Ask about trends, categories, severity, platform-specific issues, or any other dimension that matters to you. The more specific your questions, the more useful the answers. You can also go back to **Edit Data for analysis** to add more feedback or adjust the dataset, then continue the conversation with the updated context. *** ## Example Use Cases [#example-use-cases] **Analyze support ticket themes.** If you export support tickets (for example, from Zendesk) into a structured format, you can load them into Private Insights and ask which categories of issues are most common, which features generate the most complaints, or what patterns appear across different user types. All of this happens locally, so sensitive ticket content never leaves your device. **Explore internal feedback confidentially.** When your team collects internal feedback on a new feature or product direction, you can analyze it with Private Insights without sending that feedback to any external service. Ask about sentiment, recurring themes, or suggestions that appear most often, and use the answers to inform product decisions. **Quick ad-hoc analysis during planning.** When preparing for a sprint review or product meeting, load your latest feedback export, choose an LLM, and ask targeted questions. Get a summary of what users are saying about a specific feature, identify the top issues, or compare feedback across platforms—all in a few minutes, with full privacy. # Audience Overview (/docs/feedback-management/reports-and-export/feedback-dashboard/audience-overview) ## Audience Overview [#audience-overview] The **Audience Overview** tab shows high-level metrics and charts for your feedback form. Use it to understand who is viewing and responding to your form over time. ### Key Metrics [#key-metrics] Summary cards at the top display: * **Responses** — Total number of feedback submissions received * **Views** — Total number of times the feedback form was viewed * **Response Rate** — Percentage of views that resulted in a submission (e.g., 33.33%) These metrics update based on the selected date range and any applied conditions. ### Response Time Distribution [#response-time-distribution] A chart shows how long users take to complete the form, measured in seconds. This helps you identify whether the form is easy to complete or if users are spending unusually long or short amounts of time on it. ### Views and Submissions by Time (Daily) [#views-and-submissions-by-time-daily] This chart displays the number of views and submissions aggregated daily, helping you track engagement trends over time. Use it to spot peaks, drops, or seasonal patterns in form usage. ### Filtering [#filtering] Use the date range selector (e.g., "Last 7 Days") and the "+ Add Condition" button to filter the data and focus on specific time periods or audience segments. # Destinations (/docs/feedback-management/reports-and-export/feedback-dashboard/destinations) ## Destinations [#destinations] The **Destinations** tab lets you configure where feedback data is sent when users submit responses. Use it to route feedback to integrations, webhooks, or other systems. ### What You'll See [#what-youll-see] * **Active destinations** — Integrations and endpoints currently receiving feedback * **Configuration options** — Settings for each destination (e.g., API keys, mappings) * **Add new destinations** — Connect additional tools or services ### Use Cases [#use-cases] * Send feedback to Slack, Discord, email, or CRM * Trigger webhooks for custom workflows * Integrate with analytics or data warehouses * Ensure feedback reaches the right teams or systems Configure destinations to ensure every response is routed to the right place for follow-up and analysis. # Overview (/docs/feedback-management/reports-and-export/feedback-dashboard) ## Overview [#overview] The **Feedback Dashboard** provides detailed analytics and management for each individual feedback form. Unlike the project-wide Overview dashboard, this dashboard focuses on a single feedback configuration, giving you insights into audience behavior, responses, and distribution settings. ## Data Points [#data-points] The Feedback Dashboard includes the following sections, accessible via the top navigation tabs: * **Audience Overview** — Key metrics (Responses, Views, Response Rate), response time distribution, and views/submissions by time * **Responses Summary** — Aggregated summary of all responses to the feedback form * **Individual Responses** — Browse and manage each submission individually * **Destinations** — Configure where feedback data is sent (integrations, webhooks, etc.) * **Shareable Links** — Create and manage links for sharing the feedback form Use the date range selector (e.g., "Last 7 Days") and condition filters to narrow down the data. The dashboard also provides actions such as stopping feedback collection and exporting or printing reports. ## Report Views [#report-views] * **[Audience Overview](/docs/feedback-management/reports-and-export/feedback-dashboard/audience-overview)** — Metrics, response time stats, and engagement over time * **[Responses Summary](/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary)** — Summary of all responses * **[Individual Responses](/docs/feedback-management/reports-and-export/feedback-dashboard/individual-responses)** — View and manage each response * **[Destinations](/docs/feedback-management/reports-and-export/feedback-dashboard/destinations)** — Feedback routing and integrations * **[Shareable Links](/docs/feedback-management/reports-and-export/feedback-dashboard/shareable-links)** — Manage feedback form links # Individual Responses (/docs/feedback-management/reports-and-export/feedback-dashboard/individual-responses) ## Individual Responses [#individual-responses] The **Individual Responses** tab lets you browse and manage each feedback submission one by one. Use it when you need to review specific answers, follow up with respondents, or export detailed response data. ### What You'll See [#what-youll-see] * **Response list** — All submissions in a list or table format * **Full response details** — Each answer to every question in the form * **Metadata** — Timestamp, channel, language, country, and other attributes when available * **Source tracking** — UTM tags and click IDs captured from the page URL when [Source Tracking](/docs/feedback-management/advanced-options/source-tracking) is enabled on the form When **[Logic jumps](/docs/feedback-management/form-builder/logic-jumps)** are enabled for a form, open a response and switch to **Respondent path** to see only the questions that person actually visited—not the full form outline. ### Use Cases [#use-cases] * Review and respond to specific feedback * Identify outliers or notable submissions * Export individual responses for analysis or CRM integration * Filter and search responses by criteria Use the date range and condition filters to focus on a subset of responses. # Responses Summary (/docs/feedback-management/reports-and-export/feedback-dashboard/responses-summary) ## Responses Summary [#responses-summary] The **Responses Summary** tab provides an aggregated view of all responses submitted to your feedback form. Use it to see trends, distributions, and high-level insights without drilling into individual submissions. ### What You'll See [#what-youll-see] * **Aggregated data** — Totals, averages, and distributions across all responses * **Question-level summaries** — How respondents answered each question * **Trends over time** — How response patterns change across your selected date range ### Use Cases [#use-cases] * Understand overall sentiment or satisfaction * Identify common themes or patterns in feedback * Compare response distributions across different time periods * Export summary data for reporting or presentations Use the date range and condition filters to narrow the summary to specific audiences or timeframes. ## Add report breakdowns [#add-report-breakdowns] Use **Add Breakdowns** in the shared report filter bar to split the results by up to three dimensions. Choose a property from: * **Feedback Fields** — Answers and fields captured by the form * **Segments** — Saved audience segments * **User traits** — Properties attached to identified users * **Context variables** — Metadata passed when the form opens * **Source Tracking** — Campaign fields such as `utm_source`, `utm_medium`, and `utm_campaign` Breakdown selector with feedback fields, segments, user traits, context, and source tracking Add breakdowns in the order you want to inspect them. For example, start with a plan or account segment, then add device and campaign source to find where a change is concentrated. You can drill into a segment as its own filtered report. Date range, conditions, and breakdown choices are shared across the supported report views, so the same scope carries as you move between them. ## Save the report view [#save-the-report-view] When a combination of filters, breakdowns, and layout is useful more than once, save it as a [Dashboard Preset](/docs/feedback-management/reports-and-export/dashboard-presets). # Shareable Links (/docs/feedback-management/reports-and-export/feedback-dashboard/shareable-links) ## Shareable Links [#shareable-links] The **Shareable Links** tab lets you create and manage links for sharing your feedback form. Use it to distribute the form via email, social media, or embedded on your website. ### What You'll See [#what-youll-see] * **Existing links** — All shareable URLs created for this feedback form * **Link settings** — Custom slugs, expiration, or tracking parameters * **Create new links** — Generate additional shareable URLs for different campaigns or channels ### Use Cases [#use-cases] * Share the form via email or messaging * Embed the form on specific pages or campaigns * Create unique links for A/B testing or channel attribution * Track which links drive the most responses Manage your shareable links here to control how and where your feedback form is distributed. # Targeting Overview (/docs/feedback-management/targeting-and-triggers/targeting) Targeting under **Distribution → In-App** lets you decide exactly who sees your feedback form. Think of it as your audience control center—you get to choose whether your form reaches everyone or just the right people, whether they're browsing anonymously or logged in, and whether they're on mobile, desktop, or a specific country. Getting this right means better feedback quality and a smoother experience for your users. In-App targeting controls ## Why targeting matters [#why-targeting-matters] Targeting helps you: * **Reach the right people** — Show feedback forms to users who are most likely to give useful input (e.g., beta testers, specific segments, or new visitors). * **Avoid feedback fatigue** — Exclude users who already saw or responded to similar forms so you don't overwhelm them. * **Match context** — Target by language, country, or device so feedback is relevant to each user's environment. * **Improve response quality** — Focus on the audience that matters for each campaign instead of showing forms to everyone. ## Distribution areas [#distribution-areas] The **Distribution** area has three sections: 1. **[In-App Feedback](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback)** — Forms shown inside your app or website to visitors and logged-in users. 2. **[Link & Email](/docs/shareable-feedback/feedback-links)** — Shareable links you can send through external channels. 3. **[Advanced Options](/docs/feedback-management/advanced-options)** — Availability, response, and collection settings scoped to the applicable distribution method. You can enable one, both, or neither, depending on how you want to collect feedback. ## Quick workflow summary [#quick-workflow-summary] 1. Open your feedback form and go to **Distribution**. 2. Decide how you want to distribute: * **Link & Email** — Create links for external sharing. * **In-App** — Enable In-App Feedback and configure Visitors and/or Logged-in Users. 3. For Logged-in Users, choose **All** or **Selected** (and pick segments if Selected). 4. Optionally refine with **Past Interaction**, **User Language**, **Country**, and **Device Type**. 5. Fix any validation messages (e.g., "At least one feedback must be selected") by completing the required selections. 6. Save your changes. Your form will now appear only to the users you've targeted. # Triggers Overview (/docs/feedback-management/targeting-and-triggers/triggers) Ever wondered *when* your feedback form should pop up—and when it shouldn't? The **Triggers** tab is your control center for exactly that. Whether you want forms to appear the moment someone lands on a page, after they complete a purchase, or only when you explicitly call for it in code, triggers give you the flexibility to collect feedback at the right moment—without annoying your users. In-App Feedback Triggers - Manual and Automatic options ## Overview [#overview] Open **Distribution → In-App → Triggers**. Here you'll find two main trigger types: **Manual Trigger** and **Automatic Trigger**. You can enable one, both, or neither—depending on how you want to collect feedback. Each trigger type has its own settings and use cases, so you can mix and match to fit your workflow. The **Configuration overview** beside the trigger settings summarizes the active manual and automatic launch setup as you make changes. ## Trigger types [#trigger-types] | Trigger Type | Description | Use when | | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | | **[Manual Trigger](/docs/feedback-management/targeting-and-triggers/triggers/manual-trigger)** | Show the form on demand via code—whenever you decide it makes sense. | You want full control (e.g. "Contact us" buttons, help menus, custom flows). | | **[Automatic Trigger](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger)** | Show the form based on rules you define—no code required for the basic flow. | You want hands-off collection (e.g. after page visit, on event, after delay). | ## Why triggers matter [#why-triggers-matter] Triggers put you in control of the feedback experience. By choosing the right combination of manual and automatic triggers, launch types, recurrence, and location rules, you can: * **Collect feedback at the right moment** — When users are most engaged or have just completed an action. * **Avoid survey fatigue** — Use recurrence and follow-up settings to respect user time. * **Target specific flows** — Show forms only on checkout pages, help sections, or after key events. * **Stay flexible** — Use manual triggers for custom flows and automatic triggers for hands-off collection. Take a few minutes to configure your triggers—your future self (and your users) will thank you! # Manual Trigger (/docs/feedback-management/targeting-and-triggers/triggers/manual-trigger) The Manual Trigger lets you show your feedback form on demand—whenever you decide it makes sense. Perfect for "Contact us" buttons, help menus, or any moment where you want full control over when the form appears. Manual Trigger - Configuration and usage example ## Features and explanations [#features-and-explanations] | Feature | Explanation | | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Enable/Disable toggle** | Set Manual Trigger to **Enabled** when you want to launch the form from your application using the SDK. | | **Feedback Configuration UUID** | A unique ID (e.g. `bf90fbce-9826-49b9-bf2c-2ec107a5bfd2`) that identifies your form. Use this with `_encatch.showForm()` to display the form programmatically. | | **Form Slug** | A human-readable name (e.g. `customer-satisfaction-survey-2024`) that must be unique, alphanumeric lowercase with hyphens/underscores, 15–100 characters, and must start with a letter. Can be used instead of the UUID when calling `_encatch.showForm()`. | | **showForm() method** | Call `_encatch.showForm('your-uuid-or-slug')` in your application to programmatically display the form. You can use either the Form Slug or the UUID. | ## How to use the Manual Trigger [#how-to-use-the-manual-trigger] 1. Set **Manual Trigger** to **Enabled**. 2. **Get your identifiers** — You'll see a **Feedback Configuration UUID** and a **Form Slug** field. The slug is a human-readable name that must be unique, alphanumeric lowercase with hyphens/underscores, 15–100 characters, and must start with a letter. 3. **Call the method in your app** — Use `_encatch.showForm('your-uuid-or-slug')` in your application to programmatically display the form. You can use either the Form Slug or the UUID. # CDN / Script Tag (/docs/sdk-reference/web/installation-methods/cdn-script-tag) The **Encatch Web SDK** (`@encatch/web-sdk`) can be loaded from jsDelivr as an IIFE bundle. Add one ` ``` The IIFE build registers `_encatch` on `window`. Always pin a specific version in the URL (for example `@1.5.2`) rather than `@latest`, so production sites do not pick up breaking changes unexpectedly. The `jsdelivr` field in `@encatch/web-sdk` points to `dist/encatch.iife.js`. *** ## Initialize the client [#initialize-the-client] After the loader script tag, call `init()` with your publishable SDK key: ```html ``` Replace `'your-publishable-sdk-key'` with the key from **Settings → Security → Publishable SDK Keys**. Replace `'your-form-slug-or-uuid'` with either: * **Form Slug** — 15–100 characters, lowercase letters, digits, hyphens, and underscores; must start with a letter (configured under **Triggers → Manual Trigger** in the dashboard), or * **Feedback Configuration UUID** — the read-only UUID on the same Manual Trigger screen Only the **first** `init()` call runs — Encatch logs `[Encatch] SDK already initialized. Ignoring init call.` if `init()` is called again. After a successful `identifyUser()`, Encatch starts a session automatically; you do not need `startSession()` before identify. You may call `_encatch` methods immediately after the loader script; calls made before the remote script from `form.encatch.com` loads stay in the internal queue until the implementation is ready. ### Optional configuration [#optional-configuration] Pass a config object as the second argument to `init()`: ```html ``` | Option | Default | Description | | ------------------ | -------------------------- | --------------------------------------------------------------- | | `webHost` | `https://form.encatch.com` | Host that serves `/s/sdk/v1/encatch.js` and form iframes | | `apiBaseUrl` | `https://api.encatch.com` | Base URL for Encatch API requests | | `theme` | `'system'` | Form theme: `'light'`, `'dark'`, or `'system'` | | `debugMode` | `false` | Log SDK diagnostic messages to the console (development only) | | `isFullScreen` | `false` | Full-viewport form without modal overlay | | `onBeforeShowForm` | — | Return `false` to block the built-in iframe and use a custom UI | Override `webHost` or `apiBaseUrl` only for non-production Encatch environments (for example dev or UAT). See [Initialize the SDK](/docs/sdk-reference/web#initialize-the-sdk) in the client reference. *** ## Identify users [#identify-users] Encatch uses identified users for [in-app targeting](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback), [segments](/docs/segmentation/manual), and response attribution. Call `identifyUser` after `init()`: ```html ``` `userName` must be an ASCII identifier (1–50 characters: letters, digits, `.`, `_`, `@`, `-`). Email addresses and internal user IDs work when they match this format. For `$set`, `$setOnce`, `$increment`, secure HMAC signatures (optional **Secret key** on the publishable SDK key), and full username rules, see [Identify & track users](/docs/sdk-reference/web#identify--track-users). *** ## Content Security Policy [#content-security-policy] If your site sends CSP headers, allow **both** the jsDelivr loader and Encatch hosts. After `init()`, Encatch loads a **module** script from `form.encatch.com` and opens form iframes on the same host: ```http Content-Security-Policy: script-src 'self' https://form.encatch.com https://cdn.jsdelivr.net; connect-src 'self' https://api.encatch.com; frame-src 'self' https://form.encatch.com; ``` If you set custom `webHost` or `apiBaseUrl` in `init()`, whitelist those hosts in `script-src` / `frame-src` and `connect-src` respectively. See the full [Content Security Policy](/docs/sdk-reference/web#content-security-policy) section in the client reference. *** ## Next steps [#next-steps] Once installation and initialization are working, explore the full client API in the [Client Reference](/docs/sdk-reference/web) — automatic triggers, form events, pre-fill (`addToResponse`), source tracking, and session control. # NPM Package (/docs/sdk-reference/web/installation-methods/npm-package) The official [`@encatch/web-sdk`](https://www.npmjs.com/package/@encatch/web-sdk) npm package is the recommended way to integrate Encatch in React, Vue, Next.js, Astro, and other apps with a JavaScript build step. Install the package, import `_encatch`, and call `init()` with your publishable SDK key. The npm package ships the **ES module loader** (`dist/encatch.es.js`) and **TypeScript types** (`dist/index.d.ts`). Like the CDN loader, it is a stub — when you call `_encatch.init()`, Encatch injects the remote implementation from `https://form.encatch.com/s/sdk/v1/encatch.js`. API calls go to `https://api.encatch.com` by default. Commands sent before that remote script finishes loading are **queued** and replayed automatically. *** ## Overview [#overview] * **Package:** [`@encatch/web-sdk`](https://www.npmjs.com/package/@encatch/web-sdk) * **Version:** 1.5.2 * **Platforms:** Web (browser) * **Node.js:** `>= 18` * **Repository:** [github.com/get-encatch/web-sdk](https://github.com/get-encatch/web-sdk) - A **publishable SDK key** with your site listed under **Allowed Domains / Packages** Never embed the publishable key's **Secret Key** in client code. Use it only on your server to generate HMAC signatures for [secure identify](/docs/sdk-reference/web#verify-identity). *** ## What you need from the Encatch dashboard [#what-you-need-from-the-encatch-dashboard] Before installing the package: 1. **Publishable SDK key** — In your Encatch project, go to **Settings → Security → Publishable SDK Keys** and click **Create Publishable SDK Key**. Copy the full key when shown — Encatch displays it only once at creation. 2. **Allowed Domains / Packages** — On the same key, add your site origin (for example `https://app.example.com`). Up to **10** entries per key. Avoid `*` in production. 3. **Form slug or UUID** — Open your feedback form in the dashboard, go to **Triggers → Manual Trigger**, and copy the **Form Slug** or **Feedback Configuration UUID** for `showForm()`. See [Publishable SDK Keys](/docs/settings/security/publishable-sdk-keys) and [Form Builder](/docs/feedback-management/form-builder/build-feedback-form) for details. *** ## Install the package [#install-the-package] Navigate to your project root and install with your preferred package manager: ```bash npm install @encatch/web-sdk ``` ```bash yarn add @encatch/web-sdk ``` ```bash pnpm add @encatch/web-sdk ``` The package exposes the ES module entry as `"import": "./dist/encatch.es.js"` and TypeScript definitions at `dist/index.d.ts`. Re-exported types include `EncatchConfig`, `UserTraits`, `IdentifyOptions`, `Theme`, `ShowFormOptions`, and event payload types. *** ## Initialize the client [#initialize-the-client] Import `_encatch` and call `init()` with your publishable SDK key as early as possible on the **client** (browser) side: ```javascript import { _encatch } from '@encatch/web-sdk'; _encatch.init('your-publishable-sdk-key'); _encatch.startSession(); _encatch.showForm('your-form-slug-or-uuid'); ``` You can also use the default export: ```javascript import _encatch from '@encatch/web-sdk'; ``` Replace `'your-publishable-sdk-key'` with the key from **Settings → Security → Publishable SDK Keys**. Replace `'your-form-slug-or-uuid'` with either: * **Form Slug** — 15–100 characters, lowercase letters, digits, hyphens, and underscores; must start with a letter (configured under **Triggers → Manual Trigger** in the dashboard), or * **Feedback Configuration UUID** — the read-only UUID on the same Manual Trigger screen Only the **first** `init()` call runs — Encatch logs `[Encatch] SDK already initialized. Ignoring init call.` if `init()` is called again. After a successful `identifyUser()`, Encatch starts a session automatically; you do not need `startSession()` before identify. You may call `_encatch` methods immediately after `init()`; calls made before the remote script from `form.encatch.com` loads stay in the internal queue until the implementation is ready. ### Optional configuration [#optional-configuration] Pass a config object as the second argument to `init()`: ```javascript import { _encatch } from '@encatch/web-sdk'; _encatch.init('your-publishable-sdk-key', { theme: 'system', debugMode: false, onBeforeShowForm: async (payload) => { // Return false to skip the built-in modal iframe return true; }, }); ``` | Option | Default | Description | | ------------------ | -------------------------- | --------------------------------------------------------------- | | `webHost` | `https://form.encatch.com` | Host that serves `/s/sdk/v1/encatch.js` and form iframes | | `apiBaseUrl` | `https://api.encatch.com` | Base URL for Encatch API requests | | `theme` | `'system'` | Form theme: `'light'`, `'dark'`, or `'system'` | | `debugMode` | `false` | Log SDK diagnostic messages to the console (development only) | | `isFullScreen` | `false` | Full-viewport form without modal overlay | | `onBeforeShowForm` | — | Return `false` to block the built-in iframe and use a custom UI | Override `webHost` or `apiBaseUrl` only for non-production Encatch environments (for example dev or UAT). See [Initialize the SDK](/docs/sdk-reference/web#initialize-the-sdk) in the client reference. ### Next.js [#nextjs] Load and initialize the SDK on the client only. The Encatch loader relies on `window` and `document`, which are not available during server-side rendering. ```javascript 'use client'; import { useEffect } from 'react'; import { _encatch } from '@encatch/web-sdk'; export default function EncatchProvider({ children }) { useEffect(() => { _encatch.init('your-publishable-sdk-key', { theme: 'system' }); _encatch.startSession(); }, []); return children; } ``` Mount this provider once at your app root. Alternatively, use `next/dynamic` with `{ ssr: false }` for components that import `@encatch/web-sdk` directly. ### Vue.js [#vuejs] Import the package in a client-only lifecycle hook so `init()` never runs during SSR: ```javascript import { _encatch } from '@encatch/web-sdk'; export default { name: 'YourVueComponent', mounted() { _encatch.init('your-publishable-sdk-key'); _encatch.startSession(); }, }; ``` For Vue 3 Composition API, call `init()` inside `onMounted()`. ### Astro / Starlight [#astro--starlight] For documentation sites, see the full [Astro Starlight](/docs/integrations/documentation-platforms/astro-starlight) guide — it installs `@encatch/web-sdk` and initializes the SDK in a React island with `PUBLIC_ENCATCH_SDK_PUBLISHABLE_KEY`. *** ## Identify users [#identify-users] Encatch uses identified users for [in-app targeting](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback), [segments](/docs/segmentation/manual), and response attribution. Call `identifyUser` after `init()`: ```javascript _encatch.identifyUser('user@example.com', { $set: { name: 'Alice', plan: 'team' }, }); ``` `userName` must be an ASCII identifier (1–50 characters: letters, digits, `.`, `_`, `@`, `-`). Email addresses and internal user IDs work when they match this format. For `$set`, `$setOnce`, `$increment`, secure HMAC signatures (optional **Secret key** on the publishable SDK key), and full username rules, see [Identify & track users](/docs/sdk-reference/web#identify--track-users). *** ## Content Security Policy [#content-security-policy] When you install via npm, you do **not** need jsDelivr in CSP — the loader is bundled in your app. After `init()`, Encatch still loads a **module** script from `form.encatch.com` and opens form iframes on that host: ```http Content-Security-Policy: script-src 'self' https://form.encatch.com; connect-src 'self' https://api.encatch.com; frame-src 'self' https://form.encatch.com; ``` If you set custom `webHost` or `apiBaseUrl` in `init()`, whitelist those hosts in `script-src` / `frame-src` and `connect-src` respectively. See the full [Content Security Policy](/docs/sdk-reference/web#content-security-policy) section in the client reference. *** ## Next steps [#next-steps] Once installation and initialization are working, explore the full client API in the [Client Reference](/docs/sdk-reference/web) — automatic triggers, form events, pre-fill (`addToResponse`), source tracking, and session control. # Country (/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/country) **Country** lets you target users based on their geographic location. Show the form only to users in specific countries—useful for region-specific campaigns, compliance, or localized feedback. ## When to use [#when-to-use] * **All** — When you want feedback from users worldwide. Use for global campaigns or when location doesn't matter. * **Selected** — When you're running region-specific campaigns, need to comply with local regulations, or want feedback from users in particular markets. ## Options [#options] | Option | Behavior | | ------------ | ---------------------------------------------------------- | | **All** | Show the form to users in any country. | | **Selected** | Show the form only to users from the countries you select. | Country - Selected countries ## Configuration [#configuration] 1. Go to **Distribution → In-App → Targeting**. 2. Locate **Country** under the advanced targeting criteria. 3. Choose **All** or **Selected**. 4. If **Selected**, use the **Select countries...** dropdown to search and select countries. Selected countries appear as tags that you can remove with the X icon. 5. You can also add custom countries if needed. 6. If **Selected** is chosen, you must select at least one country to clear validation. ## Tips [#tips] * **Region-specific launches** — Target users in countries where you've just launched a feature. * **Compliance** — Restrict feedback collection to countries where you're legally allowed to collect data. * **Combine with language** — Use Country and [User Language](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/user-language) together for highly localized campaigns. ## Related [#related] * [User Language](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/user-language) — Target by browser or device language * [Device Type](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/device-type) — Target by device # Device Type (/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/device-type) **Device Type** lets you target users based on the device they're using. Show the form on desktop only, mobile only, or specific combinations—useful when your form or campaign is optimized for certain devices. ## When to use [#when-to-use] * **All** — When you want feedback from users on any device. Use for general campaigns or when your form works well everywhere. * **Selected** — When you're testing a mobile-specific feature, running a desktop-only survey, or want to focus on a particular platform (e.g., native app users). ## Options [#options] | Option | Behavior | | ------------ | -------------------------------------------------- | | **All** | Show the form on all device types. | | **Selected** | Show the form only on the device types you choose. | Device Type - Web and Native options ## Device types [#device-types] When **Selected** is chosen, you can pick from: ### Web [#web] | Type | Description | | ----------- | --------------------------- | | **Desktop** | Desktop and laptop browsers | | **Tablet** | Tablet browsers | | **Mobile** | Mobile browsers | ### Native [#native] | Type | Description | | ----------- | ---------------------- | | **Android** | Android native apps | | **iOS** | iOS native apps | | **Others** | Other native platforms | ## Configuration [#configuration] 1. Go to **Distribution → In-App → Targeting**. 2. Locate **Device Type** under the advanced targeting criteria. 3. Choose **All** or **Selected**. 4. If **Selected**, select the device types where the form should appear. ## Tips [#tips] * **Mobile-first features** — Target mobile or tablet when collecting feedback on mobile-specific UX. * **Desktop surveys** — Use desktop only for longer surveys that work better on larger screens. * **Native app feedback** — Target Android or iOS when you want feedback specifically from app users. ## Related [#related] * [User Language](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/user-language) — Target by language * [Country](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/country) — Target by geographic location # In-App Feedback Overview (/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback) **In-App Feedback** controls who sees the form when they're using your app or website. You can target visitors (anonymous users) and logged-in users separately, then refine with language, country, device type, and past interaction. In-App Feedback targeting options ## What is In-App Feedback? [#what-is-in-app-feedback] In-App Feedback is configured under **Distribution → In-App**. Unlike shareable links under **Link & Email**, In-App Feedback displays forms directly inside your application or website. Users encounter the form as they browse—whether they're anonymous visitors or logged-in users—and you control exactly who sees it. The setup is organized into three steps: **Targeting**, **Triggers**, and **Integration**. A **Configuration overview** beside the setup updates as you make changes and summarizes both who will see the form and how it will launch. ## Core targeting options [#core-targeting-options] | Feature | What it controls | | ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | | **[Visitors](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/visitors)** | Whether anonymous (non-logged-in) users see the form | | **[Logged-in Users](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/logged-in-users)** | Whether authenticated users see the form, and which segments to include or exclude | ## Advanced targeting criteria [#advanced-targeting-criteria] These options apply to both Visitors and Logged-in Users and let you narrow down the audience further: * **[Past Interaction](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/past-interaction)** — Exclude users who already saw or responded to specific feedback forms * **[User Language](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/user-language)** — Target by browser or device language * **[Country](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/country)** — Target by geographic location * **[Device Type](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/device-type)** — Target by device (desktop, mobile, tablet, native apps) ## Quick workflow [#quick-workflow] 1. Open your feedback form and go to **Distribution → In-App → Targeting**. 2. Enable **In-App Feedback** and configure **Visitors** and/or **Logged-in Users**. 3. For Logged-in Users, choose **All** or **Selected** (and pick segments if Selected). 4. Optionally refine with Past Interaction, User Language, Country, and Device Type. 5. Fix any validation messages by completing required selections. 6. Save your changes. ## Tips for better targeting [#tips-for-better-targeting] * **Start broad, then narrow** — Begin with **All** for Visitors or Logged-in Users, then add filters (language, country, device) if you need more precision. * **Use Past Interaction to reduce fatigue** — Exclude users who already responded to similar forms so you don't ask the same people repeatedly. * **Combine criteria** — You can use multiple filters together (e.g., English-speaking users in the US on mobile) for highly specific campaigns. * **Check validation messages** — Red warning icons and messages indicate incomplete settings. Complete the required selections to clear them. # Logged-in Users (/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/logged-in-users) For users who are logged in, you can choose whether everyone sees the form or only users in specific segments. This lets you run targeted campaigns for beta testers, premium users, specific departments, or any group you've defined. ## When to use [#when-to-use] * **Disabled** — When you only want feedback from visitors (anonymous users). * **All** — When every logged-in user should see the form. Good for broad feedback campaigns. * **Selected** — When you want to target specific segments (e.g., premium plan users, beta testers, users who completed a certain action). ## Options [#options] | Option | Behavior | | ------------ | --------------------------------------------------------------------------------------------------------------------------- | | **Disabled** | Logged-in users will not see the form. | | **All** | All logged-in users can see the form. | | **Selected** | Only users in specific segments can see the form. You'll need to choose which segments to include (and optionally exclude). | Logged-in Users - Include and exclude segments ## Configuration (Selected mode) [#configuration-selected-mode] When **Selected** is chosen: 1. **Include User Segments** — Select one or more segments. Only users in these segments will see the form. 2. **Exclude User Segments (Optional)** — Optionally exclude users in certain segments. Users in excluded segments will not see the form even if they're in an included segment. Use the search bar in the segment dropdown to find segments quickly. If you choose **Selected** but don't pick at least one segment to include, you'll see a validation message until the configuration is complete. ## User Segmentation [#user-segmentation] Segments are groups of users defined by attributes, behavior, or hand-picked lists. encatch supports **data-driven** segments (rules that update automatically) and **manual** segments (fixed username lists). To create segments for targeting, see [Segmentation overview](/docs/segmentation/overview). For condition types (traits, tracked events, feedback interaction, and feedback response), see [Data-driven segments](/docs/segmentation/data-driven). To reduce overlap with users who already saw other forms, combine segment targeting with [Past Interaction](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/past-interaction). ## Related [#related] * [Visitors](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/visitors): Target anonymous users * [Segmentation overview](/docs/segmentation/overview): Create and manage segments * [Data-driven segments](/docs/segmentation/data-driven): Build segments with traits, events, and feedback conditions * [Manual segments](/docs/segmentation/manual): Hand-picked username lists * [Past Interaction](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/past-interaction): Exclude users based on prior form activity # Past Interaction (/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/past-interaction) **Past Interaction** lets you control whether users who have already engaged with other feedback forms should see this one. This helps reduce feedback fatigue and ensures you're not repeatedly showing forms to the same people. ## When to use [#when-to-use] * **All** — When you want to include everyone, regardless of past feedback activity. Use for new campaigns or when overlap doesn't matter. * **Exclude** — When you want to avoid users who already saw or responded to specific forms. Use to prevent fatigue, run sequential campaigns, or target only fresh respondents. ## Options [#options] | Option | Behavior | | ----------- | ------------------------------------------------------------------------------------------------------------------------------ | | **All** | Include everyone, regardless of past feedback activity. | | **Exclude** | Exclude users based on their past interactions. You can choose to exclude: | | | • **Users who saw these feedbacks** — Users who viewed specific feedback forms will not see this one. | | | • **Users who responded to these feedbacks** — Users who submitted responses to specific feedback forms will not see this one. | Past Interaction - Exclude options ## Configuration [#configuration] 1. Go to **Distribution → In-App → Targeting**. 2. Locate **Past Interaction** under the advanced targeting criteria. 3. Choose **All** or **Exclude**. 4. If **Exclude**, select at least one feedback form for either "saw" or "responded" to complete the configuration. Otherwise, a validation message will appear. ## Tips [#tips] * **Exclude responders** — Use "Users who responded to these feedbacks" when you want fresh respondents who haven't already given feedback on similar topics. * **Exclude viewers** — Use "Users who saw these feedbacks" when you want to avoid users who were exposed to a form but didn't submit (e.g., to retry with a different form or message). * **Combine both** — You can exclude both viewers and responders of different forms for fine-grained control. ## Related [#related] * [Visitors](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/visitors): Target anonymous users * [Logged-in Users](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/logged-in-users): Target authenticated users and segments * [Segmentation overview](/docs/segmentation/overview): Build audiences with data-driven or manual segments # User Language (/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/user-language) **User Language** lets you target users based on their browser or device language. Show the form only to users whose language matches your form content, or run multilingual campaigns by targeting specific languages. ## When to use [#when-to-use] * **All** — When your form is language-agnostic or you're using automatic translation. Use for simple feedback that doesn't depend on language. * **Selected** — When you want to match form language to user language, run language-specific campaigns, or ensure users see content in their preferred language. ## Options [#options] | Option | Behavior | | ------------ | -------------------------------------------------------------------------------------------------- | | **All** | Show the form to users regardless of language. | | **Selected** | Show the form only to users whose browser/device language matches one of the languages you select. | User Language - Selected languages ## Configuration [#configuration] 1. Go to **Distribution → In-App → Targeting**. 2. Locate **User Language** under the advanced targeting criteria. 3. Choose **All** or **Selected**. 4. If **Selected**, use the **Select languages...** dropdown to pick languages. Selected languages appear as tags that you can remove with the X icon. 5. If **Selected** is chosen, you must select at least one language to clear validation. ## Tips [#tips] * **Match form language** — If your form is in English only, consider targeting English-speaking users to avoid confusion. * **Localized campaigns** — Run separate forms for different languages and target each to its corresponding user language. * **Browser vs. app** — Language is detected from the browser (web) or device (native) settings. ## Related [#related] * [Country](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/country) — Target by geographic location * [Device Type](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/device-type) — Target by device # Visitors (/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/visitors) **Visitors** are users who are not logged in. When enabled, the feedback form is shown to anonymous visitors browsing your app or website. When disabled, only logged-in users can see it (if you've enabled [Logged-in Users](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/logged-in-users)). ## When to use [#when-to-use] * **Enabled** — Use when you want to collect feedback from anyone, including first-time visitors and users who haven't signed in. Ideal for general product feedback, onboarding surveys, or when you want maximum reach. * **Disabled** — Use when you only want feedback from authenticated users, such as for account-specific issues, feature requests tied to user data, or when you need to identify respondents. ## Options [#options] | Option | Behavior | | ------------ | ----------------------------------------------- | | **Disabled** | Anonymous visitors will not see the form. | | **Enabled** | Anonymous visitors can see and submit the form. | Use the information icon (ⓘ) next to each option for more details. ## Configuration [#configuration] 1. Go to **Distribution → In-App → Targeting**. 2. Locate the **Visitors** section. 3. Toggle **Disabled** or **Enabled** based on your targeting strategy. 4. Combine with [Logged-in Users](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/logged-in-users) if you want both audiences, or use one or the other. ## Related [#related] * [Logged-in Users](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback/logged-in-users) — Target authenticated users and segments * [Advanced targeting criteria](/docs/feedback-management/targeting-and-triggers/targeting/in-app-feedback) — Language, country, device, and past interaction # Delayed Launch (/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/delayed-launch) **Delayed Launch** waits a set amount of time after a user action before showing the form—giving users a moment to settle in before you ask for feedback. Delayed launch - Time and user action settings ## When to use [#when-to-use] * **Session warm-up** — Show the form a few seconds after a user starts a new session. * **Audience entry** — Wait after someone enters your target audience before prompting. * **First-time visitors** — Delay from the user's very first visit so they can explore first. ## Configuration [#configuration] **Launch Survey** — Enter a number and choose the unit (e.g. **5 seconds**, **2 minutes**, **1 day**). **After the user...** — Pick when the delay starts: * **Started a new session** — The timer begins when the user starts a new session. * **Entered target audience** — The timer begins when the user matches your targeting rules. * **Was seen for the very first time** — The timer begins on the user's first visit. ## Tips [#tips] * **Avoid survey fatigue** — A short delay (3–5 seconds) often works better than showing the form immediately on page load. For instant display with no anchor, use [Immediate Launch](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/immediate-launch) instead. * **Match the flow** — Use "Entered target audience" when you want the delay to start only after users qualify for your targeting rules. * **Combine with recurrence** — Use [Recurrence Settings](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/recurrence-settings) to avoid showing the form too often to the same user. ## Related [#related] * [Immediate Launch](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/immediate-launch) — Show the form right away when conditions are met * [Recurrence Settings](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/recurrence-settings) — Control how often the form appears * [On-Page Delay](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/on-page-delay) — Add a final delay after the launch condition is met # Follow-Up Mode (/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/follow-up-mode) **Follow-Up Mode** re-engages users who haven't reached the outcome you choose. Set a stop condition, a maximum number of attempts, the wait between attempts, and the total follow-up duration. Follow-Up Mode - Stop condition and timing ## When to use [#when-to-use] * **Increase completion rates** — Give users another chance when they have not completed the form. * **Choose the right endpoint** — Stop after a dismissal, a partial submission, or a completed submission. * **Respect successful submissions** — Use **Completed** so the follow-up sequence ends after the form is submitted. * **Control persistence** — Limit maximum attempts and add wait times to avoid being intrusive. ## Stop conditions [#stop-conditions] | Condition | When follow-up stops | | ---------------------- | ----------------------------------------------- | | **Dismissed** | Stop after the user dismisses the form. | | **Partial Submission** | Stop after the user submits a partial response. | | **Completed** | Stop after the user completes the form. | Follow-Up Mode - Stop condition options ## Configuration [#configuration] **Stop Condition** — Choose when to stop following up: **Dismissed**, **Partial Submission**, or **Completed**. **Maximum Attempts** — The maximum number of times to show the form to each user. Enter a value greater than 0. **Wait Between Attempts** — Enter a number and choose **Minutes**, **Hours**, or **Days**. This controls the pause before the next attempt. **Stop After Duration** — Enter a number and choose **Minutes**, **Hours**, **Days**, or **Weeks**. Follow-ups end after this duration from the first attempt, even when Maximum Attempts has not been reached. ## Tips [#tips] * **Use Completed for completion campaigns** — Keep the sequence active until the user submits, while the attempt and duration limits prevent over-messaging. * **Use Partial Save** — Enable [Partial Save](/docs/feedback-management/advanced-options/partial-save) so users can resume where they left off when the form reappears. * **Set reasonable limits** — Start with 2–3 attempts and enough time between them for users to return naturally. * **Combine with Recurrence** — [Recurrence Settings](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/recurrence-settings) control the overall cadence; Follow-Up Mode handles the re-engagement logic. ## Related [#related] * [Recurrence Settings](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/recurrence-settings) — Control how often the form appears * [Partial Save](/docs/feedback-management/advanced-options/partial-save) — Save incomplete responses for later # Immediate Launch (/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/immediate-launch) **Immediate Launch** shows the feedback form as soon as the user is eligible—no waiting period. Once targeting rules match and the automatic trigger is enabled, the form is offered on the next ping (or when the SDK checks for available feedback). Immediate launch - Launch type selection ## When to use [#when-to-use] * **Instant feedback** — Collect input right when a user enters your target audience or starts a session. * **Time-sensitive flows** — Show the form immediately after a support visit, onboarding step, or key product moment. * **Simple auto-trigger setup** — When you do not need a delay anchor (session start, first seen, or target audience entry). ## Configuration [#configuration] Select **Immediate** under **Choose when to launch** in the Automatic Trigger section. No additional launch settings are required—unlike [Delayed Launch](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/delayed-launch), there is no timer or "After the user..." anchor to configure. You can still refine behavior with: * **[On-Page Delay](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/on-page-delay)** — Add seconds after the launch condition is met. * **[Recurrence Settings](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/recurrence-settings)** — Control how often the form is shown to the same user. * **[Follow-Up Mode](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/follow-up-mode)** — Re-engage users who dismiss or partially complete the form. * **[Location Restrictions](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/location-restrictions)** — Limit which pages can show the form. ## How it differs from Delayed Launch [#how-it-differs-from-delayed-launch] | | **Immediate** | **Delayed** | | ----------------- | --------------------------------------------------- | -------------------------------------------------------------- | | **Timing** | Form is offered as soon as eligibility is confirmed | Form waits until a set time after a user action | | **Configuration** | No delay fields | **Launch Survey** duration + **After the user...** anchor | | **Best for** | Fast, in-context feedback | Giving users time to settle in before prompting | If you want a short pause without switching launch types, use [On-Page Delay](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/on-page-delay) with Immediate launch. ## Tips [#tips] * **Pair with targeting** — Immediate launch activates for eligible users quickly; narrow [Targeting](/docs/feedback-management/targeting-and-triggers/targeting) so only the right audience sees the form. * **Avoid survey fatigue** — Use [Recurrence Settings](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/recurrence-settings) or a small [On-Page Delay](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/on-page-delay) if showing the form on every eligible ping feels too aggressive. * **Need page- or event-based triggers?** — Use [Page Visit Launch](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/page-visit-launch) or [Tracked Event Launch](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/tracked-event-launch) when timing should depend on a specific URL or custom event. ## Related [#related] * [Delayed Launch](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/delayed-launch) — Wait after a user action before showing the form * [Automatic Trigger](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger) — All launch types and shared settings # Automatic Trigger (/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger) The **Automatic Trigger** shows your feedback form when your launch rules match—no `showForm()` call required. Enable it, pick a launch type, and the form appears when your conditions are met. Automatic Trigger - Launch types and settings overview ## What is the Automatic Trigger? [#what-is-the-automatic-trigger] The Automatic Trigger is one of two trigger types under **Distribution → In-App → Triggers**. Unlike the [Manual Trigger](/docs/feedback-management/targeting-and-triggers/triggers/manual-trigger), which requires you to call `showForm()` in code, the Automatic Trigger displays your form when launch rules match—you configure timing and conditions in the dashboard, and the SDK handles display. You choose when and where the form appears, and the system handles the rest. ## Choose when to launch [#choose-when-to-launch] | Launch Type | Icon | Description | | --------------------------------------------------------------------------------------------------------------------- | ---- | ----------------------------------------------------------------------- | | **[Immediate](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/immediate-launch)** | ▶ | Shows the form right away when the trigger condition is met. | | **[Delayed](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/delayed-launch)** | ⏱ | Waits a set amount of time after a user action before showing the form. | | **[Page Visit](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/page-visit-launch)** | 🌐 | Triggers when the user visits a page matching your URL rules. | | **[Tracked Event](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/tracked-event-launch)** | 📈 | Triggers when a specific event (e.g. purchase, form submit) occurs. | ## Additional settings [#additional-settings] These options refine *how often* and *where* the form appears: * **[Recurrence Settings](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/recurrence-settings)** — Control how often the form appears to each user—so you don't over-survey them. * **[Follow-Up Mode](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/follow-up-mode)** — Re-engage users who haven't completed the form. * **[On-Page Delay](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/on-page-delay)** — Add a delay in seconds after the launch condition is met. * **[Location Restrictions](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/location-restrictions)** — Control *where* on your site the form can appear. ## How to enable [#how-to-enable] 1. Go to **Distribution → In-App → Triggers** and expand **Automatic Trigger**. 2. Toggle the switch to **Enabled**. 3. Under **Choose when to launch**, select **Immediate**, **Delayed**, **Page Visit**, or **Tracked Event**. 4. Configure any additional settings (recurrence, follow-up, delay, location) as needed. ## Quick workflow [#quick-workflow] 1. Enable the Automatic Trigger. 2. Select a launch type (Immediate, Delayed, Page Visit, or Tracked Event). 3. Configure the launch type settings (e.g. delay time, URL rules, event name). 4. Optionally add recurrence, follow-up, on-page delay, or location restrictions. 5. Save your changes. ## Related [#related] * [Manual Trigger](/docs/feedback-management/targeting-and-triggers/triggers/manual-trigger) — Show the form on demand via code * [Targeting](/docs/feedback-management/targeting-and-triggers/targeting) — Control who sees your feedback forms # Location Restrictions (/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/location-restrictions) **Location Restrictions** control *where* on your site the form can appear. Use Include rules to specify pages where the form *should* show, and Exclude rules to hide it on specific pages—even if they match an include rule. Location Restrictions - Include and exclude pages ## When to use [#when-to-use] * **Site-wide feedback** — Use "All Pages" to show the form everywhere, then exclude specific pages (e.g. checkout, login). * **Targeted pages** — Use Include rules to show only on support pages, feature pages, or post-purchase flows. * **Avoid sensitive areas** — Exclude login, payment, or admin pages where a feedback form would be inappropriate. * **Refine Page Visit Launch** — Combine with [Page Visit Launch](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/page-visit-launch) for precise control. ## Configuration [#configuration] **All Pages** — Toggle on to show the form on every page. When off, you must add Include rules to specify where it appears. **Include Rules** — When "All Pages" is off, add rules to specify where the form *should* appear. Choose a condition (e.g. **Contains**, **Starts with**) and enter a URL or pattern. The form appears on pages matching *any* rule. **No Exclusions** — Toggle on to allow the form on all included pages. When off, Exclude rules apply. **Exclude Rules** — When "No Exclusions" is off, add rules so the form does *not* appear on certain pages—even if they match an Include rule. Exclude rules take precedence. ## Matching conditions [#matching-conditions] The same URL matching options as [Page Visit Launch](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/page-visit-launch) are available: Equals, Starts with, Contains, Pattern match (regex), and relative path variants. ## Tips [#tips] * **Exclude checkout and auth** — Avoid showing feedback forms on payment, login, or signup pages. * **Use relative paths** — Keeps rules portable across staging and production. * **Order matters for clarity** — Exclude rules override Include rules; list exclusions for pages you want to explicitly block. * **Test edge cases** — Verify the form appears (or doesn't) on key URLs before going live. ## Related [#related] * [Page Visit Launch](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/page-visit-launch) — Trigger on specific page visits * [Targeting](/docs/feedback-management/targeting-and-triggers/targeting) — Control who sees the form # On-Page Delay (/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/on-page-delay) **On-Page Delay** waits a set number of seconds after the selected launch condition is met. Set it to **0** to show the form immediately. On-page delay in seconds ## When to use [#when-to-use] * **User orientation** — Give users a moment to understand the page before asking for feedback. * **Smooth display** — Let the surrounding interface settle before the form appears. * **Less interruption** — Add a short pause when immediate display would feel abrupt. * **Immediate display** — Set to **0** when you want the form to show as soon as the trigger condition is met. ## Configuration [#configuration] **On-page delay** — Enter the number of seconds to wait after the trigger condition is met. Set it to **0** to show immediately. ## How it differs from Delayed Launch [#how-it-differs-from-delayed-launch] | Setting | What it controls | | ------------------ | ------------------------------------------------------------------------------------------------------- | | **Delayed Launch** | Starts its timer from a selected user milestone, such as session start or entering the target audience. | | **On-Page Delay** | Adds seconds after the configured launch condition has been met. | Both can be used together. The delayed launch condition is evaluated first, followed by the on-page delay. ## Tips [#tips] * **Start with 2–3 seconds** — This is often enough to soften the interruption without making the form feel late. * **Use 0 for event triggers** — When triggering on a Tracked Event (e.g. purchase), the user has already acted; a page delay may not be needed. * **Test on slow connections** — Ensure the delay doesn't feel excessive when the page loads slowly. ## Related [#related] * [Immediate Launch](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/immediate-launch) — Show the form right away when conditions are met * [Delayed Launch](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/delayed-launch) — Delay from user action * [Page Visit Launch](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/page-visit-launch) — Trigger on page visits # Page Visit Launch (/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/page-visit-launch) **Page Visit Launch** triggers the form when users land on pages matching your URL rules. Use it for post-checkout surveys, feature-specific feedback, support pages, or any flow where you want feedback tied to specific pages. Page Visit - URL rules and matching options ## When to use [#when-to-use] * **Post-checkout surveys** — Show the form on the thank-you or confirmation page. * **Feature-specific feedback** — Trigger on pages for a particular feature or product. * **Support pages** — Collect feedback from users who visited help or documentation. * **Landing pages** — Gather feedback from visitors who reached a specific campaign page. ## Configuration [#configuration] **Add Rule** — Add page visit rules. The form triggers when the user visits a page matching *any* of these rules. **Matching conditions** — Choose how URLs are matched: | Condition | Description | | ----------------------------- | ------------------------------------- | | **Equals** | Exact URL match | | **Starts with** | URL begins with the specified string | | **Contains** | URL contains the specified string | | **Pattern match (regex)** | URL matches a regular expression | | **Relative path equals** | Path (without domain) matches exactly | | **Relative path starts with** | Path begins with the specified string | | **Relative path contains** | Path contains the specified string | | **Relative pattern match** | Path matches a regular expression | ## Tips [#tips] * **Use relative path** — When your site has multiple domains (e.g. staging vs production), relative path conditions keep rules portable. * **Combine rules** — Add multiple rules to cover variations (e.g. `/checkout/thank-you` and `/order/confirmation`). * **Test your regex** — If using pattern match, verify your regex against sample URLs before saving. * **Pair with targeting** — Use [Targeting](/docs/feedback-management/targeting-and-triggers/targeting) to further narrow who sees the form on those pages. ## Related [#related] * [Location Restrictions](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/location-restrictions) — Control where the form can appear * [Tracked Event Launch](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/tracked-event-launch) — Trigger on specific user actions # Recurrence Settings (/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/recurrence-settings) **Recurrence Settings** control how often the form can appear to each user. Set a required **Show every** interval and, if needed, an optional **Stop after** duration. Recurrence Settings - Show every and Stop after ## When to use [#when-to-use] * **Reduce survey fatigue** — Show the form at most once per week (or your chosen interval). * **Time-bound campaigns** — Use Stop After to stop showing the form after a set period (e.g. 30 days). * **Ongoing feedback** — Leave Stop After empty to keep collecting feedback indefinitely at the set interval. * **Post-launch feedback** — Show the form every few days for a limited time after a release. ## Configuration [#configuration] **Show every** — Enter a number greater than 0 and choose **Minutes**, **Hours**, **Days**, **Weeks**, **Months**, or **Years**. The form will not appear to that user again until the interval has passed. **Stop after (optional)** — Enter a number and choose a unit to limit how long recurrence continues. Leave both fields empty to keep showing the form indefinitely at the selected interval. ## Tips [#tips] * **Balance frequency and coverage** — Shorter intervals reach users more often but can feel intrusive. Longer intervals collect feedback more gradually. * **Combine with Follow-Up Mode** — Use [Follow-Up Mode](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/follow-up-mode) to re-engage users who dismissed or partially completed the form, while Recurrence controls the overall cadence. * **Match your product cycle** — If users engage weekly, a 7-day interval often works well. For daily users, consider 3–5 days. ## Related [#related] * [Follow-Up Mode](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/follow-up-mode) — Re-engage users who haven't completed the form * [Throttling](/docs/feedback-management/advanced-options/throttling) — Limit views and responses globally or per user # Tracked Event Launch (/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/tracked-event-launch) **Tracked Event Launch** shows the form when users perform specific actions—like completing a purchase, submitting a form, or reaching a milestone. You define the event name in your app, and the form appears when that event occurs (optionally after a minimum count within a time period). Tracked Event - Event name, minimum count, and time period ## When to use [#when-to-use] * **Post-purchase feedback** — Trigger when `purchase_completed` or similar events fire. * **Form submission follow-up** — Show the form after a user submits a contact or signup form. * **Milestone feedback** — Collect feedback when users reach a key milestone (e.g. first project created, 10th task completed). * **Feature adoption** — Trigger when users complete an onboarding step or use a new feature. ## Prerequisites [#prerequisites] **Allow track for visitors** — Enable this in your project settings so that events from anonymous visitors can trigger the form. If you only need logged-in user events, you can leave this disabled. ## Configuration [#configuration] **Event Name** — The event identifier you send from your app (e.g. `purchase_completed`, `form_submitted`). Must match exactly the event name used in your tracking code. **Minimum Count** — How many times the event must occur before the form shows. Default is 1 (form shows on first occurrence). **Time Period** — The window in which the minimum count must be met. For example, "user was first seen" or a custom time range. ## Tips [#tips] * **Name events consistently** — Use clear, lowercase names with underscores (e.g. `checkout_completed`, `trial_started`). * **Avoid over-triggering** — Use Minimum Count > 1 for events that can fire frequently (e.g. page views, clicks). * **Document your events** — Keep a list of event names and when they fire so your team can configure triggers correctly. * **Test before launch** — Send test events and verify the form appears as expected. ## Related [#related] * [Page Visit Launch](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/page-visit-launch) — Trigger on page visits * [Recurrence Settings](/docs/feedback-management/targeting-and-triggers/triggers/automatic-trigger/recurrence-settings) — Limit how often the form appears