Implementing HubBox on BigCommerce using Script Manager

Introduction

This guide details how to integrate the HubBox pickup point selection functionality into your BigCommerce store using the HubBox Tag script added via BigCommerce's built-in Script Manager.

This method involves directly injecting the HubBox JavaScript onto your checkout pages, which is the standard approach for integrating frontend features like HubBox on the BigCommerce platform.

Prerequisites:

For general information about the HubBox Tag's capabilities and core concepts, please refer to the main Tag documentation.

Step 1: Obtain Your HubBox Tag Script

Before you begin, ensure you have the correct HubBox Tag script from the HubBox team. This JavaScript code contains your unique configuration ID and the logic required to display and manage the HubBox pickup point selection interface on your BigCommerce checkout.

Step 2: Add the HubBox Tag Script via Script Manager

Follow these steps to add the script to your BigCommerce checkout:

  1. Log in to your BigCommerce Admin panel.
  2. Navigate to Storefront in the left-hand menu, then click Script Manager. (Note: If you manage multiple Storefronts via Channel Manager, you might need to navigate via Channel Manager > Channels > Your Storefront > Scripts).
  3. Click the Create a Script button.
  4. Configure the script settings as follows:
    • Name of script: Enter a descriptive name, like HubBox Tag - Checkout.
    • Description: (Optional) Add details like "Loads HubBox pickup point selector on checkout".
    • Location on page: Select Footer. (This helps ensure the script loads after the main page content is available).
    • Select pages where script will be added: Choose Checkout.
    • Script category: Select Essential. (HubBox is part of the essential checkout functionality).
    • Script type: Select Script. bigcommerce-add-script-1 bigcommerce-add-script-2
  5. Paste the Script: In the Script contents text box below the settings, carefully paste the entire HubBox Tag script provided to you by HubBox. Ensure it's pasted exactly as received. bigcommerce-add-script-3
  6. Click Save. bigcommerce-add-script-4

Step 3: Testing the Implementation

Thorough testing is crucial before making HubBox live for all customers. HubBox provides a test mode integrated within the Tag script.

Enable Test Mode

Activate Test View

What to Test

Step 4: Going Live

Once you have thoroughly tested the integration using the test mode and are confident it's working correctly:

  1. Edit the HubBox Tag script again within BigCommerce Script Manager.
  2. Change the mode property within the config object from "test" to "live":
    // ... inside the HubBox Tag script ...
    config: {
        mode: "live", // Set to "live" for deployment
        // ... other configuration options ...
    }
    // ... rest of script ...
    
  3. Click Save in Script Manager.

The HubBox pickup option will now be visible and available to all customers reaching your checkout page.

Advanced Configuration (Within the HubBox Tag Script)

The HubBox Tag script includes a config object where advanced features like product eligibility and shipping rate filtering can be configured. These configurations modify the behaviour of the base script you added via Script Manager.

Product Eligibility Filtering (getShouldBailOut)

You may need to prevent the HubBox pickup option from appearing if the customer's cart contains items unsuitable for pickup (e.g., oversized, hazardous, high-value). This is achieved using the callbacks.getShouldBailOut function within the Tag script's config. This function should return true if HubBox should be hidden ("bail out"), and false otherwise.

This function typically needs to inspect the current cart contents (often via BigCommerce Storefront APIs) and apply your business logic. For guidance on when and why to exclude products, see the Product Eligibility documentation.

BigCommerce Examples (add within config.callbacks)

Example 1: Hide pickup for any out-of-stock items in cart

This example uses Workspace and BigCommerce Storefront GraphQL API to check inventory.

callbacks: {
    getShouldBailOut: () =>
    new Promise((resolve) => {
        // Function to get cart data
        const getCart = (url) => fetch(url, { method: "GET", credentials: 'include' }).then((response) => response.json()).catch((error) => console.error(error));
        // Function to fetch product inventory via GraphQL
        const fetchProductData = (productIds, variantIds, apiToken) => fetch("/graphql", { method: "POST", credentials: "same-origin", headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiToken}` }, body: JSON.stringify({ query: `query ProductInventory{site{products(entityIds:${JSON.stringify(productIds)}){edges{node{entityId name variants(entityIds:${JSON.stringify(variantIds)}){edges{node{entityId sku inventory{aggregated{availableToSell warningLevel}}}}}}}}}}}` }) }).then((res) => res.json()).catch((error) => console.error(error));

        getCart("/api/storefront/carts?include=lineItems.physicalItems.options")
        .then((cartData) => { // Process cart data to get product/variant IDs
            const productMap = {};
            cartData?.[0]?.lineItems?.physicalItems?.forEach((item) => {
            const productId = item.productId;
            if (!Array.isArray(productMap[productId])) productMap[productId] = [];
            productMap[productId].push(item.variantId);
            });
            return productMap;
        })
        .then((productMap) => { // Fetch inventory for items in cart
            const productIds = Object.keys(productMap).map(Number);
            const variantIds = productIds.flatMap(key => productMap[key]);
            // Ensure you have the Storefront API token available here
            // You might need to pass settings.storefront_api.token if available in scope, or fetch it
            const storefrontApiToken = "{{ settings.storefront_api.token }}"; // Check if this Handlebars syntax works in Script Mgr context, otherwise pass token differently
            if (!storefrontApiToken) { console.error("Storefront API Token not available"); return Promise.reject("No API Token"); }
            return fetchProductData(productIds, variantIds, storefrontApiToken);
        })
        .then((gqlResponse) => gqlResponse.data.site.products.edges.flatMap(pEdge => pEdge.node.variants.edges.flatMap(vEdge => vEdge.node.inventory)))
        .then((inventories) => inventories.every((i) => i.aggregated?.availableToSell > 0)) // Check if ALL items are > 0 stock
        .then((areAllItemsInStock) => resolve(!areAllItemsInStock)) // Bail out (return true) if NOT all items are in stock
        .catch(() => resolve(false)); // Default to not bailing out on error
    })
}
Example 2: Hide pickup based on specific SKUs

This example fetches the cart via REST API and checks if any SKU matches a predefined list.

callbacks: {
    getShouldBailOut: () => new Promise(resolve => {
    fetch('/api/storefront/cart', { credentials: 'include' })
        .then(response => response.json())
        .then(cartArray => {
        const nonAcceptableSkuList = ['SKU-TO-BLOCK-1', 'SKU-TO-BLOCK-2']; // Define your ineligible SKUs
        const cartItems = cartArray?.[0]?.lineItems?.physicalItems ?? [];
        const cartSkuList = cartItems.map(item => item?.sku);
        const nonAcceptableSkuExists = cartSkuList.some(cartSku => nonAcceptableSkuList.includes(cartSku));
        resolve(nonAcceptableSkuExists); // Bail out (return true) if an ineligible SKU exists
        })
        .catch(() => resolve(false)); // Default to not bailing out on error
    }),
}
Example 3: Hide pickup based on a product metafield (e.g., shipping-groups contains "large")

This example fetches cart items, then uses a hypothetical HubBox helper API or requires custom backend to fetch metafields for products in the cart.

callbacks: {
    getShouldBailOut: () =>
    new Promise(async (resolve) => {
        try {
        const getCart = (url) => fetch(url, { method: "GET", credentials: 'include' }).then(response => response.json()).catch(error => console.error("Cart fetch error:", error));
        const cartData = await getCart("/api/storefront/carts?include=lineItems.physicalItems.options");
        const productIds = cartData?.[0]?.lineItems?.physicalItems?.map(item => item.productId) ?? [];

        if (productIds.length === 0) {
            resolve(false); // Empty cart, don't bail out
            return;
        }

        // --- IMPORTANT ---
        // Fetching metafields efficiently for multiple products often requires a custom backend endpoint
        // or using the Storefront GraphQL API if metafields are exposed there.
        // The example below uses a placeholder HubBox API endpoint which may not exist or apply.
        // You WILL likely need to adapt this part significantly or create your own solution.
        // Consult BigCommerce Dev Docs on accessing metafields server-side or via Storefront GraphQL API.

        const fetchMetafields = async (productId) => {
            // Placeholder: Replace with your actual method to fetch metafields for a product ID
            // Option 1: Use Storefront GraphQL API (if metafields exposed)
            // Option 2: Call a custom serverless function / middleware you create
            // Option 3: Adapt the hypothetical endpoint if applicable/provided by HubBox
            const apiEndpointUrl = "/your-custom-metafield-endpoint/"; // EXAMPLE ONLY
            const response = await fetch(`${apiEndpointUrl}?productId=${productId}`);
            const data = await response.json();
            return data.metafields || []; // Assuming endpoint returns { metafields: [...] }
        };

        const allMetafields = await Promise.all(productIds.map(fetchMetafields));
        const flatMetafields = allMetafields.flat();

        // Check if any product has a 'shipping-groups' metafield containing 'large'
        const hasLargeItem = flatMetafields.some(mf => {
            if (mf.key === 'shipping-groups') { // Check your metafield key
                try {
                    const groups = JSON.parse(mf.value); // Assuming value is JSON array ["small", "medium"]
                    return Array.isArray(groups) && groups.some(group => group.toLowerCase() === 'large');
                } catch (e) { console.error("Error parsing shipping-groups metafield", e); return false; }
            }
            return false;
        });

        resolve(hasLargeItem); // Bail out (return true) if a 'large' item exists

        } catch (error) {
            console.error("Error in getShouldBailOut:", error);
            resolve(false); // Default to not bailing out on error
        }
    })
}

Shipping Rate Filtering

This involves using configuration within the HubBox Tag script to identify and hide specific shipping rate elements on the BigCommerce checkout page. This feature is typically configured within the config.selectors.shippingMethods object inside your HubBox Tag script.

Example Configuration (Conceptual - using shippingRates within config.selectors)
// ... inside the HubBox Tag script ...
config: {
  // ... mode, key, etc ...
  selectors: {
    shippingMethods: {
      wrapper: "#checkout-shipping-options",
        interactionPreventionAction: "hide li",
          excludeOnLocalPickup: [
            {
              selectors: [
                "text-fragment: Royal Mail",
              ],
            }],
            excludeOnHomeDelivery: [{
              selectors: [
                "text-fragment: Pickup",
              ],
            }],
      },
  }
  // ... callbacks etc ...
}
// ... rest of script ...

The End Result

Once the HubBox Tag script is correctly implemented and live:

bigcommerce-example-checkout

Support

If you encounter issues during the setup or testing process on BigCommerce, please gather relevant details (screenshots, error messages from the console, steps to reproduce) and contact the HubBox Client Support team at clientsupport@hub-box.com.