Showing forms
A form appears in one of two ways: it auto-triggers because you registered it, or you open it yourself with showForm(). Understanding the difference — and the two gates in front of both — resolves most integration questions.
The two ways
Automatic — register it
Registering a form makes its triggers live. From then on it opens by itself the moment its trigger matches: a URL, a tracked event, time on page, exit intent. Register only where the form should be allowed to appear.
// At init, for the whole app:
await client.init('pk_live_xxx', { register: ['nps_q4', 'welcome'] })
// Or later, scoped to a page or component. Returns an unregister function:
const off = await client.register('exit_survey')
off() // stop it auto-triggering againIn React and Vue there is a hook that ties this to the component lifecycle:
// React
useRegisterForm('exit_survey') // registers on mount, unregisters on unmount
// Vue
useRegisterForm('exit_survey')Manual — call showForm()
Opens a form directly, from a click handler or any code path. No registration needed, and it works even for forms you never registered — the SDK fetches that single form on demand if it is not already cached.
client.showForm('nps_q4') // by slug
client.showForm('cx_01H8...') // or by id
client.showForm('nps_course', { context: { courseId: 'c-102' } })showForm() bypasses triggers, not the rules. Targeting, eligibility, and cadence are all re-checked at the moment the form would appear. If you are wiring a button the user clicks deliberately, set that form's cadence to always in the console — otherwise the second click does nothing and the user gets no feedback.
The two gates
A form is delivered to the SDK only when both of these agree. They are independent, and checking only one of them is the single most common cause of a form that never appears.
| Gate | Where it lives | What it controls |
|---|---|---|
Available in Web SDK sdk_enabled | Intunix console, per form | Enforced by the backend unconditionally. A form without it is excluded from the response no matter what your code requests. |
| register | Your app, at init or at runtime | Which of the enabled forms this particular install actually asks for. |
register modes
register is typed string[] | 'all', and it drives the network fetch itself — not merely which triggers are live.
| Config | What is fetched | Behaviour |
|---|---|---|
register: 'all' | Every SDK-enabled form | Forms marked autoActivate in the console show themselves with no host code at all. |
register: ['nps_q4'] | Only the forms listed | Their triggers go live. |
omitted, or [] | Nothing. No catalog request is made at all. | Only showForm(id) works, pulling that one form on demand. |
Prefer an explicit list. 'all' is convenient for marketing sites and the WordPress/Shopify plugins, but it means anyone with console access can make a form appear on your app without a code review. An explicit list keeps that decision in your repository.
One form at a time
Trigger matches and manual showForm() calls funnel through a single queue. If three forms qualify at once they appear one after another, never stacked. A form queued behind another has its eligibility re-checked when its turn arrives — so if a cooldown was reached while it waited, it is quietly dropped rather than shown late.
URL trigger delay
URL-triggered forms wait urlTriggerDelayMs (default 600 ms) before appearing, so they do not pop the instant a page loads. Tune it at init:
await client.init('pk_live_xxx', {
register: ['welcome'],
urlTriggerDelayMs: 1500,
})Where the form renders
Set per form in the console via its type:
modal— centred, with a backdrop.popup— a corner card that does not block the page.banner— a full-width strip.inline— mounted into an element on your page, selected by the form'stargetCSS selector. If the selector matches nothing, the SDK falls back to a fixed popup so the form is never lost off-screen.
Reacting to what the user did
The SDK reports outcomes internally to drive cadence and analytics, and also emits them as tracked events you can observe: $experience_impression, $experience_response, and $experience_dismissed. If you need to run your own code when a form is answered, listen for those rather than wrapping showForm() — it resolves when the form is enqueued, not when the user finishes.
Next: Triggers & targeting covers what makes a registered form actually fire.