Intunix

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.

code
// 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 again

In React and Vue there is a hook that ties this to the component lifecycle:

code
// 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.

code
client.showForm('nps_q4')                 // by slug
client.showForm('cx_01H8...')             // or by id
client.showForm('nps_course', { context: { courseId: 'c-102' } })
Manual shows still respect cadence

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.

GateWhere it livesWhat it controls
Available in Web SDK sdk_enabledIntunix console, per formEnforced by the backend unconditionally. A form without it is excluded from the response no matter what your code requests.
registerYour app, at init or at runtimeWhich 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.

ConfigWhat is fetchedBehaviour
register: 'all'Every SDK-enabled formForms marked autoActivate in the console show themselves with no host code at all.
register: ['nps_q4']Only the forms listedTheir triggers go live.
omitted, or []Nothing. No catalog request is made at all.Only showForm(id) works, pulling that one form on demand.
Which should you use?

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:

code
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's target CSS 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.