Skip to content

Calcumate (original) hooks in Calcumate3D

Sites written for Calcumate (original) only need to replace the snippet. Every hook Calcumate (original) exposed keeps working in Calcumate3D; the new calcumate:* events are the upgrade path, not a requirement.

The rule for every payload is superset: the keys Calcumate (original) sent are there with the same meaning, and Calcumate3D’s own keys sit beside them.

Calcumate (original) hook Direction Calcumate3D Status
CalcumateInitialized calculator → page on every successful load, right after calcumate:ready; detail.isReady === true plus the identity keys and a state object shaped like the Calcumate (original) page documents ✅
CalculationFinished calculator → page after every calculation, right after calcumate:calculated; the packed containers verbatim (unit.unitDetails.unit.unitName, unitDetails.dimensions, item placements x/y/z…) ✅
Booking calculator → page at the CTA click (before the lead form / redirect) and again after the lead-form submit, as before; detail.selectedCalculation ✅
userDetails calculator → page on lead-form submit; name / email / phone + every field + the Calcumate (original) context (selectedItems, unit, unitDetails, int, domain, ref, sessionId) ✅
RE-INIT page → calculator window.dispatchEvent(new CustomEvent('RE-INIT')) reloads the configuration and re-reads the container attributes; also accepted as postMessage('RE-INIT') into an iframe ✅
calcumateLoad (disable units) page → calculator window.dispatchEvent(new CustomEvent('calcumateLoad', { detail: [<unit ID>, …] })) excludes those units from the recommendations; [] re-enables all. If results are on screen the calculation re-runs immediately ✅
window.listUnits / window.disableUnits globals the calculator’s units (the Builder unit rows, ID / unitName / unitWidth …) and the current disabled list ✅
data-disable-list-results="true" container attribute the results screen shows the unit (and the unit pager for a mix) without the recommendation list and CTA; toggled at runtime + RE-INIT as before ✅
CTA URL params redirect cm-qty, cm-id, cm-volume, cm-used-volume, the {unitId}={quantity} pairs of Unit Quantity (Multiple), and cm-location on CalcumateGEO calculators — plus the new cm-ids, cm-volume-unit, cm-recommendation ✅
Per-unit reserve URL redirect when the recommended unit has its own URL in the Builder (unit “reserve url”), the CTA opens it instead of the global CTA URL, with no params — as before ✅
sessionStorage['FACILITY-ID'] internal not used. Calcumate (original) kept its facility pick there; it was never meant as an integration point. Calcumate3D remembers the pick in localStorage['calcumate-3d-storage'], bound to the calculator, so another calculator on another route is unaffected and no SPA cleanup is needed. Calcumate (original) internal
.select-locations-wrap CSS overrides styling not reproduced — the facility selector is part of the entry screen and the calculator’s CSS is isolated from the page. Brand it through the Builder’s Design step. Calcumate (original) only

Calcumate (original) dispatched { isReady: true }. Calcumate3D dispatches:

{
isReady: true,
calculatorId: 'abc123', // the calculator's id
language: 'en',
measurementSystem: 'metric' | 'imperial',
selectedItems: [{ id, product, quantity }], // items restored from the visitor's last session (usually [])
location: { locationId, id, name, url, distance, distanceUnit } | null, // CalcumateGEO facility
calculating: false,
state: { // the shape documented for Calcumate (original)
isReady: true, calculating: false,
selectedItems: [ /* the calculator's item rows + product, thumbnail, quantity */ ],
location, isLocationEnabled, userGeo: null,
selectedCategory: null, selectedCategoryList: [], customItems: [],
primaryCalculation: null, secondaryCalculation: null, showDialog: false, isCSP: false
}
}

It fires on every successful load (first boot, RE-INIT, each CalcumateGEO facility change); make handlers idempotent.

An array, one entry per packed container of the best recommendation, in the same order as Calcumate (original) sent them, with extra keys added:

[{
unit: {
id: 'unit-m', name: 'Medium Unit',
quantity: 1, // how many containers of this unit the recommendation uses
unitDetails: {
// Calcumate (original) nested shape
id: 'unit-m', name: 'Medium Unit',
unit: { ID: 'unit-m', unitName: 'Medium Unit', unitWidth: '2', unitDepth: '3', unitHeight: '2.4', unitReserve: '' },
dimensions: { width: 200, depth: 300, height: 240 }, // cm
// flat unit keys, as sent by Calcumate (original)
ID: 'unit-m', unitName: 'Medium Unit', unitWidth: '2', unitDepth: '3', unitHeight: '2.4',
// Calcumate3D cm keys
width: 200, height: 240, depth: 300, volume: 14.4 // volume in m³ / ft³
}
},
items: [{ id: 'bbq', product: 'BBQ', x: 0, y: 0, z: 0, width: 49.5, height: 120, depth: 60,
orientation: 'normal', scale: false, volume: 0.36, quantity: 1, image: null, instanceId: 'bbq-0' }],
totalItemsWeight: 908.4,
totalVolume: 15.77,
usedSpacePct: 72.5,
measurementSystem: 'metric',
animationDone: true
}]

Notes: unitWidth / unitDepth / unitHeight are your unit strings (metres or feet) exactly as before, while dimensions and the flat width / height / depth are centimetres. When the Calcumate service was unreachable and the calculator shows a local packing, the array is []. When a re-calculation did not change the packing, the entries are the previous full result’s.

Fires at the CTA click (whatever the redirect and lead-capture settings) and again after the lead form is submitted — the same two emit points as Calcumate (original).

{
selectedCalculation: [ /* the CalculationFinished entries of the clicked recommendation, each + `location` */ ],
recommendation: [ /* the same entries */ ],
items: [{ id, product, quantity }], // the whole inventory
location: { locationId, id, name, url, distance, distanceUnit } | null,
cta: { url, label, resolvedUrl } // resolvedUrl = what the calculator opens (null when no redirect)
}
{
// every answered field under its field id (Builder forms use opaque ids: "1", "2", …)
"1": "Jane Doe", "2": "jane@example.com", "3": "+61 400000000",
// canonical keys, filled from the first field of each type
name: "Jane Doe", email: "jane@example.com", phone: "+61 400000000", bookingDate: "2026-11-01",
"additional-info": "Ground floor please", // the first notes / message / comment field, when present
// Calcumate (original) context
selectedItems: [ /* item rows + product, thumbnail, quantity */ ],
unit: { id, name, quantity, unitDetails }, // first unit of the recommendation the CTA was pressed for
unitDetails: { … }, // its unitDetails
int: '<integration id>' | null, domain: 'example.com', domain2: 'www.example.com', ref: '<token>',
cEmail: null, sessionId: '<session id of this load>'
}

Lead data is never put in the CTA URL; this event (or calcumate:lead-captured) is the way to get it.

Section titled “calcumateLoad: filter the recommended units”
// exclude two units (ids as shown in the Builder / window.listUnits[].ID)
window.dispatchEvent(new CustomEvent('calcumateLoad', { detail: ['unit-l', 'unit-xl'] }))
// re-enable everything
window.dispatchEvent(new CustomEvent('calcumateLoad', { detail: [] }))
window.listUnits // the calculator's units: [{ ID, unitName, unitWidth, unitDepth, unitHeight, … }]
window.disableUnits // the ids currently excluded

A same-origin host can reach the globals through iframe.contentWindow.listUnits; a cross-origin host cannot, and gets the CALCUMATE_* postMessages instead. Dispatch calcumateLoad into the iframe’s window the same way, or embed with the direct script snippet so the calculator shares the page’s window.

Ids that do not name a unit of the loaded calculator are ignored (numbers are accepted and compared as strings). The list is a page-level setting: it survives RE-INIT and CalcumateGEO facility changes and is intersected with the current units on every calculation. If results are on screen when the event arrives, the calculation re-runs immediately; otherwise the list applies to the next one. Dispatch it after CalcumateInitialized (the unit list is known then).

data-disable-list-results: hide the recommendation list

Section titled “data-disable-list-results: hide the recommendation list”
<div data-calcumate data-calcumate-ref="…" data-disable-list-results="true"></div>
const el = document.querySelector('[data-calcumate]')
el.setAttribute('data-disable-list-results', 'true') // or 'false' / removeAttribute
window.dispatchEvent(new CustomEvent('RE-INIT', {})) // re-reads the attribute, as before

Only the exact string "true" enables it. The results screen then shows the 3D unit (and the unit pager for a multi-unit recommendation) without the recommendation list and CTA; the item editor stays.

Calcumate (original) Calcumate3D
cm-qty = number of units of the first unit id cm-qty = units in the recommendation
cm-id = the first unit’s id cm-id = the first unit’s id; cm-ids = every unit id of a mixed recommendation, comma-joined
Unit Quantity (Multiple) → one {unitId}={count} param per unit id the same pairs, plus cm-recommendation=1.Small Unit,4.Large Unit
cm-volume, cm-used-volume (m³ / ft³) the same, plus cm-volume-unit=m3|ft3
cm-location = selected facility id (CalcumateGEO) the same, whenever a facility is selected
unit “reserve url” set in the Builder → the CTA opens it, no params the same

Params are added with the URL API, so query keys already on the CTA URL are kept (a key spelled like a unit id would be overwritten by the pair above).

window.addEventListener('CalcumateInitialized', (e) => { if (e.detail.isReady) init() })
window.addEventListener('CalculationFinished', (e) => {
const [first] = e.detail
console.log(first.unit.unitDetails.unit.unitName, first.unit.unitDetails.dimensions, first.totalVolume)
})
window.addEventListener('Booking', (e) => { const { selectedCalculation } = e.detail })
window.addEventListener('userDetails', (e) => { const { name, email, phone } = e.detail })
window.dispatchEvent(new CustomEvent('calcumateLoad', { detail: [123, 456] }))
window.dispatchEvent(new CustomEvent('RE-INIT', {}))