Skip to main content

Custom pricing in configurators

The Visual Configurator calculates a total price by default (it sums standard product prices). If you need promotions, tiered discounts, or to show sale pricing, you can set up custom pricing with a small piece of JavaScript.

This guide shows how to turn the feature on and gives copy‑paste patterns you can adapt.

What you’ll need

  • Access to your configurator in Conversation Studio (or standalone Configuration Studio).
  • The attribute names you’ll read (e.g. category, sale price)
  • Basic JavaScript familiarity.

Enable custom pricing

  1. Open your configurator in Configuration Studio.
  2. Right panel → your section → Settings (cog) → Selection summary.
  3. Toggle on “Use custom price logic”.
  4. Paste one of the script patterns below (only one at a time).

Custom pricing

What your script receives

  • products: array of selected product objects
  • total: number (sum of standard/list prices)
  • locale: string (e.g. en-GB, de-DE)

Return a number. If nothing is selected, return 0.


Reusable helpers

These helpers:

  • Format currency per locale, including zero‑decimal currencies like JPY.
  • Safely create your own price container under a stable selector, avoiding internal classes.
// Adjust to your markets; remove what you don't need

const CURRENCIES = {
'en-US': 'USD', 'en-GB': 'GBP', 'de-DE': 'EUR', 'fr-FR': 'EUR',
'nl-NL': 'EUR', 'it-IT': 'EUR', 'es-ES': 'EUR', 'ja-JP': 'JPY', 'ko-KR': 'KRW'
};
const DEFAULT_CCY = 'USD';
const ZERO_DECIMAL = new Set(['JPY', 'KRW']);

// Resolve currency from locale
function getCurrency() {
return CURRENCIES[locale] || DEFAULT_CCY;
}

// Format amounts for display
function fmt(amount) {
const ccy = getCurrency();
const opts = { style: 'currency', currency: ccy };
if (ZERO_DECIMAL.has(ccy)) { opts.minimumFractionDigits = 0; opts.maximumFractionDigits = 0; }
return new Intl.NumberFormat(locale, opts).format(amount);
}

// Round the numeric return according to currency
function roundForCurrency(amount) {
const ccy = getCurrency();
return ZERO_DECIMAL.has(ccy) ? Math.round(amount) : Number(amount.toFixed(2));
}

// Ensure we have our own container under a stable host
function ensurePriceContainer() {
const host = document.querySelector('[data-testid="total-price"]');
if (!host) return null;
let wrap = host.querySelector('.zv-price-container');
if (!wrap) {
wrap = document.createElement('div');
wrap.className = 'zv-price-container';
wrap.style.display = 'grid';
wrap.style.gap = '4px';
host.appendChild(wrap);
}
return wrap;
}

Notes for reliability

  • Use stable hooks (like data-testid="total-price") and your own injected container. Avoid internal class names that can change.
  • Format currencies per locale, including zero‑decimal currencies (e.g. USD).
  • Don’t insert untrusted HTML; use textContent for dynamic data.
  • Test in Preview with empty, edge, and full selections.