Events on Bundle Pages
Bundly emits a set of custom JavaScript events on bundle pages. These let you hook into key interactions (like toggling modals, changing options, or adding bundles to the cart) and run your own custom logic.
Every event bubbles up to document , so you can listen anywhere:
document.addEventListener('bundly:afterAddVariant', (e) => {
console.log(e.detail.title, e.detail.price, e.detail.currency);
});
All before events are cancelable. To cancel the event:
document.addEventListener('bundly:beforeToggleProductDialog', (e) => {
e.preventDefault(); // prevents modal from opening
});
Fields on Every Event
Besides the fields listed per event below, every event.detail carries:
| Field | Value |
|---|---|
sourceElement |
The Bundly element where the action started (for example the slot, card, or dialog the customer interacted with). The event itself can be dispatched on a different element |
originalEvent |
The originating DOM event when one is available, otherwise null . Do not use this field to determine whether the action was customer-initiated |
The after event carries the same fields as its before event, plus the result fields marked (after only).
Bundle Load Event
| Event | Notes |
|---|---|
bundly:beforeLoadBundle |
Can be canceled |
bundly:afterLoadBundle |
Fires after bundle is fully loaded |
Details (example values):
bundleProductId:'8570513260706', the bundle product
Variants restored from the URL, and variants selected automatically when the page opens, are applied between these two events.
Block Update Events
| Event | Notes |
|---|---|
bundly:beforeUpdateBlock |
Can be canceled |
bundly:afterUpdateBlock |
Fires after block is updated |
Details (example values):
productId:'8570513260706', the bundle productvariantId:'45579422990498', the bundle variant
These two fields are absent when the block that refreshes is the bundle list on a product page, because that block belongs to a product and not to a bundle.
Add/Remove Variant Events
| Event | Notes |
|---|---|
bundly:beforeAddVariant |
Can be canceled |
bundly:afterAddVariant |
Fires after variant is added |
bundly:beforeRemoveVariant |
Can be canceled |
bundly:afterRemoveVariant |
Fires after variant is removed |
Details (example values):
componentIndex:'0', position of the component in the bundlecomponentVariantIndex:'1', position of the slot inside that componentvariantId:'43553180418210', the variant that was added or removedproductId:'7760014049442', the product that variant belongs totitle:'Sample Product - Blue / Large', the same title Shopify puts on the cart linesku:'SP-BL-L'price:24.99, the price of this variant on its own, before the bundle discount, in the customer's currencycurrency:'USD'quantity:2, how many units of this variant the component addsbundleProductId:'8570513260706', the bundle product
Add to Cart Events
| Event | Notes |
|---|---|
bundly:beforeAddBundleToCart |
Can be canceled |
bundly:afterAddBundleToCart |
Fires after the add to cart request finishes. The success field gives the outcome |
Details (example values):
formData: theFormDatainstance that is sent to/cart/add.jsbundleProductId:'8570513260706', the bundle productbundleTitle:'Build Your Own Box'bundleHandle:'build-your-own-box'currency:'USD'bundleOriginalPrice:89.97, total of all components before the bundle discountbundlePrice:71.98, what the customer pays for the bundlebundleItems: an array of the selected variants, each withproductId,variantId,title,sku,priceandquantity. A variant selected more than once in the same component is one entry, and itsquantitycounts all of the selectionssuccess:trueorfalse(after only)error:'Error message here'(after only, on failure)serverResponse:'{"items":[...]}', the raw response from/cart/add.js(after only, on success)
Example: send the bundle to your own analytics after a successful add to cart.
document.addEventListener('bundly:afterAddBundleToCart', (e) => {
if (!e.detail.success) return;
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'add_to_cart',
currency: e.detail.currency,
value: e.detail.bundlePrice,
items: e.detail.bundleItems.map((item) => ({
item_id: item.sku,
item_name: item.title,
item_variant: item.variantId,
price: item.price,
quantity: item.quantity,
})),
});
});
Variant Option Events
| Event | Notes |
|---|---|
bundly:beforeChangeVariantOption |
Can be canceled |
bundly:afterChangeVariantOption |
Fires after the change is applied |
Details (example values):
componentIndex:'0'componentVariantIndex:'1'productId:'7760014049442', the product whose option changedoptionName:'Size'optionValue:'Large'
Dialog Events
| Event | Notes |
|---|---|
bundly:beforeToggleProductDialog |
Can be canceled |
bundly:afterToggleProductDialog |
Fires after the dialog opens or closes |
bundly:beforeNavigateProductDialog |
Can be canceled |
bundly:afterNavigateProductDialog |
Fires when the customer moves to the previous or next product in the dialog |
Details of the toggle events (example values):
newState:'open'or'closed'componentIndex:'0'componentVariantIndex:'1'productId:'7760014049442', the product shown in the dialog
Details of the navigate events (example values):
direction:'previous'or'next'productId:'7760014049442', the product shown before the move
Bundle Summary Events
These fire on the summary panel that shows the selected items and the count.
| Event | Notes |
|---|---|
bundly:beforeToggleDetails |
Can be canceled, which keeps the panel as it is |
bundly:afterToggleDetails |
Fires when the customer opens or closes the summary panel |
bundly:beforeCompleteBundle |
Can be canceled, which prevents Bundly from automatically opening the summary panel. The bundle stays complete and the add to cart button stays available |
bundly:afterCompleteBundle |
Fires when all required slots become filled, and opens the summary panel. It fires again each time the bundle becomes incomplete and complete again |
Analytics Events (Web Pixels)
Bundly also publishes customer events to Shopify's analytics layer, so you can send bundle activity to GA4, Meta, or any other destination from a custom web pixel (Settings → Customer events → Add custom pixel).
| Event | Data |
|---|---|
bundly:bundle_viewed |
bundle_product_id |
bundly:variant_added_to_bundle |
bundle_product_id , product_id , variant_id , title , sku , price , currency , quantity |
bundly:variant_removed_from_bundle |
Same as above |
bundly:bundle_added_to_cart |
bundle_product_id , bundle_title , bundle_handle , currency , bundle_original_price , bundle_price , bundle_items |
analytics.subscribe('bundly:bundle_added_to_cart', (event) => {
console.log(event.customData.bundle_price, event.customData.bundle_items);
});
Need More Events?
Let us know what you're building, we're happy to add new hooks.