Skip to main content

One-to-Many

Welcome to the Bambuser One-to-Many technical documentation!

Bambuser enables businesses to incorporate live video shopping in their ecommerce platform via the Live Video Player. The following pages are meant to guide businesses when integrating our One-to-Many solution.

Documentation first explains steps needed to Integrate the player and then goes more into detail inside Player API Reference. To understand what gets tracked and how to access analytics data, make sure to read Analytics section. You will find all this, and so much more inside this documentation.

Boilerplate code

The boilerplate code below can be used for inspiration as well as a quick try out of main functionalities of the Bambuser Player. This code includes:

  • One dummy product to demonstrate how to provide product data to the player
  • Template for you helper methods
  • Miniplayer configuration
  • Example of cart integration
  • Example show with one product
Boilerplate Code
<!-- CTA to initiate the show -->
<button id="YOUR_ELEMENT_ID">Open the live</button>

<script>
// ======================================== Dummy product object ==============================================
const dummyProductObject = {
productId: "1111",
name: "Bambuser Hoodie",
brand: "Bambuser",
shortDescription: "World's best hoodie",
description:
`<p>Jacket in sweatshirt fabric with a jersey-lined drawstring hood, zip down the front, side pockets and ribbing at the cuffs and hem. Soft brushed inside. Regular Fit.</p><b>Benefits:</b><ul><li>Awesome hoodie</li><li>Set approves</li></ul>`,
defaultVariationIndex: 0,
price: 100,
price_discount: true,
colors: [{
variationId: "1111-black",
name: "Black Bambuser Hoodie",
colorName: "black",
colorHexCode: "#000000",
images: [
"https://demo.bambuser.shop/wp-content/uploads/2021/07/black-hoodie-front.png",
"https://demo.bambuser.shop/wp-content/uploads/2021/07/black-hoodie-right.jpeg",
"https://demo.bambuser.shop/wp-content/uploads/2021/07/black-hoodie-back.jpeg",
"https://demo.bambuser.shop/wp-content/uploads/2021/07/black-hoodie-left.jpeg"
],
sizes: [{
sizeId: "1111-black-small",
currency: "SEK",
current: 100,
original: 120,
name: "Small",
quantityInStock: 9
},
{
sizeId: "1111-black-xlarge",
currency: "SEK",
current: 100,
original: 120,
name: "X-Large",
quantityInStock: 3
}
]
},
{
variationId: "1111-white",
name: "White Bambuser Hoodie",
colorName: "white",
colorHexCode: "#FFFFFF",
images: [
"https://demo.bambuser.shop/wp-content/uploads/2021/07/white-hoodie-front.png",
"https://demo.bambuser.shop/wp-content/uploads/2021/07/white-hoodie-right.jpeg",
"https://demo.bambuser.shop/wp-content/uploads/2021/07/white-hoodie-back.jpeg",
"https://demo.bambuser.shop/wp-content/uploads/2021/07/white-hoodie-left.jpeg"
],
sizes: [{
sizeId: "1111-white-small",
currency: "SEK",
current: 100,
original: 120,
name: "Small",
quantityInStock: 8
},
{
sizeId: "1111-white-xlarge",
currency: "SEK",
current: 100,
original: 120,
name: "X-Large",
quantityInStock: 0
}
]
}
]
};

// ====================================== Define your own helper methods ==========================================
const storeApi = {};

// Retrieve the product and return the details
storeApi.getProduct = (productIdentifier) => {
// TODO: Implement your logic for fetching your own product object
// e.g. fetch("/products/[productIdentifier]", { method: "GET" });

return Promise.resolve(dummyProductObject);
};

// Add product to the native cart by SKU
// Return the result (success and reason in case of failure)
storeApi.addToCart = (sku) => {
// TODO: Implement your logic for adding a product variation to your native cart
// e.g. fetch("/cart/add", { method: "POST", body: JSON.stringify({ sku: sku, quantity: 1 }) });

return Promise.resolve({ success: true });
};

// Update the quantity of a product in the native cart by SKU
// Return the result (success and reason in case of failure)
storeApi.updateItemInCart = (sku, quantity) => {
// TODO: Implement your logic for updating your native cart
// e.g. fetch("/cart/update", { method: "POST", body: JSON.stringify({ sku: sku, quantity: quantity }) });

return Promise.resolve({ success: true });
};

// Remove the product from your native cart by SKU
// Return the result (success and reason in case of failure)
storeApi.removeItemFromCart = (sku, quantity) => {
// TODO: Implement your logic for removing the product from your native cart
// e.g. fetch("/cart/remove", { method: "POST", body: JSON.stringify({ sku: sku, quantity: 0 }) });

return Promise.resolve({ success: true });
};

// Check if your native cart is empty
storeApi.getCartState = () => {
// TODO: Implement your logic for
// e.g. fetch("/cart/state", { method: "GET" });

return Promise.resolve(0);
};

//======================================= Bambuser onReady Handler =========================================
window.onBambuserLiveShoppingReady = (player) => {
// ------------------------------------ Start of player configuration ------------------------------------
player.configure({
// Mandatory - if you have cart integration
// Currency to show prices in
// The value should be of type string
currency: "USD", // Can be initialized dynamically

// Mandatory - if you want to target a language that is not configured for your dashboard by default
// Sets the global locale (language) of the player
// Bambuser follow ISO 639-1 Code + "-" + ISO 3166-2 as standard locale format.
// The value should be of type string
locale: "en-US", // Can be initialized dynamically
buttons: {
dismiss: player.BUTTON.MINIMIZE, // Enable the Miniplyar
checkout: player.BUTTON.MINIMIZE // Minimize the player when checkout button is clicked
}
});
// ------------------------------------ End of player configuration ------------------------------------

// NOTE: Cart features will not be visible in the player
// unless you handle all events listed below:
//
// ** Cart Integrations **
// - player.EVENT.PROVIDE_PRODUCT_DATA
// - player.EVENT.ADD_TO_CART
// - player.EVENT.UPDATE_ITEM_IN_CART
// - player.EVENT.CHECKOUT
// - player.EVENT.SYNC_CART_STATE (optional)

// ------------------------------------ Start of Cart Integraion ------------------------------------

// The Bambuser player triggeres "PROVIDE_PRODUCT_DATA" event when:
// - When the viewer opens the player
player.on(player.EVENT.PROVIDE_PRODUCT_DATA, (event) => {

// "event.products" contains all show's products added through the Bambuser dashboard.
// Each product object includes:
// - ref : Product reference
// - url : URL of the product
// - id : Bambuser generated ID for each product in the player.
event.products.forEach(({
ref: sku,
url,
id: bambuserId // This id is passed as the first argument of the player.updateProduct() method
}) => {

// Fetch your product object
storeApi.getProduct(sku).then(yourProduct => {

player.updateProduct(bambuserId, (productFactory) =>
productFactory

// Mandatory
// The .product() method takes a function
// which returns a product detail object
.product((productDetailFactory) =>

// Mandatory
// productDetailFactory contains a factory returning a new instance of a product detail
productDetailFactory

// Mandatory
// Name of the product
.name(yourProduct.name)

// Optional - if not provided, brand will not appear
// Brand name to display for the product
.brandName(yourProduct.brand)

// (Optional) Short product introductory text
.introduction(yourProduct.shortDescription)

// (Optional) Description for the product
// Supports text as well as HTML string
.description(yourProduct.description)

// Mandatory
// sku (or any other identifier for your product)
// NOTE: Should be the same as your product reference
// defined in Bambuser Dashboard
.sku(yourProduct.productId)

// Optional
// Describes which index in the variations list below
// contains the default variation
// (e.g. if variations contain colors, and you want to display
// the white version of a shirt, send the index for the white variation)

// Example:
//.defaultVariationIndex(yourProduct.defaultVariationIndex || 0)
.defaultVariationIndex(0)

// Mandatory
// The .variations() method takes a function
// returning an array of variations
.variations((variationFactory) =>
yourProduct.colors.map((variation) =>

// Mandatory
// variationFactory contains a factory returning a new instance of a variation
variationFactory()

// Optional
// The .attributes() method takes a function
// defining a color attribute for the variation
.attributes((attributeFactory) =>

// Mandatory
// attributeFactory contains a factory returning a new instance of a attribute
attributeFactory

// Optional
// Color name in the variation dropdown selector,
.colorName(variation.colorName)

// Optional
// Color Hex code e.g. "#7d58ee"
.colorHexCode(variation.colorHexCode)
)

// Optional - However highly recommended
// If not provided, there will only be one image shown - thumbnail image
// List of image urls for the variation
// ordered the same as you want it displayed
.imageUrls(variation.images)

// Mandatory
// Name of the variation
// Shown if colorName is not provided as attribute.
.name(variation.name)

// Mandatory
// sku (or any other identifier for your product)
// specific down to this variation
.sku(variation.variationId)

// Mandatory
// The .sizes() method takes a function that
// returns an array of sizes
.sizes((sizeFactory) =>
variation.sizes.map((size) =>

// Mandatory
// sizeFactory contains a factory returning a new instance of a size
sizeFactory()

// Mandatory
// Name of the size
// (used in the size dropdown)
.name(size.name)

// Optional
// Set whether this combination of
// variation and size is in stock
// If false - this specific size instance will be grayed out
.inStock(size.quantityInStock > 0)

// Mandatory
// sku (or any other identifier for your product)
// specific down to this size (used for add-to-cart)
.sku(size.sizeId)

// Mandatory
// The price method contains a new chain
// defines price for the variation and size combo
.price((priceFactory) =>
priceFactory

// Mandatory
// current price as a number
.current(size.current)

// Optional
// Original price
// Used in case the current is a sale price
.original(size.original)

// Optional - overrides the default currency specified in cofigurations
// currency to show price in
.currency(size.currency)
)
)
)
)
)
)
)
});
});
});

// ------------------------------------ Start of Cart Integrations ------------------------------------

// The Bambuser player triggeres "ADD_TO_CART" event when:
// - When a viewer clicks on Add to Cart button inside the player
player.on(player.EVENT.ADD_TO_CART, (addedItem, callback) => {
storeApi.addToCart(addedItem.sku)
.then(() => callback(true))
.catch(error => {
if (error.message === yourOutOfStockErrorMessage) {
// Unsuccessful due to "out of stock"!
callback({
success: false,
reason: "out-of-stock",
});
} else {
// Unsuccessful due to other problems
callback(false);
}
});
});

// The Bambuser player triggeres "UPDATE_ITEM_IN_CART" event when:
// - Whenever the viewer modifies quantity from the player cart
// - Whenever the viewer adds a product to the cart that is already in the player cart
player.on(player.EVENT.UPDATE_ITEM_IN_CART, (updatedItem, callback) => {
if (updatedItem.quantity > 0) {
storeApi.updateItemInCart({
sku: updatedItem.sku,
quantity: updatedItem.quantity,
})
.then(() => {
// cart update was successful
callback(true);
})
.catch(function(error) {
if (error.type === "out-of-stock") {
callback({
success: false,
reason: "out-of-stock",
});
} else {
callback(false);
}
});
}

// user wants to remove the product from the cart
if (updatedItem.quantity === 0) {
storeApi.removeItemFromCart(updatedItem.sku)
.then(() => {
// successfully deleted item
callback(true);
})
.catch(() => {
// failed to delete item
callback(false);
});
}
})

// The Bambuser player triggeres "CHECKOUT" event when:
// - Whenever a viewer clicks the "Checkout" button inside the player cart
player.on(player.EVENT.CHECKOUT, () => {
// Use the showCheckout() method and pass
// a string of absolute URL to your cart/checkout page
player.showCheckout(window.location.origin + "/cart");
});

// The Bambuser player triggeres "SYNC_CART_STATE" event when:
// - Whenever the viewer navigates back to the player
player.on(player.EVENT.SYNC_CART_STATE, () => {
// Use your method to check if the on-site cart is empty or not
storeApi.getCartState().then((response) => {
if (response.item_count == 0) {
// Empty the in-player cart
// Currently, the update cart does not support anything more than emptying the player cart.
player.updateCart({
items: []
});
}
});
});

// ------------------------------------ End of Cart Integrations ------------------------------------
};

//======================================== Embed code ==============================================

(function() {
// ------------------------------------ Initialize the script ----------------------------------------
if (!window.initBambuserLiveShopping) {
window.initBambuserLiveShopping = function(item) {
window.initBambuserLiveShopping.queue.push(item);
};
window.initBambuserLiveShopping.queue = [];
const scriptNode = document.createElement('script');

// ** NOTE **
// Embed URL is specific per player theme
// Find your custom embed URL in the Bambuser Dashboard in the code snippet on each show setup page
// If your brand theme is not yet released from Bambuser side, the theme will fallback to default theme
scriptNode['src'] = 'https://lcx-embed.bambuser.com/brand-name/embed.js';
document.body.appendChild(scriptNode);
}

// ---------------------------------- Registering one or more shows ---------------------------------
// Trigger the player via click event
// You call this method separately to register multiple shows in a page
window.initBambuserLiveShopping({
showId: '3liU6PomTpJ9dzLr90BN', // REPLACE THIS WITH YOUR OWN SHOW ID
node: document.getElementById('YOUR_ELEMENT_ID'), // DOM element as CTA button; triggers on click
type: "overlay" // The type MUST be "overlay"
});

// Initiate another show
// window.initBambuserLiveShopping({
// showId: 'YOUR_SHOW_ID_2',
// node: document.getElementById('YOUR_ELEMENT_ID_2'),
// type: "overlay"
// });

})();
</script>

If you are not familiar with Bambuser One-to-Many product, watch the video below to get an idea of what it looks like.