Skip to content

Analytics & GTM

iConfigure records configurator sessions in the Manager dashboard when tracking is enabled on a product. On the host page (script inject), the tracking store also pushes events to window.dataLayer when that array exists — Google Tag Manager listens to those pushes.

Implementation source: packages/stores/tracking.js in the v2 monorepo.

Enable tracking

  1. Open Manager → your product → Submission & tracking.
  2. Enable Enable tracking to get insights (tracking_enabled on the product).
  3. Save and publish the product.

On load, _StartProductTracking in the form store starts a session and inserts a row in the Supabase tracking table. The same data appears on Dashboard and Export data → tracking.

If the insert fails, tracking is disabled for that session (no further ic_* events).

iFrame vs inject

Embed modeHost-page GTM
iFrameConfigurator JS runs in the iframe's own window. Host-page GTM does not see dataLayer.push calls.
Script injectConfigurator runs on the host windowuse this for GTM / GA4 on your site.

The code does not check embed mode explicitly; it only checks typeof dataLayer !== 'undefined'. Inject works because configurator and GTM share the same window.

Prerequisites on the host page

  1. Tracking enabled on the product in Manager.
  2. window.dataLayer must exist before the session starts — normally created by the GTM container snippet. Minimal alternative:
html
<script>window.dataLayer = window.dataLayer || [];</script>
  1. Load GTM before inject.iife.js and injectApp(). See Script inject.

GTM itself is optional; any script that defines dataLayer is enough for the pushes to land somewhere you can read.

dataLayer events (verified)

EventWhenSupabase
ic_setupSession starts after product loadInsert
ic_stepOn every configurator step changeUpdate
ic_form_showThe submission (quote) form becomes visible
ic_updateFeature change recorded + debounce (see below)Update
ic_finishSuccessful submit (info step / quotation)Update

Additionally, every successful submit pushes the legacy offerte_submit event (v1 format, flat offer fields) — independent of tracking_enabled — the moment the submit button is pressed. The host page only receives the quotation/finished postMessage at least 1 second later, so the redirect to the thank-you page never outraces the event.

The ic_step and ic_form_show events use a flat shape (no data wrapper) so they are directly usable in GTM:

javascript
{ event: 'ic_step', step: <1-based number>, step_name: '<step name>', product_id, company_id, dealer_id, total_price }
{ event: 'ic_form_show', step: <1-based number>, product_id, company_id, dealer_id, total_price }

step is always the human-facing 1-based step number (UI step 2 → step: 2). The submission form is not a step value: the moment the form becomes visible is tracked by the separate ic_form_show event — fired on the output-button click that reveals the form (e.g. "vraag offerte aan"), or on entering the info_form step when the product has no output buttons and shows the form directly. It fires on every reveal, so deduplicate in GTM if you need uniques.

ic_step and ic_form_show are always pushed (even without tracking_enabled); the matching updates[] write to Supabase only happens during an active tracking session for ic_step, and never for ic_form_show (dataLayer-only). The product_id / company_id / dealer_id fields are only populated during an active tracking session — without tracking_enabled they are null.

Each push has the shape:

javascript
{ event: 'ic_setup' | 'ic_update' | 'ic_finish', data: { /* tracking object */ } }

data object (all events)

FieldDescription
user.devicee.g. smartphone, desktop
user.browsere.g. Chrome, Mobile Safari
user.ose.g. iOS, Windows
product_idProduct UUID
company_idCompany UUID
dealer_idDealer UUID or null
finishedfalse until submit; true on ic_finish
time.loadingMs from navigation start (approx.)
time.totalMs from session start (set on update/finish)
updates[]Step, feature ID, value, timestamp, timeSpentOnFeature, totalPrice

ic_setup

Fired once in trackingSetup, immediately before the Supabase insert.

ic_update — debounce

Fired from trackingUpdate when both are true:

  1. A feature change was recorded in updates[].
  2. lastChange.time - tracking.lastSync > 3000 (3 second gap).

So it is not a fixed 3-second interval timer; rapid clicks may batch into fewer pushes.

Which interactions call trackingUpdate today:

UI pathic_update
Number inputs (FormFeatureNumberBox)Yes
Radio/checkbox via legacy SelectInput (form app)Yes
Most other display widgets (buttons, toggles, dropdowns in ui-components)Not wired yet

ic_setup and ic_finish still fire regardless. For full step-level GTM on button/toggle configurators, treat ic_finish as the conversion event until selection widgets emit updates.

ic_finish

Fired in trackingFinish when submit completes successfully (useSubmitQuote, cart flow). Adds an update with changedFeature: 'info_form' and sets finished: true.

GTM setup example

1. Container snippet (head)

Standard GTM install — creates dataLayer.

2. Custom Event trigger

SettingValue
Trigger typeCustom Event
Event nameic_finish (conversion), ic_form_show (form view / funnel), or ic_update (engagement)

Repeat for ic_setup if you need a session-start tag.

3. Data Layer Variables

Create Data Layer Variable types in GTM:

Variable nameData Layer Variable Name
DL - product iddata.product_id
DL - finisheddata.finished
DL - total timedata.time.total

For the last feature changed, use a Custom JavaScript variable or map from data.updates in a tag template.

4. GA4 event tag (example)

SettingValue
Tag typeGoogle Analytics: GA4 Event
Event nameiconfigure_finish
TriggerCustom Event ic_finish
Event parameter product_idGTM variable DL - product id

Debug checklist

  1. Product has tracking enabled in Manager.
  2. Page uses script inject, not iframe.
  3. GTM Preview open; dataLayer exists before configurator loads.
  4. Console after load:
javascript
window.dataLayer.filter((e) => e.event?.startsWith('ic_'))
  1. Change a number feature → expect ic_update after debounce.
  2. Complete submit → expect ic_finish with data.finished === true.

Manager analytics vs GTM

SourceUse case
Manager DashboardFunnel, conversion, step drop-off (Supabase tracking)
Export data → trackingRaw CSV
GTM / GA4Marketing tags on your domain

See Tracking & analytics for the Manager side.