Skip to main content

Easy Bundles SDK : Custom Storefront Implementation Guide

Written by Surya Varma
Updated over a week ago

Overview

This guide outlines the workflow for building a custom "Mix & Match" bundle interface using the Easy Bundles SDK on Shopify.

Architecture Type: Headless-on-Liquid. The App manages the backend logic, product containers, and cart session. The Developer is responsible for the Frontend UI, HTML structure, state rendering, and validation enforcement.

Phase 0: Prerequisites & App Configuration

Crucial: Before writing any code, the bundle structure must be configured in the Shopify Admin via the Easy Bundles App. The SDK merely reflects the configuration created here.

1. Create the Bundle (Merchant/Admin Step)

  • Navigate to the Easy Bundles App dashboard.

  • Select "Product Page Bundle".

  • Automatic Parent Product: When you create this bundle, the app automatically generates a "Parent" or "Dummy" product in Shopify to house the bundle.

    • Note to Developer: You do not need to create a product manually in Shopify or configure inventory/pricing for the container. The app handles this.

2. Configure Steps & Categories

Understanding the data structure is vital for using the SDK.

  • Steps: These represent the logical flow (e.g., "Step 1: Choose Base," "Step 2: Choose Toppings").

  • Categories: These are collections of products.

  • The Relationship: Steps and Categories are not 1:1.

    • A single Step can contain multiple Categories.

    • Example: Step 1 could display both "T-Shirts" (Category A) and "Hoodies" (Category B).

  • Configuration: Define your Steps, assign Categories to them, and set selection limits (min/max) inside the App Admin. These settings generate the stepIds and validation rules you will access via the SDK.

3. Configure Discounts (Optional)

If the bundle includes special pricing (e.g., Percentage Off, Fixed Price, or Tiered Discounts), configure these in the Discounts section of the App Admin.

  • Role of SDK: The SDK allows you to read these settings (via discountConfiguration) to display the savings to the user.

  • Role of App: The App backend automatically applies the actual discount to the cart line items if the rules are met.

  • Note: You cannot "create" discounts via JavaScript. They must exist in the Admin first.

Phase 1: Core Concepts & Mental Model

Once the bundle is configured, use the SDK to build the UI. Keep these three architectural rules in mind:

1. The "Manual Render" Loop

The SDK does not emit generic "state-changed" events. It does not automatically update your DOM when data changes.

  • The Workflow: You must manually trigger a UI re-render after every user interaction.

  • Pattern: User ClickCall SDK FunctionAwait CompletionCall Your render() Function.

2. Client-Side Gatekeeping

The SDK is permissive. It will allow an addToCart action even if the user hasn't selected the required number of items.

  • Your Responsibility: You must implement validation logic (using SDK helpers) to disable the "Add to Cart" button until all conditions are met.

3. State Management

  • Global Access: The SDK exposes all bundle data, rules, and current selections via the global gbbMix object.

Phase 2: Setup & Initialization

1. Enabling the SDK

Ensure the Theme App Extension is enabled in the Shopify Theme Editor.

  • Script Loading: The SDK injects automatically on product pages that are linked to a Bundle.

  • Initialization: The SDK auto-detects the Bundle ID based on the current product page. No manual gbbMix.init() call is required.

2. HTML Structure

The SDK provides zero HTML. You must build the container.

  • Recommendation: Create a wrapper div with a specific ID to act as your application root.

  • Liquid: Do not use Liquid loops to render bundle items. Use Liquid only for the basic page layout, then let JS inject the bundle interface.

<!-- Example Root --> <div id="easy-bundle-root">   <!-- Loading Spinner (Default State) -->   <div class="loader">Loading Bundle...</div> </div>

Phase 3: Development & UI Logic

1. Accessing Data

All data is available in the global state object. To inspect this during development, append ?dev=true to the URL and check the console.

  • Global State: gbbMix.sdk.state

  • Offer/Bundle IDs: Found within the state object.

  • Box Selection: If your bundle uses box sizes (6-pack vs 12-pack), access gbbMix.settings.mixAndMatchBundleData.boxSelection.

2. Rendering the UI

Since there is no "State Change" listener, you should structure your code with a central render function.

async function handleItemAdd(stepId, variantId, qty) {     // 1. Call SDK Action     await gbbMix.sdk.f.addItem(stepId, variantId, qty);      // 2. Manually Re-render UI to reflect new totals/counts     renderBundleUI(); }

3. Calculating Prices & Discounts

The SDK provides the raw subtotal in cartData.total_price. It does not automatically calculate the discounted display price for the frontend.

  • To Display Discounts: You must calculate the math manually using:

    • gbbMix.sdk.state.discountConfiguration (contains rules, % off, fixed amounts).

    • cartData.total_price (current raw total).

  • Note: The actual transactional discount is applied automatically by the App during the Cart/Checkout phase, provided the rules are met. Your calculation here is purely for the user's visual benefit.

Phase 4: Validation & Cart Actions

1. Validating Selections

Crucial: You must validate rules before allowing the user to proceed.

  • Helper Function: gbbMix.sdk.f.checkStepLevelCondition(stepId, variantId, productQuantity)

  • Logic: Iterate through steps; if any step fails the condition check, keep the "Add to Cart" button disabled.

2. Add to Cart Behavior

The addBundleToCart() function is asynchronous and AJAX-based. It does not redirect the user to checkout or the cart page automatically.

The Implementation Pattern:

  1. Trigger: Call the function.

  2. Await: Use await to keep your Loading Spinner active.

  3. Listen: Use Event Listeners to handle the final outcome (Success/Fail).

Code Reference:

const handleAddToCart = async () => {     // 1. Start Loading State     showSpinner(true);      // 2. Setup Event Listeners     const onSuccess = () => {         console.log("Bundle added!");         // Redirect to cart or open drawer         window.location.href = '/cart';     };      const onFail = () => {         alert("Failed to add bundle. Please try again.");     };      window.addEventListener('gbb-add-bundle-to-cart-success', onSuccess, { once: true });     window.addEventListener('gbb-add-bundle-to-cart-failed', onFail, { once: true });      // 3. Call SDK (Returns void, but is awaitable)     await gbbMix.sdk.f.addBundleToCart();      // 4. Cleanup Loading State     showSpinner(false); };

Phase 5: Debugging & Tools

  • Developer Mode: Add ?dev=true to your URL. This exposes gbbMix in the console for inspection.

  • Function Inspection: Once in dev mode, you can inspect SDK functions via gbbMix.sdk.f.

Phase 6: Technical Limitations

  • Headless Storefronts: The SDK relies on Shopify's Online Store 2.0 structure. It is not compatible with Hydrogen or React-based headless storefronts.

  • Vintage Themes: Support for legacy Liquid (Vintage) themes is not guaranteed due to legacy technology stacks.

  • Frameworks: While you may use lightweight frameworks (Alpine.js, Vue, React) to render the widget, the app does not provide framework-specific components. Plain JavaScript is recommended for performance.

Phase 7: API Reference

This section lists the essential properties and methods available in the gbbMix global object.

Global Objects

Object Path

Description

gbbMix.sdk.state

The primary state object containing current selections, bundle configuration, and discount rules.

gbbMix.sdk.f

The function library for interacting with the bundle (adding items, checking validation).

gbbMix.settings

Static settings loaded from the app admin.

Key State Properties (gbbMix.sdk.state)

Property

Description

discountConfiguration

Object containing discount rules (Percentage/Fixed) needed for manual frontend price calculation.

cartData

Contains the current state of the bundle in the cart, including total_price (raw subtotal).

steps

Array containing step configurations (IDs, names, associated categories).

SDK Functions (gbbMix.sdk.f)

Function

Parameters

Description

addItem

(stepId, variantId, qty)

Adds a specific variant to the bundle selection. Note: Must manually re-render UI after calling.

checkStepLevelCondition

(stepId, variantId, qty)

Helper to validate if the current selection meets the Min/Max rules configured in the Admin.

addBundleToCart

()

Asynchronously adds the valid bundle to the Shopify cart. Returns void but is awaitable.

Settings (gbbMix.settings)

Property

Description

mixAndMatchBundleData.boxSelection

Use this to access "Box Size" configurations (e.g., 6-pack vs 12-pack) if enabled for the bundle.

Event Listeners (Window)

Event Name

Description

gbb-add-bundle-to-cart-success

Fired when the bundle is successfully added to the cart via AJAX.

gbb-add-bundle-to-cart-failed

Fired when the add-to-cart operation fails (e.g., network error).

Summary Checklist for Developer

  • [ ] Admin: Bundle structure (Steps/Categories) created in Easy Bundles App.

  • [ ] Frontend: HTML container present in theme.

  • [ ] Logic: Manual render() function implemented and called after every SDK action.

  • [ ] Math: Manual price/discount calculation for display.

  • [ ] Validation: "Add to Cart" button disabled if conditions (checkStepLevelCondition) are not met.

  • [ ] Checkout: addBundleToCart handled via await (for UI loader) and EventListeners (for success/fail logic).

Did this answer your question?