Promotions Theme Support

Promotions Theme Support

Learn how Promotions integrate with your theme — including Shopify standard storefront events — and how to add custom integration code for older themes.

Function Studio natively supports Shopify’s standard storefront events and actions. On themes that ship the standard actions runtime — including Shopify’s Horizon theme family and any theme updated for the Spring ‘26 Edition — promotions work out of the box, with no integration code:

  • Auto-add / auto-remove blocks update the cart through Shopify.actions.updateCart, so your theme refreshes its own cart UI (drawer, cart page, bubble) in place — items appear and disappear without a page reload.
  • After cart changes made through the classic AJAX Cart API, Function Studio emits the standard shopify:cart:lines-update event (in the same shape the actions runtime uses), so standard-events-native themes re-render their cart sections themselves.
  • Function Studio also listens for shopify:cart:lines-update, so cart changes made by the theme or by other apps immediately re-evaluate your promotions (thresholds, item-count gift triggers, and so on).

If your theme customizes the standard actions and something misbehaves, you can force the classic integration path by pasting this into the Theme Integration field of the Promotions Runtime app embed:

<script>window.FSPromotions = window.FSPromotions || {}; window.FSPromotions.disableStandardActions = true;</script>

Custom integration code for older themes

Some older themes use neither standard storefront events nor the events that our app emits. Those require custom integration code to enable correct operation of auto-add to cart and auto-remove from cart blocks.

How to use integration code

Click Edit Theme button

Paste integration code and save

Locate Promotions Runtime and paste the code into Theme Integration field:

Save the theme

Trade Theme

<script>
document.addEventListener('cart:updated', async function(e) {
  var cart = e.detail;
  if (typeof publish === 'function' && cart) {
    publish('cart-update', {
      source: 'fs-cart-service',
      cartData: cart
    });

    // Find theme cart element
    var cartEls = [document.querySelector('cart-drawer'), document.querySelector('cart-notification'), document.querySelector('cart-items')].filter(el => !!el);

    // Collect sections from all cart elements
    var allSectionIds = [];
    var sectionEls = cartEls.filter(function(el) {
      return typeof el.getSectionsToRender === 'function';
    });

    sectionEls.forEach(function(el) {
      el.getSectionsToRender().forEach(function(s) {
        var id = s.section || s.id;
        if (id && allSectionIds.indexOf(id) === -1) allSectionIds.push(id);
      });
    });

    // Fetch deduped sections once, then render each element
    if (sectionEls.length > 0 && allSectionIds.length > 0) {
      try {
        var res = await fetch(window.location.pathname + '?sections=' + allSectionIds.join(','));
        var sections = await res.json();
        cart.sections = sections;
        sectionEls.forEach(function(el) {
          el.getSectionsToRender().forEach(function(s) {
            try {
              var sectionEl = document.getElementById(s.id);
              var sectionKey = s.section || s.id;
              if (!sectionEl || !sections[sectionKey]) return;
              var parsed = new DOMParser().parseFromString(sections[sectionKey], 'text/html');
              var sourceEl = s.selector ? parsed.querySelector(s.selector) : parsed.querySelector('.shopify-section');
              if (sourceEl) sectionEl.innerHTML = sourceEl.innerHTML;
            } catch(e) {}
          });
        });
      } catch(err) {
        console.error('[FS] Failed to fetch cart sections:', err);
      }
    }
  }
});
</script>