Cart integration
How to integrate the Bambuser player with your native shopping cart
One more elegant improvement you can introduce to your live shopping experience is to integrate the player cart with your native cart.
This is done by providing more details to the products that were added through the Bambuser Live Video Shopping workspace initially.
What is more, you need to handle the player cart-related events in order to activate the player cart, therefore sync with your native cart.
Requirements
Your e-commerce app/platform has available methods/API endpoint for:
- Fetching product details
- Adding products to the cart
- Updating items in the cart
- Checking your cart status (optional)
Implementation
To make use of the player cart feature, you need to handle some cart-related events. You will find the list of required events and configurations with details and examples below.
The in-player cart functionality, including the 'Add to Cart' button, will not be enabled unless you implement handlers for all of the following required events: PROVIDE_PRODUCT_DATA, ADD_TO_CART, UPDATE_ITEM_IN_CART, and CHECKOUT.
Required events to be handled
PROVIDE_PRODUCT_DATAADD_TO_CARTUPDATE_ITEM_IN_CARTCHECKOUTSYNC_CART_STATE
Required configs to be set:
localecurrency

All events below have to be wrapped inside onBambuserLiveShoppingReady()
window.onBambuserLiveShoppingReady = player => {
// `player` object contains Bambuser Player API methods and constants
// Configurations
player.configure({
currency: 'USD',
locale: 'en-US',
});
// Handle player events here
// See the examples below
};
Providing more data to player products
Event name: player.EVENT.PROVIDE_PRODUCT_DATA
- When the viewer opens the player
When adding products in the Bambuser Workspace, we only store the product's title, thumbnail, brand, and a product reference. However, to use the player cart feature, you need to hydrate this product with more product details such as:
- More product images
- Variations (color, size)
- Prices
In order to do that, you will first have to write a method that fetches the product details from your inventory. Then you can use a player API method called updateProduct(...) in order to hydrate products in the show with extra information.

Event payload
| Property | Description | Type |
|---|---|---|
| event.products | Contains all show's products added through the Bambuser workspace. Each product object includes:
| Array |
Example code
- Dynamic implementation
- Sample product data
- Static implementation
player.on(player.EVENT.PROVIDE_PRODUCT_DATA, (event) => {
event.products.forEach(async ({ ref: sku, url, id: bambuserId }) => {
const yourProduct = await yourGetProductMethod(sku);
player.updateProduct(bambuserId, (productFactory) =>
productFactory
// -> The .product() method takes a function
// returning a product detail object
.product((productDetailFactory) =>
productDetailFactory
// Name of the product
.name(yourProduct.name)
// 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)
// sku (or any other identifier for your product)
// NOTE: Should be the same as your product reference
// defined in Bambuser Workspace
.sku(yourProduct.productId)
// 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)
.defaultVariationIndex(0)
// -> The .variations() method takes a function
// returning an array of variations
.variations((variationFactory) =>
yourProduct.colors.map((variation) =>
// VariationFactory contains a factory returning a new instance of a variation
variationFactory()
// -> (Optional) The .attributes() method takes a function
// defines color attribute for the variation
.attributes((attributeFactory) =>
attributeFactory
// Color name in the variation dropdown selector,
.colorName(variation.colorName)
// (Optional) Color Hex code e.g. '#7d58ee'
.colorHexCode(variation.colorHexCode)
)
// List of image urls for the variation
// ordered the same as you want it displayed
.imageUrls(variation.images)
// Name of the variation
// Shown if colorName is not provided as attribute.
.name(variation.name)
// sku (or any other identifier for your product)
// specific down to this variation
.sku(variation.variationId)
// -> The .sizes() method takes a function that
// returns an array of sizes
.sizes((sizeFactory) =>
variation.sizes.map((size) =>
// s contains a factory returning a new instance of a variation
sizeFactory()
// Name of the size
// (used in dropdowns)
.name(size.name)
// Set whether this combination of
// variation and size is in stock
.inStock(size.quantityInStock > 0)
// sku (or any other identifier for your product)
// specific down to this size (used for add-to-cart)
.sku(size.sizeId)
// -> The price method contains a new chain
// defines price for the variation and size combo
.price((priceFactory) =>
priceFactory
// currency to show price in
// Optional - overrides the default currency
.currency(size.currency)
// current price as a number
.current(size.current)
// (Optional) original price
// Used in case the current is a sale price
.original(size.original)
// (Optional) This set of fields allows showing price per unit, e.g. $77 / 100ml
.perUnit(size.perUnit)
.unitAmount(size.unitAmount)
.unitDisplayName(size.unitDisplayName),
)
)
)
)
)
)
);
});
});
{
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>`,
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,
perUnit: 100,
unitAmount: 1,
unitDisplayName: "piece",
}
]
},
{
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
}
]
}
]
}
// This is only for demonstration purposes
// Hardcoding products data is not recommended
player.on(player.EVENT.PROVIDE_PRODUCT_DATA, (event) => {
event.products.forEach(async ({ ref: sku, url, id: bambuserId }) => {
player.updateProduct(bambuserId, (productFactory) =>
productFactory.product((productDetailFactory) =>
productDetailFactory
.brandName("Bambuser")
.defaultVariationIndex(0)
.introduction("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>`
)
.name("Bambuser Hoodie")
.sku("1111")
.variations((variationFactory) => [
variationFactory()
.attributes((attributeFactory) =>
attributeFactory.colorName("black").colorHexCode("#000000")
)
.imageUrls([
"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",
])
.name("Black Bambuser Hoodie")
.sku("1111-1")
.sizes((sizeFactory) => [
sizeFactory()
.name("Small")
.inStock(9 > 0)
.sku("1111-black-small")
.price((priceFactory) =>
priceFactory.currency("SEK").current(100).original(120)
),
sizeFactory()
.name("X-Large")
.inStock(3 > 0)
.sku("1111-black-xlarge")
.price((priceFactory) =>
priceFactory.currency("SEK").current(100).original(120).perUnit(100).unitAmount(1).unitDisplayName("piece"),
),
]),
variationFactory()
.attributes((attributeFactory) =>
attributeFactory.colorName("white").colorHexCode("#FFFFF")
)
.imageUrls([
"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",
])
.name("White Bambuser Hoodie")
.sku("1111-2")
.sizes((sizeFactory) => [
sizeFactory()
.name("Small")
.inStock(8 > 0)
.sku("1111-white-small")
.price((priceFactory) =>
priceFactory.currency("SEK").current(100).original(120)
),
sizeFactory()
.name("X-Large")
.inStock(0 > 0)
.sku("1111-2-2")
.price((priceFactory) =>
priceFactory.currency("SEK").current(100).original(120)
),
]),
])
)
);
});
});
Find more details on Player API Reference.
Handle Add To Cart event
Event name: player.EVENT.ADD_TO_CART
- When a viewer clicks on
Add to Cartbutton inside the player
In the player, the viewer will be able to add products to the player cart.
To reflect this event to you native cart, you will need to use your own method to add the product to the cart in the player.EVENT.ADD_TO_CART event handler.
When callback(true), the product will be added to the player cart.
When callback(false), an appropriate error message will appear in the player. You can also modify your own error messages.
Event payload
| Content | Description | Type |
|---|---|---|
| addedItem.sku | Contains your reference to the product | String |
| callback | To inform the player cart if the process of handling the event was successful or unsuccessful | Function |
Example code
player.on(player.EVENT.ADD_TO_CART, (addedItem, callback) => {
yourAddToCartMethod(addedItem.sku)
.then(() => {
callback(true); // item successfully added to cart
})
.catch(error => {
if (error.type === 'out-of-stock') {
// Unsuccessful due to 'out of stock'
callback({
success: false,
reason: 'out-of-stock',
});
} else {
// Unsuccessful due to other problems
callback(false);
}
});
});
Customizing cart operations error
Sometimes you might want to customize your own error messages for
ADD_TO_CARTandUPDATE_ITEM_IN_CARTcallbacks. You can do this by passing the below object as the argument when invokingcallbackmethod:Usage Example
callback({
success: false,
reason: "custom-error",
message: "This is my custom error message", //edit this by your choice
});
Handle Update Cart event
Event name: player.EVENT.UPDATE_ITEM_IN_CART
- 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
In addition to adding items to the cart, a viewer can also increase or decrease the quantity of a previously added item, or even remove the item from the cart.
To reflect this event to you native cart, you will need to use your own method to update the product to the native cart within the EVENT.UPDATE_ITEM_IN_CART event handler.
When callback(true), the product will be added to the Bambuser cart.
When callback(false), an appropriate error message will appear in the player. You can also modify your own error messages.
Event payload
| Property | Description | Type |
|---|---|---|
| updatedItem.sku | contains your reference to the product | String |
| updatedItem.quantity | number of products with above sku currently in the player cart | Integer |
| updatedItem.previousQuantity | number of products with above sku previously in the player cart | Integer |
| callback | To inform the player cart if the process of handling the event was successful or unsuccessful | Function |
Example code
// The user wants to change the quantity of an item in cart
player.on(player.EVENT.UPDATE_ITEM_IN_CART, (updatedItem, callback) => {
if (updatedItem.quantity > 0) {
yourUpdateCartMethod({
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) {
yourMethodToDeleteItemFromCart(updatedItem.sku)
.then(() => {
// successfully deleted item
callback(true);
})
.catch(() => {
// failed to delete item
callback(false);
});
}
})
Customizing cart operations error
Sometimes you might want to customize your own error messages for
ADD_TO_CARTandUPDATE_ITEM_IN_CARTcallbacks. You can do this by passing the below object as the argument when invokingcallbackmethod:Usage Example
callback({
success: false,
reason: "custom-error",
message: "This is my custom error message", //edit this by your choice
});
Handle Go to Checkout event
Event name: player.EVENT.CHECKOUT
- Whenever a viewer clicks the "Checkout" button inside the player cart
When the viewer is happy with their shopping cart, they can click the Checkout button inside the player cart.
To handle that, you should specify the location of your website cart inside EVENT.CHECKOUT.
Example code
player.on(player.EVENT.CHECKOUT, () => {
player.showCheckout(window.location.origin + "/cart");
})
Sync the player cart
Event name: player.EVENT.SYNC_CART_STATE
- Whenever the viewer navigates back to the player
Currently, the update cart does not support anything more than emptying the player cart.
Example code
player.on(player.EVENT.SYNC_CART_STATE, () => {
// Use your method to check if the user has checkout
if (isOnSiteCartEmpty()) {
// Emptying the in-player cart
player.updateCart({
items: [],
});
}
});
For Shopify
Shopify stores have a standard product model and API endpoints. We have a guide and a ready-to-use sample integration code that works across almost all Shopify stores.
To learn more, check out the Shopify integration guide.
Troubleshooting
- We have Cart Integration, but clicking on the products minimizes the player / opens the product in new tab
- We can only see one dropdown with combined variations
Cart Integration FAQ
Bambuser Live’s in-player Product Detail Page (PDP) currently supports a maximum of two variations (e.g., Color and Size). This means the player can display up to two dropdowns for product selection.
If you have a third variation (e.g., Material), you will need to either:
- Combine it with one of your other variations (e.g., merge Material with Size or Color).
- Opt not to use Cart Integration for these products.
Every time you open a new instance of the Bambuser Player, the cart will be empty. This is by design. The bi-directional cart sync is currently not supported.
To display both prices, use the PROVIDE_PRODUCT_DATA event handler and include .current() and .original() in the .price() method:
.current(size.current)sets the discounted price (e.g., 50)..original(size.original)sets the original price (e.g., 75).
If current price is lower than original price, the player will display both if provided (e.g., "$50 (was $75)"). Ensure your product data includes both prices.
This typically happens when your product data is provided in a "flat" structure instead of the required hierarchical structure. The Bambuser player needs variations like sizes to be nested under primary variations like colors to display them in separate dropdowns.
For a detailed explanation and solution, please see our troubleshooting guide:
We can only see one dropdown with combined variations
The player's UI does not update stock status in real-time for viewers who are already watching the show. The initial stock status is fetched when the player loads.
However, the player's logic handles this gracefully. If a viewer tries to add a sold-out item to their cart, the ADD_TO_CART event will fire. Your backend should reject this action, and you can then use the callback function to inform the player that the item is out of stock. The player will then display an "out of stock" message to the user.
The stock status will be correctly reflected as out-of-stock for any new viewers who join the show or for existing viewers who refresh the page.
You can update stock availability using the same function used to "provide product data" initially. This function can be called at any time, not just when the player requests it.
Updating Stock in Real-Time:
Call the player.updateProduct() method with updated inventory information:
// Update stock availability for a product
player.updateProduct(productId, {
variations: [
{
name: "Size",
values: [
{
name: "Small",
quantityInStock: 5, // Updated stock quantity
inStock: true
},
{
name: "Medium",
quantityInStock: 0, // Out of stock
inStock: false
}
]
}
]
});When to Update Stock:
- Real-time updates: When inventory changes occur in your system
- Periodic updates: Set up automated checks to sync stock levels
- Before shows: Ensure accurate stock information before going live
- After purchases: Update stock immediately after successful transactions
The relevant details for updating stock are included in the documentation for providing product data, using the same updateProduct() method.