Skip to main content

Provide Product Data

To be able to present products to the customer within the Call Widget during a One-to-One 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).

Inside provide-product-data event you will need to:
  1. Fetch your product object

    Your frontend integration code requests product data from your backend and forward the information back to the embed instance.

  2. Product Mapping

    Inside the updateProduct() method you will need to map the product data into a predefined structure that we understand.

img

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 Call Widget.

Fetch product byDeviceDescriptionMandatory
SKU
  • Desktop
  • Mobile App
  • Agent enters the SKU of the product to the Desktop agent tool
Yes
URL
  • Desktop
  • Mobile App


  • Agent copy/paste product to the Desktop agent tool
  • In mobile app, when agent clicks on Add Product from agent UI, your products overview page will open in the webview inside our app. From there, agent will have to navigate to a specific PDP and add the product to the call. PDP URL will then be passed to event payload
Yes
Scanned Code
  • Mobile App

  • Agent will be able to scan a barcode of the product through the mobile app. If the scanned code is different to the SKU on your end, you will have to account for fetching the product through scanned code as well
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()

  1. First, you define different possible variations (e.g. size, color, material, ...) a product could have using attributes()  function inside the product() method. You will need to give a unique identifier to each attribute and its option.

    e.g. attribute("attributeId") and option("optionId")

  2. Second, you map the attribute defined in the product() method to each product variation inside the variations() 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.

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 Call 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

PropertyDescriptionType
event.productsevent.products object includes information about product reference added through Bambuser Agent Tool:

  • ref : reference based on how the product was added
  • type: type of the product reference
    • url - product was added using URL
    • scanned-code - product was added using barcode on mobile
    • product-reference - product is neither URL or scanned-code
  • id : Bambuser generated ID for each product added to the widget. This id is passed as the first argument of the player.updateProduct() method
Array

  1. Dynamic implementation: Dynamic implementation based on the below sample product object (2) structure
  2. Sample product data: Example of a fetched product object
  3. Static implementation: How the dynamic implementation code (1) would actually get read
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/one-to-one/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))
)
)
)
);
});
})
});
});

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:

  1. By User-Agent
  2. 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.

  3. By Static IP Address
  4. You can also whitelist our Image Transformer through the static IP address:


    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.