Hype Discounts

Storefront SDK (window.Hype)

Updated Oct 1, 20265 min read

On this page (8)

Hype Discounts exposes its storefront runtime on window.Hype. Use it to read the shopper's active campaigns and cart, apply discount codes, format money in the shop's currency, and react to campaign events from your own theme code.

What loads it

The Hype: Discounts app embed loads everything. Turn it on at Online Store → Themes → Customize → App embeds → Hype: Discounts. The embed renders a module script that:

  1. Inlines two app metafields as JSON: hype.ui_blocks_schema and hype.pricing_schema.
  2. Imports hype.js and hype-ui.js from the app's assets.
  3. Constructs the SDK and assigns these globals:
GlobalWhat it holds
window.HypeThe SDK instance described on this page
window.HypeUIThe controller classes behind the campaign elements — see UI SDK (window.HypeUI)
window.HypeUIBlocksSchemaBlock settings keyed by campaign ID
window.HypeSwatchesConfigThe shop's variant swatch configuration
window.HypeProductContext{ handle, collectionIds }, on product pages only

The embed's Enable debug logs, API Proxy link (default /apps/hype) and Hide Decimals for Whole Numbers settings feed the SDK's configuration. Its Custom JS field runs on every page and is the simplest place to put the snippets below.

Waiting for the SDK

window.Hype exists as soon as the embed's module runs, but campaigns arrive later, over the app proxy. Check for data first, then fall back to the event:

const start = () => {  console.log(window.Hype.campaigns)}if (window.Hype?.campaigns) {  start()} else {  document.addEventListener('hype:campaigns-loaded', start)}

Methods

MethodSignatureWhat it does
applyDiscountCode(codes: string | string[]) => Promise<void>Re-fetches campaigns with these codes and writes them to the cart. Codes are merged with any already stored for the session.
reset() => Promise<void>Clears the stored campaign link and codes, blanks the _hype_link cart attribute, empties campaigns / bundles / offers, and re-emits the three loaded events with empty arrays.
formatMoney(cents: number, options?: { shouldConvertToMarketPrice?: boolean }) => stringFormats cents using the shop's money format. Converts to the visitor's market price by default.
updateAllDynamicText() => voidRe-runs live pricing against the current DOM. Does nothing unless live pricing is active on the page.
log(options?: { level: 'info' | 'warn' | 'error' }, ...args: unknown[]) => voidPrints a prefixed console message. Silent unless Enable debug logs is on in the app embed.
await window.Hype.applyDiscountCode('SUMMER20')await window.Hype.applyDiscountCode(['SUMMER20', 'FREESHIP'])window.Hype.formatMoney(1999) // "$19.99" with a "${{amount}}" money formatwindow.Hype.formatMoney(1999, { shouldConvertToMarketPrice: false })window.Hype.log({ level: 'warn' }, 'No tier matched', cart.item_count)

reset() does not remove a code that is already on the cart. To do that, call window.Hype.utils.replaceCartDiscount('').

Properties

PropertyTypeNotes
campaignsActiveCampaign[] | undefinedundefined until the proxy responds; [] when nothing is active
bundlesFixedBundle[] | undefinedSame lifecycle as campaigns
offersStorefrontOffer[] | undefinedSame lifecycle as campaigns
cartreactive storeget() returns the cart or null; subscribe(cb) returns an unsubscribe function
eventsobjectThe event-name constants in the table below
utilsobjectThe helpers in the last section
visitorIdstringA persistent per-visitor ID

Each entry in campaigns carries campaignId, discountCode, type, dynamicPricingEnabled, isPrivateActive and a discounts array whose shape depends on type. type is one of MULTI_VALUE_DISCOUNT, AMOUNT_OFF_ORDER, GIFT_WITH_PURCHASE, TIERED_CART_DISCOUNT or VOLUME_DISCOUNT.

The cart store calls your callback once immediately, then on every change:

const stop = window.Hype.cart.subscribe((cart) => {  if (!cart) return  console.log(cart.item_count, window.Hype.formatMoney(cart.total_price))})// laterstop()

Events

Every event is dispatched on document as a CustomEvent. Listen with document.addEventListener.

ConstantEvent nameFires whenevent.detail
CAMPAIGNS_LOADEDhype:campaigns-loadedCampaigns come back from the app proxy, and on reset()ActiveCampaign[]
BUNDLES_LOADEDhype:bundles-loadedBundles come back in the same responseFixedBundle[]
OFFERS_LOADEDhype:offers-loadedOffers come back in the same responseStorefrontOffer[]
DISCOUNT_APPLIEDhype:discount-appliedCodes have been written to the cart{ discountCodes: string[], isNewLinkOpened: boolean, isNewDiscount: boolean, campaignId?: string }
CART_UPDATE_COMPLETEhype:cart-update-completeHype has re-fetched the cart after a changeThe cart object
FREE_GIFTS_ADDEDhype:free-gifts-addedHype auto-added gift linesThe added line items
FREE_GIFTS_REMOVEDhype:free-gifts-removedHype removed gift lines that are no longer earned{ campaignId: string, items: CartItem[] }
ITEM_ADDED_TO_CARThype:item-added-to-cartA Hype element added items to the cartThe added line items
document.addEventListener('hype:discount-applied', (event) => {  console.log('applied', event.detail.discountCodes)})

window.Hype.events also contains CART_UPDATE (hype:cart-update). Nothing in the app dispatches it — use hype:cart-update-complete instead.

Cart and product utilities

All of these live on window.Hype.utils.

UtilitySignatureNotes
getProductData(handle: string) => Promise<Product>Fetches /products/<handle>.js. Cached for 10 minutes in the browser.
getProductHandleFromUrl(url: string) => { handle: string | null, variantId: number | null }Accepts an absolute URL or a path
getCurrencyRate() => numberReads Shopify.currency.rate
addToCart(items: AddCartItem[]) => Promise<{ items: CartItem[] }>Posts to /cart/add.js. Throws with Shopify's message when the add fails, for example a sold-out variant.
fetchCart() => Promise<Cart>Reads /cart.js
removeFromCart(lineKeys: string[]) => Promise<Cart>Sets each line key's quantity to 0
replaceCartDiscount(discount: string) => Promise<Cart>Replaces the cart's discount codes. Pass '' to clear them.
const { handle } = window.Hype.utils.getProductHandleFromUrl(location.href)const product = await window.Hype.utils.getProductData(handle)await window.Hype.utils.addToCart([{ id: product.variants[0].id, quantity: 1 }])const cart = await window.Hype.utils.fetchCart()await window.Hype.utils.removeFromCart([cart.items[0].key])

removeFromCart takes line keys (cart.items[n].key), not line numbers.

Link campaigns. A link campaign activates from the ?hypecampaign=<slug> URL parameter. Hype stores the slug in sessionStorage under hype-campaign and on the cart as the _hype_link attribute, so it survives page loads and returns visits within the session. When more than one source has a value, the URL parameter wins, then session storage, then the cart attribute.

To activate one from your own code, send the shopper to a URL carrying the parameter:

location.href = `/collections/all?hypecampaign=${slug}`

Code campaigns. Call applyDiscountCode. Hype re-fetches campaigns with those codes, stores them in sessionStorage under hype-discount-codes, and writes them to the cart:

document.querySelector('#promo-form').addEventListener('submit', async (e) => {  e.preventDefault()  await window.Hype.applyDiscountCode(e.target.code.value.trim())})

Only one code set is written at a time, and Hype replaces the cart's existing codes when it applies. Hype's own cart requests carry a from-hype=1 parameter so they do not re-trigger its cart monitor; keep that in mind if you inspect network traffic.

Related articles

Still stuck?

Ask a follow-up and we'll see it came from “Storefront SDK (window.Hype)”.

Opens chat with your question and a link to this article.