Provide Product Data
To be able to present products to the customer within the Calls Widget during a Video Consultation session you will need to follow the steps presented below.
The integration of products is purely frontend javascript communication between your site and Bambuser, although your frontend integration code needs to communicate with your backend for fetching the product data.
When an Agent enters a product identifier in the Agent Tool UI, the event provide-product-data
will be triggered in the embed instance (BambuserOneToOneEmbed
).
provide-product-data
event you will need to:-
Fetch your product object
Your frontend integration code requests product data from your backend and forward the information back to the embed instance.
-
Product Mapping
Inside the
updateProduct()
method you will need to map the product data into a predefined structure that we understand.
Fetch your product object
You should account for different ways to fetch your product object depending on how your agents will be adding products to the Calls Widget.
Fetch product by | Device | Description | Mandatory |
---|---|---|---|
SKU |
|
| Yes |
URL |
|
| Yes |
Scanned Code |
|
| No |
Product mapping
Attribute (required)
Attribute plays a big part when it comes to providng product data and defining product variants. Attributes are passed inside two methods: product()
and variations()
- First, you define different possible variations (e.g. size, color, material, ...) a product could have using
attributes()
function inside theproduct()
method. You will need to give a unique identifier to each attribute and its option.
e.g. attribute("attributeId")
and option("optionId")
- Second, you map the attribute defined in the
product()
method to each product variation inside thevariations()
method to identify a unique variant. You map this using previously defined"attributeId"
and"optionId"
.
e.g. attribute("attributeId", "optionId")
The presentation of products and possibility to compare product attributes will function better the more details (variations, attributes, info, rating etc) you have provided for each product. More information regarding this can be found below.
Related Products (optional)
When mapping your product, related products can also be specified. The related products will be presented to the agent in the tool UI and can easily be added to the Calls Widget.
If the agent adds one of the related products, the related product's SKU will get passed to provide-product-data
event.
Comparable attributes (optional)
When mapping your product, you can define extra comparable attributes. These attributes will be listed next to each other when the agent puts the displayed products into a compare view.
Rating (optional)
When mapping your product, you can provide information regarding the product's current rating. The rating is presented on the product display page
together with the general product information that you have provided.
Code Example
Event payload
Property | Description | Type |
---|---|---|
event.products | event.products object includes information about product reference added through Bambuser Agent Tool:
| Array |
Dynamic implementation
: Dynamic implementation based on the below sample product object (2) structureSample product data
: Example of a fetched product objectStatic implementation
: How the dynamic implementation code (1) would actually get read
- Dynamic implementation
- Sample product data
- Static implementation
oneToOneEmbed.on("provide-product-data", (event) => {
event.products.forEach(({
ref,
type,
id: bambuserId
}) => {
// Mandatory to handle at least URL and SKU
// Use the references provided above to fetch your product object
// Provide product data to the widget using the methods below.
// type: "url" | "product-reference" | "scanned-code"
let sku;
if (type === "url") {
sku = yourMethodToTransformUrlToSku(ref)
} else if (type === "scanned-code") {
sku = yourMethodToTransformBarcodeToSku(ref)
} else if (type === "product-reference") {
sku = ref;
}
// Fetch your product object
storeApi.getProduct(ref).then(yourProduct => {
// Product mapping
oneToOneEmbed.updateProduct(bambuserId, (productFactory) => {
return (
productFactory
// Mandatory
// currency of the product
.currency("USD")
// Mandatory
// locale that product is localized to
// Bambuser follow ISO 639-1 Code + "-" + ISO 3166-2 as standard locale format.
// The value should be of type string
.locale("en-US")
// Mandatory
// The product method contains a new chain
// these are methods specific to this actual product
.product((detailFactory) =>
detailFactory
// Optional
// Name of the product
.name(yourProduct.title)
// Optional
// Sku of your product
.sku(yourProduct.productId)
// Optional
// Define the index of specific variation
// which will be selected by default when
// agent fetches a product
// Example:
//.defaultVariationIndex(yourMethodToGetVariationIndex(ref, type))
.defaultVariationIndex(0)
// Mandatory
// Description for the product
.description(yourProduct.description)
// Preferred
// URL for product
.url(window.location.origin + yourProduct.slug)
// Mandatory
// The attributes method contains a new chain
// returned array defines any dimensions (e.g. color, size,...) of your product
.attributes((attribute) => {
return yourProduct.options.map((attr) =>
// Mandatory if your products contain more than one variant
// Attribute identifier
attribute(attr.optionId)
// Optional - If not provided, above specifed attribute identifier will replace it
// Localized name of the attribute
// This will show as a dropdown label in agent tool
.name(attr.name)
//Mandatory
// The options method contains a new chain
// Returned array available options of the dimension
.options((option) =>
attr.values.map((optionName) =>
// Mandatory
// Option identifier
option(optionName)
// Optional
// If not provided, above specifed option identifier will replace it
// Localized name of the option
// This will show as an option inside a dropdown in agent tool
.name(optionName)
)
)
);
})
// Mandatory
// The variations method contains a new chain
// Returned array defines variants (e.g. colors) of your product
.variations((variationFactory) =>
yourProduct.variants.map((variation) =>
// Mandatory
// The variationFactory method contains a new chain
// These are methods specific to this actual product variation
variationFactory()
// Mandatory
// Name of the variation
.name(variation.title)
// Preferred
// URL for variation
.url(window.location.origin + variation.slug)
// Optional
// Displayed below the price of the product
.subtitle(yourProduct.brand)
// Mandatory
// sku (or any other identifier for your product)
// specific down to this variation
.sku(variation.variationId)
// Optional
// Set whether this variation is in stock
// if false, the product wont be able to get added to the cart
// and it will get "Sold out" label when shown in the call
.inStock(variation.available)
// Mandatory
// list of image urls for the variation
// ordered the same as you want it displayed
//
// NOTE:
// Provided images will be compressed to optimize call performance
// If your product images are loading slowly / not loading, you might
// have to whitelist our Image Transformer.
// Read more about this in FAQ section under Provide Product Data:
// https://bambuser.com/docs/video-consultation/provide-product-data#frequently-asked-questions
.imageUrls(variation.images)
// Optional
// The price method contains a new chain
// Defines price for the specific variation
.price((priceFactory) =>
priceFactory
// Optional
// original price (in case current is a sale price)
.original(variation.original_price)
// Mandatory
// current price of the product
.current(variation.price)
)
// Mandatory if your products contain more than one variant
// The attributes method contains a new chain
// Returned array defines attributes for the unique variation
.attributes((attribute) =>
yourProduct.options.map((attr) =>
// Mandatory
// Attribute identifier and option identifier that identifies the variation
attribute(
attr.optionId,
variation["option" + attr.optionId]
)
)
)
// Optional
// List of extra specifications to show when comparing products.
// These will show on top of already specified attributes above
.comparableAttributes((attribute) =>
yourProduct.comparableAttributes.map((compAttr) =>
// Mandatory inside comparableAttributes()
// Comparable Attribute identifier and its value
attribute(compAttr.comparableAttributesId, compAttr.value)
// Optional
// If not provided, the above specifed attribute identifier will replace it
// Localized name of the comparable attribute
// This will show as an attribute name when comparing products
.name(compAttr.name)))
// Optional
// List of related products
// that will be shown in agent product information view
.relatedProducts((relatedProductFactory) =>
yourProduct.relatedProducts.map((relatProd) =>
// Mandatory inside relatedProducts()
// The relatedProductFactory method contains a new chain
// These are methods specific to this actual related product
relatedProductFactory()
// Mandatory inside relatedProductFactory()
// Title of the related product
.title(relatProd.title)
// Mandatory inside relatedProductFactory()
// SKU of the related product
// If agent clicks on the related product, the "provide-product-data" event
// will get triggered and pass this specific SKU as a reference
.sku(relatProd.sku)
// Mandatory inside relatedProductFactory()
// string of the thumbnail image url for the related product
.imageUrl(relatProd.thumbnail)
// Mandatory inside relatedProductFactory()
// The price method contains a new chain
// Defines price for the specific variation
.price(priceFactory =>
priceFactory
// Mandatory inside priceFactory
// current price of the product
.current(relatProd.price))
)
)
// Optional
// Unique selling points of the variant or product
// displayed on the product display page
// Options:
// BULLETS - expect an array
// PARAGRAPH - expects a string
.details(detail => [
detail("BULLETS", yourProduct.details.map(
(details) => details))
])
// Optional
// The rating method contains a new chain
// Defines rating for the specific variant or product
/// Rating are displayed as stars
.rating(ratingFactory =>
ratingFactory
// Mandatory inside ratingFactory
// Specify number max value
// This equal to the amount of total stars
// For best UI experience we do not recommend exceeding 10
.maxValue(yourProduct.rating.maxValue)
// Mandatory inside ratingFactory
// Average rating of your product
// This equals to how many amount of total stars are filled
// Should be equal or lower than the maxValue
.rating(yourProduct.rating.averageRating)
// Optional
// Number rating of your variant or product
// Displayed next to the star ratings
.numberOfRatings(yourProduct.rating.numberOfRatings))
)
)
)
);
});
})
});
});
{
"productId": "1111",
"title": "Bambuser Hoodie",
"description": "World's best hoodie",
"brand": "Bambuser",
"price": 100,
"details": [
"Loose fit",
"Cropped length",
"Functional fabric with soft-touch"
],
"slug": "/product/1737/bambuser-hoodie/",
"collection": "Super soft series",
"original_price": 150,
"rating": {
"averageRating": 4,
"maxValue": 5,
"numberOfRatings": 23
},
"comparableAttributes": [
{
"name": "Wool",
"comparableAttributesId": 1,
"value": "100%"
},
{
"name": "Washing Temperature",
"comparableAttributesId": 2,
"value": "40 degrees"
}
],
"relatedProducts": [
{
"title": "Bambuser Cap",
"sku": "2222",
"thumbnail": "https://demo.bambuser.shop/wp-content/uploads/2021/09/cap_600x.jpeg",
"price": 30
},
{
"title": "Bambuser Tote Bag",
"sku": "3333",
"thumbnail": "https://demo.bambuser.shop/wp-content/uploads/2020/09/bb-tote.png",
"price": 5
}
],
"options": [
{
"name": "Color",
"optionId": 1,
"values": [
"Black",
"White"
]
},
{
"name": "Size",
"optionId": 2,
"values": [
"Small"
]
}
],
"variants": [
{
"variationId": "1111-black-small",
"title": "Black Bambuser Hoodie",
"slug": "/product/1737/bambuser-hoodie/?attribute_color=Black&attribute_size=Small",
"option1": "Black",
"option2": "Small",
"available": true,
"price": 100,
"original_price": 150,
"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"
]
},
{
"variationId": "1111-white-small",
"title": "White Bambuser Hoodie",
"slug": "/product/1737/bambuser-hoodie/?attribute_color=White&attribute_size=Small",
"option1": "White",
"option2": "Small",
"available": false,
"price": 100,
"original_price": 150,
"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"
]
}
]
}
// This is only for demonstration purposes
// Hardcoding products data is not recommended
oneToOneEmbed.on("provide-product-data", (event) => {
event.products.forEach(({
ref,
type,
id: bambuserId
}) => {
// let sku;
// if (type === "url") {
// sku = yourMethodToTransformUrlToSku(ref)
// } else if (type === "scanned-code") {
// sku = yourMethodToTransformBarcodeToSku(ref)
// } else if (type === "product-reference") {
// sku = ref;
// }
// Fetch your product object
// storeApi.getProduct(ref).then(yourProduct => {
oneToOneEmbed.updateProduct(bambuserId, (productFactory) => {
return (
productFactory
.currency("USD")
.locale("en-US")
.product((detailFactory) =>
detailFactory
.name("Bambuser Hoodie")
.sku("1111")
.defaultVariationIndex(0)
.description("World's best hoodie")
.url("https://demo.bambuser.shop/product/1737/bambuser-hoodie/")
.attributes((attribute) => [
attribute(1)
.name("Color")
.options((option) => [
option("Black").name("Black"),
option("White").name("White")
]),
attribute(2)
.name("Size")
.options((option) => [
option("Small")
.name("Small")
]),
])
.variations((variationFactory) => [
variationFactory()
.name("Black Bambuser Hoodie")
.url("https://demo.bambuser.shop/product/1737/bambuser-hoodie/?attribute_color=Black&attribute_size=Small")
.subtitle("Bambuser")
.sku("1111-black-small")
.inStock(true)
.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"
])
.price((priceFactory) =>
priceFactory
.original(150)
.current(100)
)
.attributes((attribute) => [
attribute(1, "Black"),
attribute(2, "Small"),
])
.comparableAttributes((attribute) => [
attribute(1, "100%")
.name("Cotton"),
attribute(2, "40 degrees")
.name("Washing Temperature")
])
.relatedProducts((relatedProductFactory) => [
relatedProductFactory()
.title("Bambuser Cap")
.sku("2222")
.imageUrl("https://demo.bambuser.shop/wp-content/uploads/2021/09/cap_600x.jpeg")
.price(priceFactory =>
priceFactory
.current(30)),
relatedProductFactory()
.title("Bambuser Tote Bag")
.sku("3333")
.imageUrl("https://demo.bambuser.shop/wp-content/uploads/2020/09/bb-tote.png")
.price(priceFactory =>
priceFactory
.current(5))
])
.details(detail => [
detail("BULLETS",
["Loose fit",
"Cropped length",
"Functional fabric with soft-touch"
])
])
.rating(ratingFactory =>
ratingFactory
.maxValue(5)
.rating(4)
.numberOfRatings(23)
),
variationFactory()
.name("White Bambuser Hoodie")
.url("https://demo.bambuser.shop/product/1737/bambuser-hoodie/?attribute_color=White&attribute_size=Small")
.subtitle("Bambuser")
.sku("2222-white-small")
.inStock(false)
.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"
])
.price((priceFactory) =>
priceFactory
.original(150)
.current(100)
)
.attributes((attribute) => [
attribute(1, "White"),
attribute(2, "Small"),
])
.comparableAttributes((attribute) => [
attribute(1, "100%")
.name("Wool"),
attribute(2, "40 degrees")
.name("Washing Temperature")
])
.relatedProducts((relatedProductFactory) => [
relatedProductFactory()
.title("Bambuser Cap")
.sku("2222")
.imageUrl("https://demo.bambuser.shop/wp-content/uploads/2021/09/cap_600x.jpeg")
.price(priceFactory =>
priceFactory
.current(30)),
relatedProductFactory()
.title("Bambuser Tote Bag")
.sku("3333")
.imageUrl("https://demo.bambuser.shop/wp-content/uploads/2020/09/bb-tote.png")
.price(priceFactory =>
priceFactory
.current(5))
])
.details(detail => [
detail("BULLETS",
["Loose fit",
"Cropped length",
"Functional fabric with soft-touch"
])
])
.rating(ratingFactory =>
ratingFactory
.maxValue(5)
.rating(4)
.numberOfRatings(23))
])
)
);
});
});
});
//})
Provide Search Data
To optimize the effort of adding products, integration can be extended with the option to provide search data. Agents will be able to search for products in a flexible way with better support to find the best fit product.
Read more about the integration specifics here.
Frequently Asked Questions
Provided images will be compressed to optimize call performance, which is done thorough our Image Tranformer. In some cases,
you might be blocking those request. For that, you will have to whitelist our Image Transformer. You can do this in two different ways:
- By User-Agent
The Image Transformer will identify itself with the following user-agent:BambuserLiveShopping/1.0
. You can make an exception for requests made by this user-agent. Once whitelisted the user-agent, it should start working right away. - By Static IP Address
You can also whitelist our Image Transformer through the static IP address: - Global server:
35.224.84.15
- EU server:
35.240.106.166
STATIC IP ACTIVATION
Beside whitelisting our static IP address from your side, you also need to inform Bambuser staff to enable 'Static IP proxy' for your organization.