Shopify + LiveShopping
Integrate Bambuser Live Shopping with your Shopify storeβ
In order to integrate the Bambuser LiveShopping player into a Shopify store, you will need to add some code to your Shopify LiveShopping landing page (wherever you want to embed the player). The embed and integration codes can be added by adding script tags to your page content or theme codes.
Below you'll find a sample Shopify integration code that you can use when integrating Bambuser One-to-many player into your Shopify store.
Steps:
- Embed show(s) into a page π
- Add the sample integration code to your page π
- (Optional) Modify the integration code using Player API Reference.
- Add Conversion Tracking π
Due to Shopify's technical limitations, the Miniplayer feature is not compatible with Shopify stores. You can read more about the Miniplayer compatibility here.
Get startedβ
Embedding a showβ
The simplest way to embed a One-to-many show on a Shopify store page is to copy-paste the embed code to your page content. In the Bambuser workspace, on each show setup page, you will find a code snippet that contains the embed code for that show. You can simply copy-paste it to any page (as HTML).
- Copy the embed code from the show setup page in the Bambuser workspace.
- On your Shopify page, switch the editor to HTML view.
- Paste the embed code and save the page.
To learn more about the embed code, how to make it autoplay, or how to customize the triggering element, read the Initial Setup guide.
Embedding multiple shows on one pageβ
If you want to embed multiple shows on one page you can call window.initBambuserLiveShopping
method multiple times to register more than one show.
window.initBambuserLiveShopping({
showId: 'BAMBUSER-LIVESHOPPING-SHOW-ID-HERE', // ShowID from the Workspace
node: document.getElementById('myCoolClickableThing'), // Triggering element
type: 'overlay',
});
In the example below you see how to have more than one show embedded into your landing page.
Example code
<!-- Your very cool interactive element here provided with a id attribute -->
<div id="myCoolClickableThing-1">Watch episode 1</div>
<div id="myCoolClickableThing-2">Watch episode 1</div>
<script>
(function() {
if (!window.initBambuserLiveShopping) {
window.initBambuserLiveShopping = function(item) { window.initBambuserLiveShopping.queue.push(item) };
window.initBambuserLiveShopping.queue = [];
var scriptNode = document.createElement('script');
scriptNode['src'] = 'https://lcx-embed.bambuser.com/your-brand-name/embed.js';
document.body.appendChild(scriptNode);
}
// Multiple shows can be embedded in a single page as below
// node: The trigger element for opening the specified show
window.initBambuserLiveShopping({
showId: 'BAMBUSER-LIVESHOPPING-SHOW-ID-HERE',
node: document.getElementById('myCoolClickableThing-1'),
type: 'overlay',
});
window.initBambuserLiveShopping({
showId: 'BAMBUSER-LIVESHOPPING-SHOW-ID-HERE',
node: document.getElementById('myCoolClickableThing-2'),
type: 'overlay',
});
})();
</script>
Cart Integrationβ
To add product and cart functionalities to the player, you need to implement Cart Integration into your Shopify store.
Sample integration codeβ
Here you find a sample integration code that implements the Cart Integration feature into your Shopify store. This sample code works on almost all Shopify stores that have standard product models without any changes required. However, if you have a special product setup, you may need to modify the code to justify that with your case.
In the next section, we explain how you should add the integration code into your Shopify store.
Sample code
- Cart integration code
- Sample product data
<script>
// ====================================== Define constants ========================================
// Reduces server calls if a product has a crazy number of images.
const MAX_IMAGES_COUNT = 6;
// Extracts product handle from the product URL
const SHOPIFY_PRODUCT_URL_HANDLE_REGEX = /\/products\/(.[\w\d-+]+)/;
// ====================================== General helper methods for Shopify ========================================
// Sometimes image URLs miss the protocol at the beginning
// E.g. '//cdn.shopify.com/s/files/.../image.jpg'
window.urlSanitizer = (url) => {
if (typeof url === 'string') {
if (url.startsWith('//')) return `https:${url}`;
else if (url.toLocaleLowerCase().startsWith('http')) return url;
else console.log(`Not a valid URL: ${url}`);
} else console.log(`Not a valid URL: ${url}`);
return null;
};
// Returns the store's active currency for the current user
// E.g,: 'EUR'
window.getActiveCurrency = () => {
// 1. From the Shopify object
const getCurrencyFromContext = Shopify?.currency?.active;
if (getCurrencyFromContext) return getCurrencyFromContext;
// 2. From the 'cart_currency' cookie
const currencyFromCookies = document.cookie
.split('; ')
.find((row) => row.startsWith('cart_currency'))
?.split('=')[1];
if (currencyFromCookies) return currencyFromCookies;
// If no currency found
return null;
};
//========== Shopify Ajax API Helper methods ===============
window.oneToManyStoreApi = {};
oneToManyStoreApi.getProductByUrl = (url) => {
const handle = SHOPIFY_PRODUCT_URL_HANDLE_REGEX.exec(url);
try {
if (typeof handle[1] == 'string' && handle[1].length > 0) {
return fetch('/products/' + handle[1] + '.js', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
}).then((resp) => resp.json());
}
} catch (error) {
throw new Error(
'Cannot find the handle in the product URL: ' + url + '/n' + error
);
}
};
oneToManyStoreApi.addToCart = (itemId) =>
fetch('/cart/add.js', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
items: [
{
quantity: 1,
id: itemId,
},
],
}),
}).then((resp) => resp.json());
oneToManyStoreApi.updateItemInCart = (itemId, quantity) =>
fetch('/cart/update.js', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
updates: {
[itemId]: quantity,
},
}),
}).then((resp) => resp.json());
oneToManyStoreApi.getCartState = () =>
fetch('/cart.js', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
}).then((resp) => resp.json());
oneToManyStoreApi.getVariantIdFromUrlParams = (url) => {
// Extract the variant ID from the URL
// URL Ex. https://www.MY-SHOPIFY-STORE.com/products/my-product-handle?variant=VARIATION_ID
const variantId = new URL(url).searchParams.get('variant');
return typeof variantId == 'string' && variantId.length == 14
? variantId
: null;
};
//=========== Bambuser onReady Handler =================
window.onBambuserLiveShoppingReady = (player) => {
// ---- Start of player configuration ----
player.configure({
currency: getActiveCurrency() || 'USD',
locale: 'en-US',
buttons: {
dismiss: player.BUTTON.CLOSE,
},
});
// ---- End of player configuration ----
// ---- Start of Cart Integrations ----
player.on(player.EVENT.ADD_TO_CART, (addedItem, callback) => {
oneToManyStoreApi
.addToCart(addedItem.sku)
.then((res) => {
if (res.items) {
callback(true);
console.log('Item added succussfully!');
} else if (res.description && res.description.includes('sold out')) {
callback({ success: false, reason: 'out-of-stock' });
} else callback(false);
})
.catch((error) => {
callback(false);
console.error('Add to cart error! ', error);
});
});
player.on(player.EVENT.UPDATE_ITEM_IN_CART, (updatedItem, callback) => {
console.log(
`Cart updated! ${updatedItem.previousQuantity} --> ${updatedItem.quantity}`
);
oneToManyStoreApi
.updateItemInCart(updatedItem.sku, updatedItem.quantity)
.then((res) => {
if (res.items) {
callback(true);
console.log('Item updated succussfully!');
} else callback(false);
})
.catch((error) => {
callback(false);
console.error('Error on updating item! ', error);
});
});
player.on(player.EVENT.SYNC_CART_STATE, () => {
// Use your method to check if the user has checkout
oneToManyStoreApi.getCartState().then((res) => {
if (res.item_count == 0) {
// Emptying the in-player cart
player.updateCart({
items: [],
});
}
});
});
player.on(player.EVENT.CHECKOUT, () => {
// Use the showCheckout() method to safely
// navigate the user to your checkout page
player.showCheckout(window.location.origin + '/cart');
});
// ---- End of Cart Integrations ----
// ---- Start of Product Hydration ----
player.on(player.EVENT.PROVIDE_PRODUCT_DATA, (event) => {
// Iterates over all the products you have added to the show on the workspace
event.products.forEach(({ ref: sku, id, url }) => {
const variantId = oneToManyStoreApi.getVariantIdFromUrlParams(url);
try {
// Your method to fetch a product data
oneToManyStoreApi.getProductByUrl(url).then((item) => {
//Uncomment the line below for debugging retrieved product data
//console.log(item);
player.updateProduct(id, (productFactory) =>
productFactory.product((detailsFactory) =>
detailsFactory
.name(item.title)
.sku(item.id)
.brandName(item.vendor)
.description(item.description)
.defaultVariationIndex(
variantId
? item.variants.findIndex(
(variant) => variant.id == variantId
)
: 0
)
.variations((variationFactory) =>
item.variants.map((variation) =>
variationFactory()
.attributes((attributeFactory) =>
attributeFactory.colorName(variation.title)
)
.imageUrls([
// Adding the featured image of the chosen variation (if existed) at the beginning of the images array
...(variation.featured_image
? [variation.featured_image.src]
: []),
// Adding product imgaes
...item.images
.slice(0, MAX_IMAGES_COUNT - 1)
.map((url) => urlSanitizer(url))
.filter((url) => typeof url === 'string'),
])
.name(variation.title)
.sku(item.id)
.sizes((sizeFactory) => [
sizeFactory()
.name(variation.title)
.sku(variation.id)
.inStock(variation.available)
.price((priceFactory) =>
priceFactory
.original(variation.compare_at_price / 100)
.current(variation.price / 100)
),
])
)
)
)
);
});
} catch (error) {
console.warn('CANNOT HYDRATE THE PRODUCT! \n', error);
}
});
});
};
</script>
{
"id":3780507959318,
"title":"Stratus Backpack",
"handle":"stratus-backpack",
"description":"\u003cmeta charset=\"utf-8\"\u003e\n\u003cp\u003e\u003ci\u003eThis is a demonstration store. You can purchase products like this from\u003cspan\u003e \u003ca href=\"https://caraasport.com\" title=\"Caraa\"\u003eCaraa\u003c/a\u003e\u003c/span\u003e.\u003c/i\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan\u003eLight as air. The Stratus is encased in cloud-like waterproof nylon and features exterior + interior pockets for your water bottle, umbrella, and laptop. Reach around to the side for on-the-go access to the main compartment. Collapse it for easy travel. Your backpack just got an upgrade.\u003c/span\u003e\u003c/p\u003e",
"published_at":"2020-03-09T16:13:44-04:00",
"created_at":"2020-03-09T16:13:50-04:00",
"vendor":"debut-rich-media-demo",
"type":"",
"tags":[],
"price":17500,
"price_min":17500,
"price_max":19500,
"available":true,
"price_varies":true,
"compare_at_price":null,
"compare_at_price_min":0,
"compare_at_price_max":0,
"compare_at_price_varies":false,
"variants":[
{
"id":29013951414294,
"title":"Navy",
"option1":"Navy",
"option2":null,
"option3":null,
"sku":"",
"requires_shipping":true,
"taxable":true,
"featured_image":{
"id":4721544527894,
"product_id":3780507959318,
"position":1,
"created_at":"2020-03-09T16:13:51-04:00",
"updated_at":"2020-03-09T16:13:51-04:00",
"alt":null,
"width":1058,
"height":1039,
"src":"https://cdn.shopify.com/s/files/1/0260/1061/5830/products/main_backpack.png?v=1583784831",
"variant_ids":[
29013951414294
]
},
"available":true,
"name":"Stratus Backpack - Navy",
"public_title":"Navy",
"options":[
"Navy"
],
"price":17500,
"weight":0,
"compare_at_price":null,
"inventory_management":"shopify",
"barcode":"",
"featured_media":{
"alt":null,
"id":1459887833110,
"position":1,
"preview_image":{
"aspect_ratio":1.018,
"height":1039,
"width":1058,
"src":"https://cdn.shopify.com/s/files/1/0260/1061/5830/products/main_backpack.png?v=1583784831"
}
}
},
{
"id":29013951447062,
"title":"Black",
"option1":"Black",
"option2":null,
"option3":null,
"sku":"",
"requires_shipping":true,
"taxable":true,
"featured_image":{
"id":4721544658966,
"product_id":3780507959318,
"position":4,
"created_at":"2020-03-09T16:13:51-04:00",
"updated_at":"2020-03-11T10:45:10-04:00",
"alt":null,
"width":1058,
"height":1039,
"src":"https://cdn.shopify.com/s/files/1/0260/1061/5830/products/stratus_03.png?v=1583937910",
"variant_ids":[
29013951447062
]
},
"available":true,
"name":"Stratus Backpack - Black",
"public_title":"Black",
"options":[
"Black"
],
"price":19500,
"weight":0,
"compare_at_price":null,
"inventory_management":"shopify",
"barcode":"",
"featured_media":{
"alt":null,
"id":1459887964182,
"position":5,
"preview_image":{
"aspect_ratio":1.018,
"height":1039,
"width":1058,
"src":"https://cdn.shopify.com/s/files/1/0260/1061/5830/products/stratus_03.png?v=1583784831"
}
}
},
{
"id":29013951479830,
"title":"Red",
"option1":"Red",
"option2":null,
"option3":null,
"sku":"",
"requires_shipping":true,
"taxable":true,
"featured_image":null,
"available":false,
"name":"Stratus Backpack - Red",
"public_title":"Red",
"options":[
"Red"
],
"price":17500,
"weight":0,
"compare_at_price":null,
"inventory_management":"shopify",
"barcode":""
}
],
"images":[
"//cdn.shopify.com/s/files/1/0260/1061/5830/products/main_backpack.png?v=1583784831",
"//cdn.shopify.com/s/files/1/0260/1061/5830/products/stratus_01.png?v=1583937910",
"//cdn.shopify.com/s/files/1/0260/1061/5830/products/stratus_02.png?v=1583937910",
"//cdn.shopify.com/s/files/1/0260/1061/5830/products/stratus_03.png?v=1583937910"
],
"featured_image":"//cdn.shopify.com/s/files/1/0260/1061/5830/products/main_backpack.png?v=1583784831",
"options":[
{
"name":"Color",
"position":1,
"values":[
"Navy",
"Black",
"Red"
]
}
],
"url":"/products/stratus-backpack",
"media":[
{
"alt":null,
"id":1459887833110,
"position":1,
"preview_image":{
"aspect_ratio":1.018,
"height":1039,
"width":1058,
"src":"https://cdn.shopify.com/s/files/1/0260/1061/5830/products/main_backpack.png?v=1583784831"
},
"aspect_ratio":1.018,
"height":1039,
"media_type":"image",
"src":"https://cdn.shopify.com/s/files/1/0260/1061/5830/products/main_backpack.png?v=1583784831",
"width":1058
},
{
"alt":null,
"id":1461301641238,
"position":2,
"preview_image":{
"aspect_ratio":1.0,
"height":1024,
"width":1024,
"src":"https://cdn.shopify.com/s/files/1/0260/1061/5830/products/StratusBag.jpg?v=1583937876"
},
"media_type":"model",
"sources":[
{
"format":"glb",
"mime_type":"model/gltf-binary",
"url":"https://model3d.shopifycdn.com/models/o/5f491746c036baf6/StratusBag.glb"
},
{
"format":"usdz",
"mime_type":"model/vnd.usdz+zip",
"url":"https://model3d.shopifycdn.com/models/o/c3b4ad9cbc191499/StratusBag.usdz"
}
]
},
{
"alt":null,
"id":1459887865878,
"position":3,
"preview_image":{
"aspect_ratio":1.018,
"height":1039,
"width":1058,
"src":"https://cdn.shopify.com/s/files/1/0260/1061/5830/products/stratus_01.png?v=1583784831"
},
"aspect_ratio":1.018,
"height":1039,
"media_type":"image",
"src":"https://cdn.shopify.com/s/files/1/0260/1061/5830/products/stratus_01.png?v=1583784831",
"width":1058
},
{
"alt":null,
"id":1459887931414,
"position":4,
"preview_image":{
"aspect_ratio":1.018,
"height":1039,
"width":1058,
"src":"https://cdn.shopify.com/s/files/1/0260/1061/5830/products/stratus_02.png?v=1583784831"
},
"aspect_ratio":1.018,
"height":1039,
"media_type":"image",
"src":"https://cdn.shopify.com/s/files/1/0260/1061/5830/products/stratus_02.png?v=1583784831",
"width":1058
},
{
"alt":null,
"id":1459887964182,
"position":5,
"preview_image":{
"aspect_ratio":1.018,
"height":1039,
"width":1058,
"src":"https://cdn.shopify.com/s/files/1/0260/1061/5830/products/stratus_03.png?v=1583784831"
},
"aspect_ratio":1.018,
"height":1039,
"media_type":"image",
"src":"https://cdn.shopify.com/s/files/1/0260/1061/5830/products/stratus_03.png?v=1583784831",
"width":1058
}
]
}
For more detailed information about the Cart Integration feature and its implementation, read Cart Integration guide.
Adding integration code to your Shopifyβ
There are different ways to add the integration code to the Shopify store. You need to make sure that your integration code is included in all pages that you have the player embedded on.
(Option 1) Add to the page contentβ
Recommended if:
- You only have a single landing page for the incoming traffic to the live show
Steps:
- Copy-paste the provided sample integration code to your page content (in HTML mode)
(Option 2) Add to all pagesβ
Recommended if:
- You have the player embedded on multiple or all pages
- You have the FAB widget embedded on all pages
Steps:
- In your Shopify theme codes, create a snippet and add the sample integration code there
- Assuming that you named the snippet
bambuser-cart-integration.liquid
, add this snippet to thetheme.liquid
layout as below:
{% render 'bambuser-cart-integration'%}
(Option 3) Add to a specific page templateβ
Recommended if:
- You have a set of pages where you embed the player
Steps:
- In your Shopify theme codes, create a snippet and add the sample integration code there
- Assuming that you named the snippet
bambuser-cart-integration.liquid
, you can add this snippet to your page template(s) as below:
{% render 'bambuser-cart-integration'%}
The resultβ
Once you have the cart integration working, you should be seeing the following behaviour:
- The product prices are shown in the product list
- Clicking a product shows the product details view in the player
- You can add products to the cart
- You can manage the cart and go to check out
Conversion Tracking on Shopifyβ
Adding the Bambuser Conversion Tracking to your Shopify store enables your team to track sales that are attributed to Bambuser shows.
Implement via Shopify Custom Pixelβ
Implement Bambuser Conversion Tracking in your Shopify store using a Shopify Custom Pixel.
- Log in to your Shopify Admin workspace
- From the bottom-left select
Settings
- Choose
Customer
events from the left menu - From the top-right, click on
Add custom pixel
- Give it a name and click
Add Pixel
- You should see a code box. If there are some codes already in the code box please remove them.
- Copy the code below (Select Global/EU servers based on your account's region!), and paste it on the Custom Pixel code box.
- Press Save and then press Connect
- Global Servers
- EU Specific Servers
Tracking library URL is different depending on location of servers that your workspace is set up on. Use Global servers URL https://cdn.liveshopping.bambuser.com/metrics/bambuser.min.js
if the login to your Bambuser workspace is on following link: https://lcx.bambuser.com/.
// ---------------------------------------------------------
// Bambuser Conversion Tracking for Shopify Pixels.
// Shopify Admin -> Settings -> Customer events
// ---------------------------------------------------------
// (IMPORTANT)
// Change the value to true only if your Bambuser workspace's base URL matches lcx-eu.bambuser.com
const USE_EU_SERVER = false;
// ---------------------------------------------------------
// For debugging
const LOGGING_ENABLED = false;
// ---------------------------------------------------------
// Subscribe to customer events using the analytics.subscribe() API
analytics.subscribe('checkout_completed', (event) => {
LOGGING_ENABLED && console.log('π - Running Conversion Tracking Customer Event...');
const checkout = event.data.checkout;
// Send the conversion data above to Bambuser
function onPurchaseBambuser () {
var data = {
event: 'purchase', // value needs to be βpurchaseβ
orderId: checkout.order.id, // The order id
orderValue: checkout.totalPrice.amount, // Total gross order value
currency: checkout.totalPrice.currencyCode, // The currency used for the order value
orderProductIds: checkout.lineItems.map((item) => item.id.toString()), // Array or comma-separated string of all product ids in the order
};
// Send the conversion data above to Bambuser
window._bambuser.collect(data);
LOGGING_ENABLED && console.log('π - If relevant, the purchase should be collected now!', data);
}
// Load the tracking library and sec invoke onPurchase() method
LOGGING_ENABLED && console.log('π - Mounting tracking script!');
var bamSrcElm = document.createElement('script');
bamSrcElm.src = USE_EU_SERVER ? 'https://cdn.liveshopping.bambuser.com/metrics/bambuser-eu.min.js' : 'https://cdn.liveshopping.bambuser.com/metrics/bambuser.min.js';
bamSrcElm.onload = onPurchaseBambuser;
document.body.appendChild(bamSrcElm);
});
Tracking library URL is different depending on location of servers that your workspace is set up on. Use European servers URL https://cdn.liveshopping.bambuser.com/metrics/bambuser-eu.min.js
if the login to your Bambuser workspace is on following link: https://lcx-eu.bambuser.com/.
// ---------------------------------------------------------
// Bambuser Conversion Tracking for Shopify Pixels.
// Shopify Admin -> Settings -> Customer events
// ---------------------------------------------------------
// (IMPORTANT)
// Change the value to true only if your Bambuser workspace's base URL matches lcx-eu.bambuser.com
const USE_EU_SERVER = true;
// ---------------------------------------------------------
// For debugging
const LOGGING_ENABLED = false;
// ---------------------------------------------------------
// Subscribe to customer events using the analytics.subscribe() API
analytics.subscribe('checkout_completed', (event) => {
LOGGING_ENABLED && console.log('π - Running Conversion Tracking Customer Event...');
const checkout = event.data.checkout;
// Send the conversion data above to Bambuser
function onPurchaseBambuser () {
var data = {
event: 'purchase', // value needs to be βpurchaseβ
orderId: checkout.order.id, // The order id
orderValue: checkout.totalPrice.amount, // Total gross order value
currency: checkout.totalPrice.currencyCode, // The currency used for the order value
orderProductIds: checkout.lineItems.map((item) => item.id.toString()), // Array or comma-separated string of all product ids in the order
};
// Send the conversion data above to Bambuser
window._bambuser.collect(data);
LOGGING_ENABLED && console.log('π - If relevant, the purchase should be collected now!', data);
}
// Load the tracking library and sec invoke onPurchase() method
LOGGING_ENABLED && console.log('π - Mounting tracking script!');
var bamSrcElm = document.createElement('script');
bamSrcElm.src = USE_EU_SERVER ? 'https://cdn.liveshopping.bambuser.com/metrics/bambuser-eu.min.js' : 'https://cdn.liveshopping.bambuser.com/metrics/bambuser.min.js';
bamSrcElm.onload = onPurchaseBambuser;
document.body.appendChild(bamSrcElm);
});
Troubleshootingβ
If you have any issues, check out the Conversion Tracking troubleshooting checklist. To find out more, see the Bambuser Conversion Tracking π documentation.