Calcumate3D events
The calculator is a script embed in your page, so it talks to the page through standard DOM events. When it is loaded inside an iframe, it also mirrors the important moments to the parent frame with postMessage.
| Direction | Channel | Who uses it |
|---|---|---|
| calculator → page | CustomEvent on window, names calcumate:* |
script-tag embeds (same document) |
| calculator → page | the four unprefixed Calcumate (original) CustomEvents (CalcumateInitialized, CalculationFinished, Booking, userDetails) |
sites written for Calcumate (original). See Calcumate (original) hooks in Calcumate3D |
| calculator → parent frame | window.parent.postMessage({ type: 'CALCUMATE_*', … }) |
iframe embeds (cross-origin hosts) |
| page → calculator | CustomEvent on window (RE-INIT, RootLoaded, calcumateLoad) or postMessage('RE-INIT') into the iframe |
re-loading the configuration, mounting late containers, filtering the recommended units |
Events the calculator sends to your page
Section titled “Events the calculator sends to your page”All calcumate:* events are CustomEvents dispatched on window; the data is in event.detail.
| Event | When | event.detail |
|---|---|---|
calcumate:ready |
the configuration loaded and the calculator is initialised. Fires on every successful load: first boot, RE-INIT, and a CalcumateGEO facility change (each is a full reload). |
{ embedId } |
calcumate:error |
the configuration could not be loaded and the visitor sees a retryable error (network error, invalid token). | { code, message } |
calcumate:blocked |
the configuration was refused and the visitor sees a blocking modal (domain_mismatch, plan / calculator disabled). |
{ reason } |
calcumate:state-changed |
every screen transition (see the state table below). | { from, to, trigger } |
calcumate:calculated |
a calculation produced recommendations (the calculating → result transition). |
{ recommendationCount, bestMatch? } where bestMatch = { spaceUsedPct, unitCount, capacityVolumeCm3 } (omitted when the Calcumate service was unreachable and a local fallback packing is shown). |
calcumate:cta-click |
the visitor pressed the results CTA (“See pricing” / your label). Fires at the click, before the lead form and before any redirect, whatever the CTA settings. | { recommendationId, unitId, unitName, units: [{ id, name, count }] } — the recommendation the button belongs to, resolved to its unit identity. |
Calcumate (original): Booking |
right after cta-click, and again after the lead-form submit |
{ selectedCalculation, recommendation, items, location, cta: { url, label, resolvedUrl } }. See Booking |
calcumate:lead-captured |
the lead form (Builder: Request lead details) was submitted. | the cta-click detail + fields: [{ id, label, type, value }] |
States and triggers (calcumate:state-changed)
Section titled “States and triggers (calcumate:state-changed)”to |
Meaning |
|---|---|
loading |
boot; assets loading (initial state — never a to, only a from) |
intro |
the camera intro is playing (skipped for returning visitors and reduced-motion users) |
idle |
the entry screen (presets or category grid) |
staging |
the visitor is picking or editing items |
calculating |
a calculation request is in flight |
result |
recommendations are shown |
error |
a calculation failed |
Triggers: ASSETS_READY, INTRO_DONE, BROWSE, ITEM_ADDED, ITEM_CLEARED, CALCULATE, SUCCESS, ERROR, RETRY, ADJUST, EDIT, RESUME_RESULT, HOME. Only accepted transitions emit: adding a second item while already in staging is silent, and so is a trigger the current state ignores.
Typical sequences:
- First visit:
ready→loading → intro (ASSETS_READY)→intro → idle (INTRO_DONE). - Returning visitor:
ready→loading → idle (ASSETS_READY). - Browsing + calculating:
idle → staging (BROWSE)→staging → calculating (CALCULATE)→calculating → result (SUCCESS)+calculated. - A preset tile + Calculate:
idle → staging (ITEM_ADDED)then the calculating pair. - Re-calculating from results:
result → calculating (CALCULATE)→calculating → result. - Logo (home) from results:
result → idle (HOME); Start again:idle → result (RESUME_RESULT). - Emptying the inventory from anywhere:
… → idle (ITEM_CLEARED). - After a page refresh the calculator restores the visitor’s items and screen, so your page sees the normal sequence again (
idle → staging, and the calculating pair for a restored result).
Examples
Section titled “Examples”window.addEventListener('calcumate:ready', (e) => { console.log('calculator ready', e.detail.embedId)})
window.addEventListener('calcumate:state-changed', (e) => { const { from, to, trigger } = e.detail if (to === 'result') showBookNowBanner() analytics.track('calculator_state', { from, to, trigger })})
window.addEventListener('calcumate:calculated', (e) => { const { recommendationCount, bestMatch } = e.detail console.log(`${recommendationCount} options; best uses ${bestMatch?.unitCount} unit(s) at ${bestMatch?.spaceUsedPct}%`)})
window.addEventListener('calcumate:cta-click', (e) => { const { unitId, unitName, units } = e.detail // e.g. pre-select the unit on your booking page, or route the visitor yourself // when "Disable CTA redirection" is on in the Builder})
window.addEventListener('calcumate:lead-captured', (e) => { const { fields } = e.detail // [{ id, label, type, value }] const email = fields.find((f) => f.type === 'email')?.value})What the CTA settings change
Section titled “What the CTA settings change”These settings live in the Builder’s Advanced settings and Units steps.
| Builder setting | Effect on events |
|---|---|
| Disable CTA redirection ON | cta-click (and the Calcumate (original) Booking) still fire; the calculator does not navigate. Use the event to route the visitor. |
| Request lead details ON | cta-click → the lead form opens → lead-captured (and userDetails, then Booking again) on submit → then the redirect, if enabled. The lead is also posted to Calcumate and emailed to the configured recipients; lead data is never put in the CTA URL. |
| CTA URL params | The redirect URL gets cm-qty, cm-id (+ cm-ids), cm-volume, cm-used-volume, cm-volume-unit (m3 / ft3), cm-recommendation + one {unitId}={count} pair per unit, according to the toggles; cm-location whenever a CalcumateGEO facility is selected. Independent of the events. |
| Unit “reserve url” (Builder, per unit) | When the recommended unit has its own URL, the CTA opens that URL with no params instead of the global CTA URL. |
Messages to the parent frame (iframe embeds)
Section titled “Messages to the parent frame (iframe embeds)”When the calculator runs inside an iframe it also calls window.parent.postMessage(envelope, parentOrigin), where parentOrigin is taken from document.referrer. If the iframe is loaded with referrerpolicy="no-referrer" the origin is unknown and the messages are skipped.
Envelope: { type, payload, embedId, timestamp }.
type |
Mirrors | payload |
|---|---|---|
CALCUMATE_READY |
calcumate:ready |
— |
CALCUMATE_ERROR |
calcumate:error |
{ error } |
CALCUMATE_STATE_CHANGED |
calcumate:state-changed |
{ from, to, trigger } |
CALCUMATE_CALCULATION_COMPLETE |
calcumate:calculated |
{ recommendationCount } |
CALCUMATE_CTA_CLICKED |
calcumate:cta-click |
the same detail |
CALCUMATE_LEAD_CAPTURED |
calcumate:lead-captured |
the same detail |
// parent pagewindow.addEventListener('message', (e) => { // if (e.origin !== 'https://your-calculator-host.example') return const msg = e.data if (!msg || typeof msg.type !== 'string' || !msg.type.startsWith('CALCUMATE_')) return if (msg.type === 'CALCUMATE_STATE_CHANGED' && msg.payload.to === 'result') showBookNowBanner()})The unprefixed Calcumate (original) events are not mirrored to the parent frame; Calcumate (original) never used postMessage either. Forward them from the framed page yourself if you need them there: the React Native pattern (injectedJavaScript + window.ReactNativeWebView.postMessage) applies to any iframe.
Events your page can send to the calculator
Section titled “Events your page can send to the calculator”| Event | How | Effect |
|---|---|---|
RE-INIT |
window.dispatchEvent(new Event('RE-INIT')) — or, into an iframe, iframe.contentWindow.postMessage('RE-INIT', '*') / postMessage({ type: 'RE-INIT' }, '*') |
Reloads the configuration in place (fresh settings from the Builder) without re-mounting. Produces a new ready + the boot state-changed sequence. The snippet attributes are not re-read. |
RootLoaded |
window.dispatchEvent(new Event('RootLoaded')) |
Re-scans the page for [data-calcumate] containers and mounts the new ones (SPAs, modals opened after the one-second auto-retry). |
calcumateLoad |
window.dispatchEvent(new CustomEvent('calcumateLoad', { detail: ['unit-l'] })) |
Excludes those unit ids from the recommendations; [] re-enables all. A Calcumate (original) hook. Re-runs the calculation when results are on screen. window.listUnits lists the ids. See calcumateLoad. |
data-disable-list-results="true" + RE-INIT |
attribute on the container | Hides the recommendation list + CTA on the results screen; re-read on every RE-INIT. A Calcumate (original) hook. See data-disable-list-results. |
// after your SPA navigates to a page that contains the snippet's <div>window.dispatchEvent(new Event('RootLoaded'))
// after changing the calculator in the Builder, without reloading the pagewindow.dispatchEvent(new Event('RE-INIT'))Ordering guarantees
Section titled “Ordering guarantees”calcumate:readyis followed, in the same tick, byCalcumateInitialized; the pair precedes the firststate-changed.calcumate:calculatedis always preceded bystate-changed { to: 'calculating' }andstate-changed { to: 'result' }, and followed byCalculationFinished.calcumate:cta-clickis followed byBooking;calcumate:lead-capturedbyuserDetailsand then a secondBooking; thepostMessagetwin of each is sent right after theCustomEvent.- A CalcumateGEO facility pick is a full reload: expect a new
ready/CalcumateInitialized(with the new facility inlocation) and nostate-changedfor the reset. - A load failure (
error/blocked) emits nothing else until the visitor retries or the configuration is reloaded; a successful retry replays the full boot sequence.