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.
For general information about the HubBox Tag's capabilities and core concepts, please refer to the main Tag documentation.
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.
Follow these steps to add the script to your BigCommerce checkout:
HubBox Tag - Checkout
.Thorough testing is crucial before making HubBox live for all customers. HubBox provides a test mode integrated within the Tag script.
config
object within the HubBox Tag script you just pasted into Script Manager.mode
property within the config
is set to "test"
:// ... inside the HubBox Tag script ...
config: {
mode: "test", // Set to "test" for testing
// ... other configuration options ...
}
// ... rest of script ...
mode
is set to "test"
, the HubBox widget will only appear if a specific query parameter is added to your checkout page URL.?hubboxPayloadTest=true
to the end of the checkout URL in your browser's address bar and press Enter. Example URL: https://yourstore.mybigcommerce.com/checkout?hubboxPayloadTest=true
Once you have thoroughly tested the integration using the test mode and are confident it's working correctly:
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 ...
The HubBox pickup option will now be visible and available to all customers reaching your checkout page.
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.
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.
config.callbacks
)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
})
}
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
}),
}
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
}
})
}
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.
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 ...
Once the HubBox Tag script is correctly implemented and live:
shipping address
fields will be populated with the details of the chosen pickup point.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.