Skip to main content
The Promotions UI JS SDK automatically applies location-based discounts to prices on your page and renders a customisable banner that tells visitors about their local deal. It works with plain HTML — no framework required.
This SDK is separate from the entitlements JS SDK. Use this SDK when you need PPP / country-based discount banners and price display.

Installation

1. Add the Script

Paste this snippet just before the closing <head> tag on your pricing page:
<script type="text/javascript">
function resolvePdSDKFunction(n,...o){return new Promise((e,t)=>{!function i(){window.KQPromotionUISDK&&"function"==typeof window.KQPromotionUISDK[n]?window.KQPromotionUISDK[n](...o).then(e).catch(t):setTimeout(i,100)}()})}!function(n,o,e,t,i,r,c){n[t]=n[t]||function(){(n[t].q=n[t].q||[]).push(Array.prototype.slice.call(arguments))},r=o.createElement(e),c=o.getElementsByTagName(e)[0],r.id="kelviq-sdk",r.async=1,r.src="https://cdn.kelviq.com/js-promotions-ui/0.1/js-promotions-ui.umd.js",c.parentNode.insertBefore(r,c)}(window,document,"script","KQPromotionUISDK"),window.KQPromotionUI={init:function(n){KQPromotionUISDK("init",n)},getUpdatedPrice:function(n,o){return resolvePdSDKFunction("getUpdatedPrice",n,o)},updatePriceElement:function(n,o){return resolvePdSDKFunction("updatePriceElement",n,o)},updatePrice:function(n){return resolvePdSDKFunction("updatePrice",n)}};
</script>

2. Initialize the SDK

Copy your promotion ID from the promotion detail page and call init():
Copy promotion ID
KQPromotionUI.init({
  // Replace with your promotion ID
  promotionId: "YOUR_PROMOTION_ID",
  // Access token can be found in the Settings -> Developers section
  accessToken: "YOUR_CLIENT_ACCESS_TOKEN",
  showBanner: true,
});
This will automatically display a discount banner if the visitor is eligible for a discount.
Never expose your Server API Key in the browser. Use the Client API Key, which is safe for client-side code. You can find both keys under Settings → Developers in the Kelviq dashboard.

init() options

OptionTypeDefaultDescription
promotionIdstringPromotion ID from the Kelviq dashboard
accessTokenstringClient API Key (Settings → Developers)
showBannerbooleantrueRender the localised discount banner automatically
environment"production" | "sandbox""production"Target environment
baseCurrencyCodestring"USD"ISO 4217 code for prices displayed on the page
baseCurrencySymbolstring"$"Symbol written to data-kq-currency-symbol elements
currencyDisplay"symbol" | "code" | "name""symbol"How the currency is formatted via Intl.NumberFormat
showDecimalbooleanfalseInclude the decimal portion in formatted prices
minimumDecimalDigitsnumber2Minimum fraction digits (0–2)
maximumDecimalDigitsnumber2Maximum fraction digits (0–2)
banner.*objectCustomization for the discount banner
banner.unStyledbooleanfalseif true, no styling will be applied to the banner
banner.addCloseIconbooleantrueControl close button visibility. This setting will work only if close button is enabled from the ParityDeals banner settings
banner.placementtop|bottom’top’The placement of the discount banner
banner.containerstringnullThe container for the discount banner
banner.backgroundColorstring’#f0f0f0’The background color of the discount banner
banner.fontColorstring’#333333’The font color of the discount banner
banner.borderRadiusstring’0px’The border radius of the discount banner
banner.fontSizestring’14px’The font size of the discount banner

Auto price update

After init() resolves, every element with data-kq-price on the page is automatically updated with the discounted price for the visitor’s country.

Basic usage

<!-- Integer-only price -->
<div data-kq-price="49">
  <sup data-kq-currency-symbol></sup>
  <span data-kq-price-integer></span>
</div>

<!-- Price with decimal -->
<div data-kq-price="49" data-kq-show-decimal="true">
  <sup data-kq-currency-symbol></sup>
  <span data-kq-price-integer></span>
  <span data-kq-price-decimal-separator></span>
  <span data-kq-price-decimal></span>
</div>

<!-- Discounted price + original price (linked by data-kq-rel) -->
<div data-kq-price="79" data-kq-rel="pro-plan" data-kq-show-decimal="true">
  <span data-kq-price-formatted></span>
</div>
<div data-kq-original-price-display="99" data-kq-rel="pro-plan" class="original-price">
  <span data-kq-price-formatted></span>
</div>

<!-- Currency code instead of symbol -->
<div data-kq-price="99" data-kq-currency-display="code">
  <span data-kq-price-formatted></span>   <!-- renders e.g. "USD 99" -->
</div>
The original-price element is hidden by default. The SDK shows it automatically when a discount is active and hides it when the visitor’s country has no discount.

Price container attributes

AttributeValueDescription
data-kq-pricenumberBase price — the discounted value is computed and written to child elements
data-kq-original-price-displaynumberOriginal (pre-discount) price; hidden when there is no active discount
data-kq-relstringLinks a price element and its original-price element so they update together
data-kq-show-decimal"true" | "false"Per-element decimal override (falls back to showDecimal from init())
data-kq-currency-display"symbol" | "code" | "name"Per-element currency format
data-kq-minimum-decimal-digitsnumberPer-element minimum fraction digits (0–2)
data-kq-maximum-decimal-digitsnumberPer-element maximum fraction digits (0–2)

Sub-element attributes

Place these inside a price container to receive individual parts of the formatted price:
AttributeExample output
data-kq-currency-symbol$
data-kq-price-integer49
data-kq-price-decimal99
data-kq-price-decimal-separator.
data-kq-currency-codeUSD
data-kq-price-formatted$49.99

JS API

All methods return Promises and require init() to have been called first.

getUpdatedPrice(price, options?)

Computes the discounted price and returns a PriceObject without touching the DOM.
const result = await KQPromotionUI.getUpdatedPrice(100, { showDecimal: true });
console.log(result.formattedPrice); // "$80.00"
console.log(result.price);          // 80
Parameters
ParameterTypeDescription
pricenumberBase price to apply the discount to
optionsPartial<Config>Optional overrides (same fields as init())
Returns — PriceObject
FieldTypeDescription
pricenumberFinal price after discount
formattedPricestringFully formatted string, e.g. $80.00
integerPartstringInteger portion only, e.g. 80
decimalPartstringDecimal digits only, e.g. 00
decimalSeparatorstringLocale-specific separator, e.g. .
currencySymbolstringCurrency symbol, e.g. $
currencyCodestringISO 4217 code, e.g. USD
apiResponsePricingDataFull API response including country, percentage, and widgets

updatePriceElement(element, options?)

Updates a specific DOM element with the computed discounted price. The element must have a data-kq-price attribute. All elements linked to it via data-kq-rel are updated as well.
const el = document.getElementById("pro-price");
const result = await KQPromotionUI.updatePriceElement(el, { showDecimal: true });
console.log(result.formattedPrice);
Parameters
ParameterTypeDescription
elementHTMLElementMust have data-kq-price attribute
optionsPartial<Config>Optional overrides
Returns a PriceObject (same shape as getUpdatedPrice).

updatePrice(configs[])

Batch-update multiple elements, optionally rendering each with an HTML template.
await KQPromotionUI.updatePrice([
  {
    element: document.getElementById("monthly"),
    price: 29,
    options: { showDecimal: false },
    template: "<div class='price'>{{formattedPrice}} <small>/mo</small></div>",
  },
  {
    element: document.getElementById("annual"),
    price: 199,
    options: { showDecimal: true },
    template: "<div class='price'>{{formattedPrice}} <small>/yr</small></div>",
  },
]);
Config object fields
FieldTypeDescription
elementHTMLElementTarget element — its innerHTML is replaced with the rendered template
pricenumberBase price
optionsPartial<Config>Optional overrides
templatestringHTML string with {{key}} placeholders
Available template variables (any field from PriceObject): {{price}} · {{formattedPrice}} · {{integerPart}} · {{decimalPart}} · {{decimalSeparator}} · {{currencySymbol}} · {{currencyCode}} Returns Promise<PriceObject[]> — one entry per config.

CSS hooks

The SDK adds classes to document.body that you can target in your stylesheets:
ClassAdded when
kq-discount-appliedAn active discount > 0% exists for the visitor’s country
kq-has-parity-bannerThe discount banner has been injected into the page
/* Show a sale badge only when a discount is active */
.sale-badge { display: none; }
body.kq-discount-applied .sale-badge { display: inline-block; }

/* Add top padding so content isn't hidden under the banner */
body.kq-has-parity-banner main { padding-top: 60px; }

Sandbox

Set environment: "sandbox" to test against the Kelviq sandbox environment.
KQPromotionUI.init({
  promotionId: "YOUR_PROMOTION_ID",
  accessToken: "YOUR_CLIENT_ACCESS_TOKEN",
  environment: "sandbox",
});
Use sandbox API keys (available under Settings → Developers with the Sandbox toggle enabled) so real visitor data is never affected during testing.