Liquid / Page Builders
The Kaching Bundles widget automatically appears above the Add to Cart button on product pages — no code changes required. The rest of this guide covers integrations where you need more control: custom placement, variant syncing, cart handling, and reading widget state.
Placing the widget
Section titled “Placing the widget”By default the widget auto-places itself above the Add to Cart button. To control where it renders — for example inside a page builder section or below the product title — add this element wherever you want the widget:
<kaching-bundle product-id="{{ product.id }}"></kaching-bundle>When the widget finds a <kaching-bundle> element on the page, it skips auto-placement and renders inside your custom element instead.
If you need to delay initialization — for example, until after your page builder has rendered — set this flag before the Kaching script loads:
window.kachingBundlesDisableAutoInitialize = trueThen call window.kachingBundlesInitialize() manually when ready:
window.kachingBundlesInitialize()kaching-bundles-block-loaded event
Section titled “kaching-bundles-block-loaded event”Fired after the widget is fully mounted and ready. Useful for page builders that need to run code after the widget is available.
document.addEventListener("kaching-bundles-block-loaded", (event) => { const { component } = event.detail // `component` is the <kaching-bundles-block> HTMLElement})Syncing variant selection
Section titled “Syncing variant selection”currentVariantId
Section titled “currentVariantId”If your page builder has its own variant picker, keep the Kaching widget in sync by setting currentVariantId whenever the selected variant changes:
const widget = document.querySelector("kaching-bundles-block")widget.currentVariantId = selectedVariant.idcurrentVariantId accepts a numeric Shopify variant ID.
variant-selected event
Section titled “variant-selected event”The widget fires a variant-selected event when the customer selects a variant inside the widget (e.g., when a bundle includes variant options). Use this to update product images or other UI:
widget.addEventListener("variant-selected", (event) => { const { variantId } = event.detail updateProductImages(variantId)})Syncing quantity
Section titled “Syncing quantity”If your theme has its own quantity picker, keep the widget in sync by setting quantity whenever the value changes:
const widget = document.querySelector("kaching-bundles-block")widget.quantity = quantityInput.valueBy default, the widget hides the theme’s native quantity input to avoid a duplicate UI. To keep it visible, set this flag before the Kaching script loads:
window.kachingBundlesKeepQuantityInput = trueUpdating the displayed price
Section titled “Updating the displayed price”.pricing()
Section titled “.pricing()”Use the .pricing() method to read current pricing for a one-time display — for example on a custom ATC button:
const widget = document.querySelector("kaching-bundles-block")const { discountedPrice, fullPrice } = widget.pricing()
atcButton.textContent = `Add to Cart — ${discountedPrice.formatted}`widget.pricing(): Pricing{ discountedPrice: { amount: number; formatted: string } fullPrice: { amount: number; formatted: string } discountedPricePerItem: { amount: number; formatted: string } fullPricePerItem: { amount: number; formatted: string } discountedPriceWithoutSellingPlan: { amount: number; formatted: string } discountedPricesForSellingPlans: Array<{ sellingPlanId: number amount: number formatted: string }>}formatted strings use the store’s currency format (e.g., "$29.99"). Amounts are in currency units (e.g., 29.99 for $29.99).
For reactive updates, listen to the items-changed event — see Reacting to selection changes.
Reacting to selection changes
Section titled “Reacting to selection changes”items-changed event
Section titled “items-changed event”Fired whenever the selection changes — when the customer picks a different tier, changes quantity, or selects bundle products. The event carries no detail; call .pricing() or .items() to read the current state:
const widget = document.querySelector("kaching-bundles-block")widget.addEventListener("items-changed", () => { const { discountedPrice } = widget.pricing() atcButton.textContent = `Add to Cart — ${discountedPrice.formatted}`})deal-bar-selected event
Section titled “deal-bar-selected event”Fired when a deal bar tier is selected or deselected.
const widget = document.querySelector("kaching-bundles-block")widget.addEventListener("deal-bar-selected", (event) => { const { dealBarId, preselected } = event.detail
if (dealBarId) { console.log("Tier selected:", dealBarId) } else { console.log("Tier deselected") }})detail: { dealBarId: string | null // null when deselected preselected: boolean // true if the tier was auto-selected}Handling Add to Cart
Section titled “Handling Add to Cart”By default, the widget handles adding items to the cart — and we strongly recommend keeping it that way. The built-in handling covers edge cases like selling plans, cart properties, and discount validation that are easy to get wrong.
Only disable it if your page builder absolutely must manage the cart itself.
1. Disable built-in Add to Cart
Section titled “1. Disable built-in Add to Cart”Set this flag before the Kaching script loads:
window.kachingBundlesDisableAddToCartHandling = true2. Validate selection
Section titled “2. Validate selection”Before adding to cart, validate that the customer has made a valid selection:
const widget = document.querySelector("kaching-bundles-block")const { valid, message } = widget.validateItemSelection()
if (!valid) { // The widget already shows the error UI — optionally show `message` in your own UI too return}widget.validateItemSelection(): { valid: boolean; message: string | null }If valid is false, message contains the merchant-configured error text (or null if none is set).
For silent checks (e.g., disabling a button without showing error UI), use .isItemSelectionValid() instead:
widget.isItemSelectionValid(): booleanUse .validateItemSelection() when the customer attempts to add to cart, and .isItemSelectionValid() for silent checks.
3. Read line items
Section titled “3. Read line items”When the customer clicks your ATC button, call .items() on the widget to get the cart line items:
const widget = document.querySelector("kaching-bundles-block")const lines = widget.items()widget.items(): Item[]Each item has the following shape:
{ id: number // Shopify variant ID quantity: number properties: Record<string, unknown> selling_plan?: number // Selling plan ID, if subscriptions apply}Pass lines to your cart API or page builder’s cart action.