Skip to main content

Player API reference

The Bambuser Player API provides methods to configure the behavior and appearance of the Bambuser Live Shopping Player on your website or mobile app. This reference covers all configuration options, events, methods, and constants available across Web (JavaScript), Swift (iOS), and Kotlin (Android) platforms.

Getting Started

After setting up your onBambuserLiveShoppingReady handler (example below) you can start customizing the behavior of your player.

<script>
window.onBambuserLiveShoppingReady = player => {
// player = Bambuser Player API
// All configuration, event listeners, and method calls
// demonstrated in this reference go here.
};
</script>

Note that the player object and its properties (constants and methods below) are only accessible within the onBambuserLiveShoppingReady method body.

Important

All JavaScript code examples in this reference must be placed inside the onBambuserLiveShoppingReady callback. Define this method before you call initBambuserLiveShopping to initialize any instances of the player when embedding the code snippet.

Example:

<script>
window.onBambuserLiveShoppingReady = player => {
player.configure({
currency: "USD",
locale: "en-US"
});

player.on(player.EVENT.READY, () => {
console.log("Player is ready!");
});
};
</script>
How it works

Configuration Options

The player can be configured to meet your needs using the configure method on Web, or by passing a configuration map on mobile SDKs. If implementing cart integration, some configurations like currency and locale are required for the player to correctly display products and translations.

player.configure(configuration)

player.configure({
currency: "USD",
locale: "en-US",
buttons: {
dismiss: player.BUTTON.MINIMIZE,
checkout: player.BUTTON.MINIMIZE,
},
});

configuration.locale

  • Value type: string
  • Default: Workspace default locale

Sets the global locale of the player, defining the language and region for products, cart, and checkout integration. The value must be in the format languageCode-countryCode (e.g., en-US, sv-SE).

To support a locale, it must first be added in Bam Hub under Settings > Translations. If the specified locale is not available, the player falls back to the default locale defined in your Bam Hub.

note

Translation updates may take up to 30 minutes to reflect due to caching.

Usage example:

player.configure({
locale: "en-US",
});

Dynamic locale example:

const userLocale = yourMethodToGetUserLocale(); // e.g., "sv-SE" for Swedish
player.configure({
locale: userLocale,
});

configuration.currency

  • Value type: string
  • Default: None (must be set for product display)

Sets the global currency of the player. The value should contain the three-letter ISO currency code (e.g., USD, EUR, SEK). If no other currency is specified, this value is used for products, cart, and checkout integration.

Usage example:

player.configure({
currency: "USD",
});

configuration.autoplay

  • Value type: boolean
  • Default: true

Controls whether the video automatically plays when the player is presented.

note

Some browsers do not allow media to autoplay with unmuted sound. In those cases, the player will autoplay the video with muted sound instead.

Usage example:

player.configure({
autoplay: false, // Video will not play automatically when player is presented
});

configuration.externalTitle and configuration.innerTitle

  • Value type: string
  • Default: externalTitle = "Bambuser Live Shopping Player", innerTitle = value of externalTitle

Define accessibility titles for the player:

  • externalTitle sets the iframe title attribute outside the player.
  • innerTitle sets the player page document.title inside the iframe.

innerTitle is escaped and capped at 200 characters. externalTitle is used verbatim, so keep it short yourself.

tip

Set both values explicitly for better screen-reader context. Keep them plain and short.

Usage example:

player.configure({
externalTitle: "Live shopping video player",
innerTitle: "Spring drop live show - Bambuser",
});

configuration.buttons

  • Value type: object
  • Default: Varies per button (see table below)

Configures how buttons behave in the player. Each button can be set to follow a behavior specified in the player.BUTTON constants section.

ButtonDescriptionAvailable BehaviorsDefault Behavior
dismissThe button in the upper right corner of the playerCLOSE, MINIMIZE, NONE, EVENTAUTO
checkoutThe checkout buttonLINK, MINIMIZE, EVENTAUTO
productClick on a product reference, in the highlight or the product listLINK, MINIMIZE, INLINE, NONE, EVENTAUTO
minimizeThe minimize button in the playerEVENTAUTO
actionCardClick on an action cardLINK, INLINE, NONE, EVENTAUTO
productListThe product list (and cart) buttonEVENTAUTO
addToCartThe add-to-cart button on products and the product highlightEVENTAUTO

Use case example — Disable the Miniplayer:

player.configure({
buttons: {
dismiss: player.BUTTON.CLOSE,
},
});

Use case example — Enable the Miniplayer:

player.configure({
buttons: {
dismiss: player.BUTTON.MINIMIZE,
},
});

Use case example — Force product clicks to open PDP in new tab:

player.configure({
buttons: {
product: player.BUTTON.LINK,
},
});

Use case example — Force product clicks to minimize the player and show PDP:

player.configure({
buttons: {
dismiss: player.BUTTON.MINIMIZE,
product: player.BUTTON.MINIMIZE,
},
});

Use case example — Minimize on checkout and product click:

player.configure({
buttons: {
dismiss: player.BUTTON.MINIMIZE,
checkout: player.BUTTON.MINIMIZE,
},
});

Use case example — Override product click action with your custom handler:

By default the player decides what a product click does — opening its own product view, a new tab, or minimizing behind your PDP. Setting product to player.BUTTON.EVENT stops the player from acting on the click altogether and leaves it to you: it only emits SHOW_PRODUCT_VIEW event with the clicked product, and your handler decides what happens next.

player.configure({
buttons: {
product: player.BUTTON.EVENT,
},
});
player.on(player.EVENT.SHOW_PRODUCT_VIEW, (product) => {
// The player does nothing on its own — open your own PDP, drawer, or route
yourOpenProductDetails(product);
});

This applies to product clicks anywhere in the player: the product highlight and the product list alike.

note

player.BUTTON.NONE suppresses the same click handling, and SHOW_PRODUCT_VIEW is emitted in both cases. Prefer EVENT when you intend to handle the click yourself, so the configuration states your intent.

Use case example — Run a custom callback function on checkout button click:

player.configure({
buttons: {
dismiss: player.BUTTON.MINIMIZE,
checkout: player.BUTTON.EVENT,
},
});
player.on(player.EVENT.CHECKOUT, () => {
// Custom behavior on checkout button click
// Example: minimize the player and open a site's cart drawer in your app
player.minimize();
window.openCartDrawer();
});

configuration.audioTrackLocale

  • Value type: string
  • Default: None

Sets the default audio track language when dubbed audio is enabled. The player automatically selects and plays the appropriate dubbed language when multiple audio options are available, eliminating the need for users to manually choose a language.

Usage example:

player.configure({
audioTrackLocale: "de-DE", // Sets German dubbed audio as the default
});

configuration.shareTargets

  • Value type: Array<string>
  • Default: ['facebook', 'whatsapp', 'email', 'twitter', 'linkedin']

Overrides the default share targets displayed in the player's share dialog.

All Available Share Targets
  • linkedin (default)
  • twitter (default)
  • whatsapp (default)
  • email (default)
  • facebook (default)
  • instapaper
  • line
  • liveJournal
  • mailRu
  • odnoklassniki
  • pocket
  • reddit
  • telegram
  • tumblr
  • viber
  • vk
  • wechat
  • weibo
  • workplace

Usage example:

player.configure({
shareTargets: ['reddit', 'telegram'],
});

configuration.minimizedPosition

  • Value type: string or constant
  • Default: player.MINIMIZED_POSITION.BOTTOM_RIGHT

Configures the initial position of the Miniplayer. See player.MINIMIZED_POSITION for available positions.

Usage example:

player.configure({
minimizedPosition: player.MINIMIZED_POSITION.BOTTOM_LEFT,
});

configuration.checkoutOnCartClick

  • Value type: boolean
  • Default: false

When set to true, the player emits the CHECKOUT event when clicking any button that would normally open the in-player cart, instead of opening the player's internal cart view.

Usage example:

player.configure({
checkoutOnCartClick: true,
});

configuration.shareBaseUrl

  • Value type: string
  • Default: window.location.href

Overrides the base URL for creating a link to access the show for both the Share and Add to Calendar features. The URL must be an absolute path and can include protocol (http:// or https://) and query parameters.

If shareBaseUrl is undefined, null, or '', the share URL defaults to window.location.href.

Usage example:

player.configure({
shareBaseUrl: 'https://example.com/live-shopping?referer=joe',
});

configuration.trackingTags

  • Value type: Array<{key: string, value: string | number | boolean}>
  • Default: []

Add a list of custom tracking tags which are sent once at the beginning of the session via the on-configuration event. The tags are not attached to all tracking events. Instead, they are sent once during initialization, and Bambuser's backend aggregation system stitches them together with the session data.

Can also be set or updated later using the setTrackingTags() method.

Usage example:

player.configure({
trackingTags: [{ key: 'memberId', value: '123-abc' }],
});

configuration.allowShareAutoplay

  • Value type: boolean
  • Default: true

Controls whether the shared URL includes the ?autoplayLiveShopping=[showId] query parameter. When set to false, users who open a shared link will not get autoplay behavior. Learn more about Autoplay.

Usage example:

player.configure({
allowShareAutoplay: false,
});

configuration.enableFirstPartyCookies

  • Value type: boolean
  • Default: true

Controls whether the player sets first-party cookies. If a user has declined cookies through your cookie consent, you may need to disable the player's cookies using this configuration.

caution

This flag should only be set to false for visitors who declined cookies. The Shopper Events Tracker cannot collect purchase data from users who do not have cookies set.

Usage example:

// Replace `hasDeclinedCookies` with your own logic
player.configure({
enableFirstPartyCookies: !hasDeclinedCookies(),
});

configuration.cookie

  • Value type: object

Settings for first-party cookies set by the player.

Properties:

  • domain (string) — Sets the domain attribute of the first-party cookies.
  • activityCookieTTLDays (number) — Changes the expiration time for Conversion Tracking cookies (_bamls_shid and _bamls_lits) and consequently the duration of time that purchases are tracked.

Usage example:

player.configure({
cookie: {
domain: '.example.com', // Cookies accessible by all subdomains
activityCookieTTLDays: 1, // Track conversions for 1 day after interaction
},
});

configuration.trimPriceTrailingZeros

  • Value type: boolean
  • Default: false

Removes the price decimals when they are equal to zero. For example, $100.00 becomes $100.

Usage example:

player.configure({
trimPriceTrailingZeros: true,
});

  • Value type: string
  • Default: None

Makes the player seek to a specific product appearance reference in the show. The deeplink value for a product appearance can be found via the product appearances REST API endpoints.

note

The deeplink value will become invalid if the video content for a specific show is changed. Fetch a new value from the API when this happens.

Usage example:

player.configure({
deeplink: "f00ba5@100",
});

// Alternative: pass deeplink at initialization
window.initBambuserLiveShopping({
showId: 'YOUR_SHOW_ID',
deeplink: "f00ba5@100",
});

configuration.ui

  • Value type: object
  • Default: All false (nothing hidden)

Controls the visibility of different UI elements inside the player.

Available properties:

  • hideAll — Hides all UI elements at once
  • hideActionBar
  • hideAddToCalendar
  • hideAddToCalendarButton — Hides only the button that opens the add-to-calendar dialog
  • hideCartButton
  • hideCartView
  • hideChatOverlay
  • hideClosedCaptionsButton — Hides the closed captions (subtitles) button
  • hideEmojiOverlay
  • hidePlaybackRateButton — Hides the playback speed control button
  • hideProductList
  • hideProductView
  • hidePromotedShows — Hides promoted shows shown at the end of a video
  • hideShareButton
  • hideShareFromTimestampButton — Hides the share-from-timestamp button
  • hideShareView
  • hideVolumeButton — Hides the volume control button
  • hideWishlist
  • showShareButtonInMobileActionBar — Shows the share button in the mobile action bar (default false)
tip

Use hideAll: true to hide every UI element in one go.

Usage example:

// Hide all UI elements
player.configure({
ui: {
hideAll: true,
},
});

// Or hide individual elements
player.configure({
ui: {
hideAddToCalendar: true,
hideShareView: true,
},
});

configuration.overrideSafeAreaInsets

  • Value type: object{ top?: number, right?: number, bottom?: number, left?: number } (pixels)
  • Default: None

Overrides the safe area insets used by the player layout. Useful when embedding in mobile WebViews where the host app applies its own insets or when additional bottom spacing is needed to avoid gesture areas.

This configuration will apply the specified insets even if the browser does not provide any.

Usage example:

player.configure({
overrideSafeAreaInsets: { bottom: 100 },
});

configuration.neverCollapseTimelineBarMobile

  • Value type: boolean
  • Default: false

Prevents the timeline bar from collapsing on mobile viewports, keeping it expanded for improved touch targeting near OS gesture areas. Combine with overrideSafeAreaInsets if additional bottom spacing is needed.

Usage example:

player.configure({
neverCollapseTimelineBarMobile: true,
});

configuration.startMuted

  • Value type: boolean
  • Default: false

Starts the player in a muted state. Unlike autoplay muting (which is browser-enforced), this explicitly mutes the player regardless of autoplay policy. The player can later be unmuted by the user or programmatically via player.unmute().

Usage example:

player.configure({
startMuted: true,
});

configuration.disableChatInput

  • Value type: boolean
  • Default: false

When set to true, the viewer cannot type in the chat, but can still see incoming CHAT_MESSAGES. Useful when chat should be read-only for the audience.

Usage example:

player.configure({
disableChatInput: true,
});

configuration.disableClickOutsideBehavior

  • Value type: boolean
  • Default: false

Disables the default behavior of closing or minimizing the player when the user clicks outside of it. Useful when the player is embedded alongside interactive page content that should remain clickable.

Usage example:

player.configure({
disableClickOutsideBehavior: true,
});

configuration.allowSoundControl

  • Value type: boolean
  • Default: false

Adds a visible mute/unmute button on the desktop version of the player. Mute state changes trigger the MUTED and UNMUTED events. You can also control mute state programmatically via player.mute() and player.unmute().

Usage example:

player.configure({
allowSoundControl: true,
});

configuration.playerContainerNode

  • Value type: DOM element
  • Default: document.body

Sets the DOM node where the player iframe is rendered. If no node is specified, the player is appended to the <body> element. Useful when you need the player inside a specific container for layout or z-index stacking context control.

Usage example:

player.configure({
playerContainerNode: document.getElementById('player-container'),
});

configuration.miniplayerSize

  • Value type: string or constant
  • Default: player.MINIPLAYER_SIZE.SMALL

Configures the size of the Miniplayer. See player.MINIPLAYER_SIZE for available values.

Usage example:

player.configure({
miniplayerSize: player.MINIPLAYER_SIZE.LARGE,
});

configuration.miniPlayer

  • Value type: object

Configuration options for the Miniplayer layout.

Properties:

  • edgeSpacing (object) — Defines the spacing (in pixels) between the Miniplayer and the viewport edges. Accepts { top?: number, right?: number, bottom?: number, left?: number }.

Usage example:

player.configure({
miniPlayer: {
edgeSpacing: { bottom: 80, right: 20 },
},
});

configuration.floatingPlayer

  • Value type: object

Configuration for the floating player (the player that stays visible during site navigation when minimized). Learn more about Miniplayer compatibility and navigation.

Properties:

  • navigationMode (string) — How site navigation works when the floating player is active. Use player.FLOATING_PLAYER_NAVIGATION_MODE constants. Possible values:
    • IFRAME (default) — Adds an iframe above the existing site where all navigation happens, with the floating player placed on top.
    • MANUAL — Only shows the floating player; site navigation is handled by your app. Best suited for SPAs where page content updates without full page loads. See Miniplayer for SPA websites.

Usage example:

player.configure({
floatingPlayer: {
navigationMode: player.FLOATING_PLAYER_NAVIGATION_MODE.MANUAL,
},
});

configuration.themeId

  • Value type: string
  • Default: None

Applies a specific theme to the player. The theme ID can be found in your Bam Hub under theme settings.

Usage example:

player.configure({
themeId: "your-theme-id",
});

configuration.playerOrientation

  • Value type: string
  • Default: auto

Controls the orientation of the player. When unset, the player automatically determines orientation based on video content.

Possible values:

  • "portrait" — Forces portrait orientation
  • "landscape" — Forces landscape orientation

Usage example:

player.configure({
playerOrientation: "landscape",
});

configuration.allowMinimizeOnCurtains

  • Value type: boolean
  • Default: true

Whether the top-right button stays a minimize button while a curtain is showing (pre-show, paused, ended, and similar). Set it to false where minimizing is impossible — a native Picture-in-Picture host, for example — and the button falls back to close on curtains.

note

Only relevant when the Miniplayer is enabled via buttons.dismiss: player.BUTTON.MINIMIZE. Otherwise the button is always a close button.

Usage example:

player.configure({
allowMinimizeOnCurtains: false,
});

configuration.disableTouchMoveScrollPrevention

  • Value type: boolean
  • Default: false

By default the player swallows touchmove, so dragging inside it does not scroll the page behind. Set true to let the event through — needed when the player runs in a WebView inside a native scrollable container.

Usage example:

player.configure({
disableTouchMoveScrollPrevention: true,
});

configuration.useViewportFitScale

  • Value type: boolean
  • Default: false

Adds viewport-fit=cover to the embedding page's viewport meta tag while the player is open, restoring it on close. Applied automatically in an iOS WKWebView; set this flag to force it elsewhere, or on a web component embed, where it is opt-in. Pairs with overrideSafeAreaInsets.

Usage example:

player.configure({
useViewportFitScale: true,
});

configuration.experimental

  • Value type: object
  • Default: {}

Configures behavior and functionality of the player using experimental flags.

warning

All flags under experimental are subject to change and should be used with caution. When a feature is considered "production ready" it will be moved to the general configuration.

Available properties:

  • chatName (string) — Sets the chat alias for the user instead of prompting when entering chat.
  • hasAcceptedTerms (boolean) — Disables the terms & conditions prompt if set to true.
  • sandboxAttributes (string) — Applies the provided value as-is to the player and surf iframes' sandbox attribute.
  • credentiallessIframes (boolean) — Adds the credentialless attribute to all iframes created by the player. See MDN: credentialless.

Usage example:

player.configure({
experimental: {
chatName: "John D",
hasAcceptedTerms: true,
},
});

Events

The Player API provides events you can listen to for integrating player behavior with your application. Events are categorized below by functionality.

Event Subscription

Use player.on() to register event listeners and player.off() to remove them. Use constants from player.EVENT for event names.

// Register an event listener
player.on(player.EVENT.READY, () => {
console.log("Player is ready");
});
// Remove a specific event listener
const handleClose = () => {
console.log("Player was closed");
};

player.on(player.EVENT.CLOSE, handleClose);

// Later, remove the listener (must pass the same function reference)
player.off(player.EVENT.CLOSE, handleClose);
// Remove all event listeners (use with caution)
player.removeAllListeners();

Player Lifecycle Events

LOAD

  • Web constant: player.EVENT.LOAD
  • SDK event string: "load"

Fired when the player app has been loaded.

Payload: None

Example:

player.on(player.EVENT.LOAD, () => {
console.log("Player app loaded");
});

READY

  • Web constant: player.EVENT.READY
  • SDK event string: "ready"

Fired when the player GUI has been loaded and is ready for user interactions.

Payload:

{
orgId: "your-organization-id",
userId: "bambuser-user-id", // Anonymous viewer identifier
sessionId: "bambuser-session-id",
withMinimizeSupport: true, // Whether the Miniplayer is enabled
playerVersion: 2,
preferNewTabCheckout: true // Only present when using cart integration
}

Example:

player.on(player.EVENT.READY, () => {
console.log("Player is ready for interaction");
});

CLOSE

  • Web constant: player.EVENT.CLOSE
  • SDK event string: "close"

Fired when the user closes the player.

Payload:

{
actionOrigin: "player" // Where the close was triggered from
}
note

actionOrigin is omitted when the player is closed by clicking outside of it rather than through a player control.

Example:

player.on(player.EVENT.CLOSE, () => {
console.log("Player was closed");
});

LOAD_ERROR

  • Web constant: player.EVENT.LOAD_ERROR
  • SDK event string: "load-error"

Fired when the player fails to load a show (e.g., invalid show ID, unpublished, or deleted show).

Payload:

{
status: 404 // Currently only status 404 is supported
}

Example:

player.on(player.EVENT.LOAD_ERROR, (data) => {
if (data.status === 404) {
console.log("Show not found");
}
});

UPDATE_SHOW_STATUS

  • Web constant: player.EVENT.UPDATE_SHOW_STATUS
  • SDK event string: "should-update-show-status"

Fired when the show status changes (e.g., transitioning from live to ended, or from pre-show to live).

Payload: { showStatus: string }

StatusString value
Loading"livecommerce:loading"
Playing live"livecommerce:playing-live"
Playing recorded"livecommerce:playing-recorded"
Browser not supported"livecommerce:browser-not-supported"

Example:

player.on(player.EVENT.UPDATE_SHOW_STATUS, (data) => {
console.log("Show status changed", data);
});

Product Events

PROVIDE_PRODUCT_DATA

  • Web constant: player.EVENT.PROVIDE_PRODUCT_DATA
  • SDK event string: "provide-product-data"

Fired when the player needs product data to display. This event is triggered during initialization and at various points during the session. You must handle this event and provide product details using player.updateProduct().

Payload:

{
context: "display", // "pre-load" | "will-display" | "display"
products: [
{
id: "bambuser-generated-product-id",
ref: "product-sku-or-reference",
url: "https://example.com/product-page"
}
],
options: {
eventId: "show-id",
locale: "en-US", // resolved player locale
currency: "USD" // resolved player currency
},
}

context tells you why the player is asking, so you can prioritize your own lookups: pre-load is a background prefetch, will-display means the product is about to be shown, and display means it is being shown now.

Example:

player.on(player.EVENT.PROVIDE_PRODUCT_DATA, (event) => {
event.products.forEach(({ ref: sku, url, id: bambuserId }) => {
yourGetProductMethod(sku).then((product) => {
player.updateProduct(bambuserId, (factory) =>
factory.product((detail) =>
detail
.name(product.name)
.sku(product.sku)
.brandName(product.brand)
// ... see updateProduct() for full builder API
)
);
});
});
});
note

For complete product hydration examples, see the player.updateProduct() method.


SHOW_PRODUCT_VIEW

  • Web constant: player.EVENT.SHOW_PRODUCT_VIEW
  • SDK event string: "should-show-product-view"

Fired when a product is clicked (from the product list or a highlighted product).

Payload:

{
vendor: "hydratable-product",
id: "bambuser-generated-product-id",
ref: "product-sku-or-reference",
sku: "product-sku",
title: "Product name",
url: "https://example.com/product-page",
actionOrigin: "highlight",
actionTarget: "show-product-detail-none",
raw: { /* feed columns — catalog-sourced products only */ }
}
FieldDescription
vendorAlways the constant "hydratable-product". A schema marker, not a merchant or brand identifier — safe to ignore.
idBambuser-generated product ID, the same one used with player.updateProduct()
refYour product reference as configured on the show
skuResolved SKU for the product
titleProduct name
urlPublic product URL with the player's tracking parameters appended if enabled
actionOriginWhere the click came from: highlight, highlightCta, productsList, bundle, lightPDP, or externalApiCall. Absent for clicks from the in-player cart.
actionTargetWhat the player did about it: show-product-detail-in-player, show-product-detail-in-new-tab, show-product-detail-behind-player, or show-product-detail-none
rawCatalog feed columns, catalog-sourced products only
note

When buttons.product is player.BUTTON.EVENT or NONE, actionTarget is show-product-detail-none — the player emitted the event and did nothing else, leaving the click to your handler.

Example:

player.on(player.EVENT.SHOW_PRODUCT_VIEW, () => {
console.log("Product view opened");
});

HIDE_PRODUCT_VIEW

  • Web constant: player.EVENT.HIDE_PRODUCT_VIEW
  • SDK event string: "should-hide-product-view"

Fired when the product view is closed.

Payload: None


SHOW_PRODUCT_LIST

  • Web constant: player.EVENT.SHOW_PRODUCT_LIST
  • SDK event string: "should-show-product-list"

Fired when the product list should open.

Payload:

{
actionOrigin: "player",
products: [
{
id: "bambuser-generated-product-id",
ref: "product-sku-or-reference",
sku: "product-sku",
title: "Product name",
url: "https://example.com/product-page"
}
]
}

products contains every product on the show, in list order — useful for rendering your own product list when buttons.productList is set to player.BUTTON.EVENT.


HIDE_PRODUCT_LIST

  • Web constant: player.EVENT.HIDE_PRODUCT_LIST
  • SDK event string: "should-hide-product-list"

Fired when the product list is closed.

Payload: None


UPDATE_PRODUCT_HIGHLIGHT

  • Web constant: player.EVENT.UPDATE_PRODUCT_HIGHLIGHT
  • SDK event string: "should-update-product-highlight"

Fired when the current product highlight changes during a live show or recorded playback. Only product highlights are reported; the highlighted product object uses the same public product data shape the player exposes in other product events.

Payload:

{
// A single-element array when a product is highlighted,
// or [] when the highlight is cleared or is not a product
products: [
{
id: "bambuser-generated-product-id",
ref: "product-sku-or-reference",
sku: "product-sku",
title: "Product name",
url: "https://example.com/product-page"
}
]
}

Example:

player.on(player.EVENT.UPDATE_PRODUCT_HIGHLIGHT, (event) => {
const products = event.products ?? [];

if (products.length === 0) {
clearHighlightedProduct();
return;
}

const [highlightedProduct] = products;
renderHighlightedProduct(highlightedProduct);
});
note

You can also query the current highlight imperatively with player.getHighlightedProductsList().


Raw catalog feed data

note

This applies only to products that come from a product catalog (feed) imported into Bam Hub. Products added to a show manually by PDP URL have no feed entry behind them, so they never carry raw.

Where a product is backed by an imported catalog, several product-related events carry an additional raw object alongside their documented fields. It is a flat map of every column in that product's feed entry — including identifiers that have no dedicated field in the player's product model, such as item_group_id, gtin, google_product_category, and your custom labels. The keys are the feed column names exactly as they appear in your catalog, so the available fields depend on your own feed.

raw is present on:

player.on(player.EVENT.ADD_TO_CART, (addedItem, callback) => {
const groupId = addedItem.raw?.item_group_id;
// ...
});
caution

raw is omitted entirely whenever there is no feed entry behind the product — manually added products, products hydrated purely through player.updateProduct(), or a show that mixes both sources. Always guard with optional chaining and treat every field as optional; never build an integration that depends on raw being present.


Cart Events

ADD_TO_CART

  • Web constant: player.EVENT.ADD_TO_CART
  • SDK event string: "should-add-item-to-cart"

Fired when a user clicks the add-to-cart button for a product. A callback() is provided as the second argument in the event payload — you must call it within 30 seconds to let the player know if the operation was successful, otherwise the player treats the operation as failed. Learn more about handling add to cart.

Payload:

{
sku: "product-size-sku",
options: {
size: "M", // selected size name, or null
sizeIndex: 1, // index of the selected size
variation: "Red", // selected variation (color) name, or null
variationIndex: 0 // index of the selected variation
},
raw: { /* feed columns — catalog-sourced products only */ }
}
caution

This event has no quantity field — add-to-cart always adds a single unit. Use 1 in your handler, and listen for UPDATE_ITEM_IN_CART to react to quantity changes.

Example:

player.on(player.EVENT.ADD_TO_CART, (addedItem, callback) => {
yourAddToCartMethod(addedItem.sku, 1)
.then(() => callback(true))
.catch(() => callback(false));
});

UPDATE_ITEM_IN_CART

  • Web constant: player.EVENT.UPDATE_ITEM_IN_CART
  • SDK event string: "should-update-item-in-cart"

Fired when a user changes the quantity of a product in the in-player cart. A callback() is provided as the second argument in the event payload — you must call it within 30 seconds to confirm the update, otherwise the player treats the operation as failed. Learn more about handling cart updates.

Payload:

{
sku: "product-size-sku",
options: {
size: "M",
sizeIndex: 1,
variation: "Red",
variationIndex: 0
},
quantity: 2, // New quantity (0 means remove)
previousQuantity: 1, // Quantity before this change
raw: { /* feed columns — catalog-sourced products only */ }
}

Example:

player.on(player.EVENT.UPDATE_ITEM_IN_CART, (updatedItem, callback) => {
yourUpdateCartMethod(updatedItem.sku, updatedItem.quantity)
.then(() => callback(true))
.catch(() => callback(false));
});

CHECKOUT

  • Web constant: player.EVENT.CHECKOUT
  • SDK event string: "goto-checkout"

Fired when the user presses the checkout button from the player cart view. Use this to navigate the user to your checkout page.

Payload: None

Example:

player.on(player.EVENT.CHECKOUT, () => {
player.showCheckout("https://example.com/checkout");
});

SYNC_CART_STATE

  • Web constant: player.EVENT.SYNC_CART_STATE
  • SDK event string: "should-sync-cart-state"

Fired whenever the viewer navigates back to the player. The player requests an update regarding which items should be displayed in the user's in-player cart. Use player.updateCart() to sync the cart state.

Payload: None

Example:

player.on(player.EVENT.SYNC_CART_STATE, () => {
if (isOnSiteCartEmpty()) {
player.updateCart({ items: [] });
}
});

SHOW_CART

  • Web constant: player.EVENT.SHOW_CART
  • SDK event string: "should-show-cart"

Fired when the cart view is shown.

Payload:

{
actionOrigin: "player",
items: [ /* current in-player cart items */ ]
}
note

Each entry in items is the player's internal cart record (product, options, quantity). Its exact shape is not part of the stable API — read quantity and options, and correlate with your own cart rather than depending on the nested product object.


HIDE_CART

  • Web constant: player.EVENT.HIDE_CART
  • SDK event string: "should-hide-cart"

Fired when the cart view is closed.

Payload:

{
actionOrigin: "player"
}

Wishlist Events

PROVIDE_WISHLIST_STATUS

  • Web constant: player.EVENT.PROVIDE_WISHLIST_STATUS
  • SDK event string: "provide-wishlist-status"

Fired during the startup sequence of the player, after it has fetched the list of products from the backend. The player requests the wishlist status for a list of products. Learn more about Wishlist Integration.

Payload:

{
products: [
{
id: "bambuser-product-id",
ref: "product-sku-or-reference",
sku: "product-sku",
title: "Product name",
url: "https://example.com/product-page"
}
]
}

ADD_TO_WISHLIST

  • Web constant: player.EVENT.ADD_TO_WISHLIST
  • SDK event string: "add-to-wishlist"

Fired when a user clicks the add-to-wishlist button for a product. Learn more about Wishlist Integration.

Payload:

{
sku: "product-sku",
raw: { /* feed columns — catalog-sourced products only */ }
}

The player waits for a response and expects an object back:

{
success: true,
sku: "product-sku", // Optional — the SKU that was actually added
reason: undefined // When success is false: "login-required",
// "more-info-required", or your own reason string
}

Responding with login-required makes the player show its login prompt and emit OPEN_WISHLIST_LOGIN. more-info-required prompts the viewer to choose a variation or size before retrying.


REMOVE_FROM_WISHLIST

  • Web constant: player.EVENT.REMOVE_FROM_WISHLIST
  • SDK event string: "remove-from-wishlist"

Fired when a user clicks the remove-from-wishlist button for a product. Learn more about Wishlist Integration.

Payload:

{
sku: "product-sku",
raw: { /* feed columns — catalog-sourced products only */ }
}

The player expects the same { success, sku, reason } response as ADD_TO_WISHLIST.


OPEN_WISHLIST

  • Web constant: player.EVENT.OPEN_WISHLIST
  • SDK event string: "open-wishlist"

Fired when a user clicks the "View wishlist" button. Learn more about Wishlist Integration.


OPEN_WISHLIST_LOGIN

  • Web constant: player.EVENT.OPEN_WISHLIST_LOGIN
  • SDK event string: "open-wishlist-login"

Fired when a user clicks the "Login" button after attempting to add an item to the wishlist. Learn more about Wishlist Integration.


Miniplayer Events

MINIMIZE

  • Web constant: player.EVENT.MINIMIZE
  • SDK event string: "minimize"

Fired when the player is minimized to the Miniplayer.

Payload:

{
url: "https://example.com/product-page" // Page to navigate to behind the Miniplayer
}

url is present when the minimize was triggered by something that also navigates — a product click configured with player.BUTTON.MINIMIZE, or a link in the chat.


  • Web constant: player.EVENT.NAVIGATE_BEHIND_TO
  • SDK event string: "navigate-behind-to"

Fired when navigation should happen behind the player in SPA navigation mode. Handle this event to update your app's route while the Miniplayer remains visible.

Payload:

{
url: "/target-page-path"
}

Example:

player.on(player.EVENT.NAVIGATE_BEHIND_TO, (event) => {
// Navigate your SPA to the target URL
window.history.pushState({}, '', event.url);
});

NOTIFY_URL_CHANGE

  • Web constant: player.EVENT.NOTIFY_URL_CHANGE
  • SDK event string: "notify-url-change"

Fired when the Miniplayer is enabled and the player initiates a URL navigation within the iframe overlaying the current page.

Payload:

{
url: "https://example.com/target-page"
}

Playback Events

MUTED

  • Web constant: player.EVENT.MUTED
  • SDK event string: "muted"

Fired when the player is muted.

Payload: None


UNMUTED

  • Web constant: player.EVENT.UNMUTED
  • SDK event string: "unmuted"

Fired when the player is unmuted.

Payload: None


PLAYBACK_STATUS

  • Web constant: player.EVENT.PLAYBACK_STATUS
  • SDK event string: "playback-status"

Fired when the playback status changes. This event fires frequently (e.g., on play, pause, seek, mute, end).

Payload:

{
playing: boolean, // Whether the video is currently playing
suspended: boolean, // Whether playback is suspended (e.g., buffering)
muted: boolean, // Whether the player is muted
seeking: boolean, // Whether the player is currently seeking
ended: boolean, // Whether the video has ended
started: boolean, // Whether playback has started at least once
archived: boolean, // Whether the show is a recorded (archived) show
live: boolean, // Whether the show is currently live
hasAudio: boolean, // Whether the current broadcast carries an audio track
playbackRate: number, // Current playback speed (e.g., 1.0 for normal)
videoPlayerSize: {
width: number, // Video player width in pixels
height: number // Video player height in pixels
}
}

Example:

player.on(player.EVENT.PLAYBACK_STATUS, (data) => {
if (data.ended) {
console.log("Video has ended");
}
});

Closed Captions Events

CAPTIONS_SHOWN

  • Web constant: player.EVENT.CAPTIONS_SHOWN
  • SDK event string: "captions-shown"

Fired when closed captions are enabled in the player.

Payload:

{
languageCode: "en" // The caption track that was turned on
}

CAPTIONS_HIDDEN

  • Web constant: player.EVENT.CAPTIONS_HIDDEN
  • SDK event string: "captions-hidden"

Fired when closed captions are disabled in the player.

Payload: None


CAPTION_TRACK_CHANGED

  • Web constant: player.EVENT.CAPTION_TRACK_CHANGED
  • SDK event string: "caption-track-changed"

Fired when the active caption track language changes.

Payload: { languageCode: string }


Picture-in-Picture Events

ENTERED_PICTURE_IN_PICTURE

  • Web constant: player.EVENT.ENTERED_PICTURE_IN_PICTURE
  • SDK event string: "entered-picture-in-picture"

Fired when the player successfully enters Picture-in-Picture (PiP) mode after calling player.requestPictureInPicture().

Payload: None


EXITED_PICTURE_IN_PICTURE

  • Web constant: player.EVENT.EXITED_PICTURE_IN_PICTURE
  • SDK event string: "exited-picture-in-picture"

Fired when the player exits Picture-in-Picture mode, either by the user interacting with PiP controls or by calling player.exitPictureInPicture().

Payload:

{
stopPlaybackIntent: boolean
}
  • stopPlaybackIntent: true — The user likely intended to stop playback. Triggered when the player pauses within ~1.5 seconds before exiting PiP. Often correlates with tapping a native PiP "close" button, but not 100% reliable since browsers do not expose which button was tapped.
  • stopPlaybackIntent: false — The user likely intended to continue playing. Triggered when the player does not pause before exiting PiP. Often correlates with tapping a "restore" button.
note

This event also fires on programmatic exit via player.exitPictureInPicture(). In such cases, treat stopPlaybackIntent as false and do not assume a user-initiated close. To refine your logic, observe recent PLAYBACK_STATUS events around the same time.

Example:

player.on(player.EVENT.EXITED_PICTURE_IN_PICTURE, (data) => {
if (data.stopPlaybackIntent) {
player.close();
}
});

UI Events

SHOW_CHAT_OVERLAY

  • Web constant: player.EVENT.SHOW_CHAT_OVERLAY
  • SDK event string: "should-show-chat-overlay"

Fired when the chat overlay is shown.

Payload: None


HIDE_CHAT_OVERLAY

  • Web constant: player.EVENT.HIDE_CHAT_OVERLAY
  • SDK event string: "should-hide-chat-overlay"

Fired when the chat overlay is closed.

Payload: None


SHOW_SHARE

  • Web constant: player.EVENT.SHOW_SHARE
  • SDK event string: "should-show-share"

Fired when the share dialog should open.

Payload:

{
url: "https://example.com/live-shopping", // Share URL for the show
urlWithTime: "https://example.com/live-shopping?t=125", // Share URL at the current timestamp
shareFromTimestamp: false, // Whether the viewer chose "share from timestamp"
currentTimeOfShow: 125, // Current playback position, in seconds
actionOrigin: "player"
}

The share URL is derived from shareBaseUrl when configured.


SHOW_ADD_TO_CALENDAR

  • Web constant: player.EVENT.SHOW_ADD_TO_CALENDAR
  • SDK event string: "should-show-add-to-calendar"

Fired when the add-to-calendar dialog is opened.

Payload:

{
title: "Show title",
description: "Show description\n\nhttps://example.com/live-shopping",
start: "2026-09-01T18:00:00.000Z", // Scheduled start of the show
duration: 3600000, // Fixed one-hour duration, in milliseconds
url: "https://example.com/live-shopping"
}
note

duration is always one hour — the player does not know the real length of an upcoming show.


SHOW_EMOJI_BATCH

  • Web constant: player.EVENT.SHOW_EMOJI_BATCH
  • SDK event string: "should-show-emoji-batch"

Fired when an emoji batch (usually hearts) is shown.

Payload:

{
quantity: 5, // Number of emojis in the batch
text: "heart" // Emoji type in the batch
}

ACTION_CARD_CLICKED

  • Web constant: player.EVENT.ACTION_CARD_CLICKED
  • SDK event string: "action-card-clicked"

Fired when an action card is clicked.

Payload:

{
actionId: "action-card-id", // The ID of the action card
url: "https://example.com", // The URL associated with the action card
target: "current-tab" | "new-tab" // Where the URL should open
}

TOP_UI_ELEMENT_SHOWN

  • Web constant: player.EVENT.TOP_UI_ELEMENT_SHOWN
  • SDK event string: "top-ui-element-shown"

Fired when the top notification bar is shown.

Payload:

{
id: "notification-id", // Matches the id in TOP_UI_ELEMENT_HIDDEN
type: "product-added", // See the list below
titleKey: "translation.key",
textKey: "translation.key",
error: undefined, // Present for error notifications
params: {}, // Interpolation values for the translation keys
duration: 5000 // Auto-dismiss delay, in milliseconds
}

type is one of info, error, product-added, product-added-to-wishlist, product-removed-from-wishlist, wishlist-login-required, or wishlist-more-info-required.

note

titleKey and textKey are translation keys, not display strings. Resolve them against your own copy if you render the notification yourself.


TOP_UI_ELEMENT_HIDDEN

  • Web constant: player.EVENT.TOP_UI_ELEMENT_HIDDEN
  • SDK event string: "top-ui-element-hidden"

Fired when the top notification bar is hidden.

Payload:

{
id: "notification-id" // The id from the matching TOP_UI_ELEMENT_SHOWN
}

PLAYER_CONTAINER_UPDATE

  • Web constant: player.EVENT.PLAYER_CONTAINER_UPDATE
  • SDK event string: "player-container-update"

Fired when the player container is updated.

Payload: None


OPEN_URL

  • Web constant: player.EVENT.OPEN_URL
  • SDK event string: "open-url"

Fired when a user navigates to a URL from the player (e.g., clicking a product link, action card link, or share link).

Payload:

{
url: "https://example.com/product-page",
target: "_blank" | "_top" // Browser window target
}

Example:

player.on(player.EVENT.OPEN_URL, (data) => {
console.log("Opening URL:", data.url, "in target:", data.target);
});

PREVIEW_SHOULD_EXPAND

  • Web constant: player.EVENT.PREVIEW_SHOULD_EXPAND
  • SDK event string: "preview-should-expand"

Fired when an inline or embedded preview player should expand to the full player overlay. Handle this event to control the transition from a preview (e.g., a thumbnail or mini embed) to the full player experience.

Payload: None

Example:

player.on(player.EVENT.PREVIEW_SHOULD_EXPAND, () => {
console.log("Preview is requesting to expand to full player");
});

FOCUS_WEB_COMPONENT_OUTSIDE_IFRAME

  • Web constant: player.EVENT.FOCUS_WEB_COMPONENT_OUTSIDE_IFRAME
  • SDK event string: "focus-web-component-outside-iframe"

Fired when the player requests that keyboard focus be moved to a web component element outside of the player iframe. This is used for accessibility and focus management when the player is embedded as a web component.

Payload: None


Gesture Events

PLAYER_SWIPE_UP / PLAYER_SWIPE_DOWN / PLAYER_SWIPE_LEFT / PLAYER_SWIPE_RIGHT

  • Web constants: player.EVENT.PLAYER_SWIPE_UP, player.EVENT.PLAYER_SWIPE_DOWN, player.EVENT.PLAYER_SWIPE_LEFT, player.EVENT.PLAYER_SWIPE_RIGHT
  • SDK event strings: "player-swipe-up", "player-swipe-down", "player-swipe-left", "player-swipe-right"

Fired when the user makes a swipe gesture on the player.

Payload: None

Example:

player.on(player.EVENT.PLAYER_SWIPE_UP, () => {
console.log("User swiped up");
});

Chat Events

CHAT_MESSAGES

  • Web constant: player.EVENT.CHAT_MESSAGES
  • SDK event string: "chat-messages"

Fired when new chat messages are available.

Payload: Array<Object>

FieldTypeDescription
cstringClient type — "p" (player) or "m" (moderator)
nstringSender display name
mstringMessage text
rnumberRelative time in the broadcast (seconds)
pobjectPublished timestamp ({ seconds, nanoseconds })

Example:

player.on(player.EVENT.CHAT_MESSAGES, (messages) => {
messages.forEach((msg) => {
console.log(`${msg.n}: ${msg.m}`);
});
});

Methods

Methods available on the player API, organized by functionality.

Event Handling

player.on(eventName, eventHandler)

Registers an event listener for any event from the player.EVENT constants. See Event Subscription for cross-platform patterns.

Parameters:

  • eventName — An event constant from player.EVENT (e.g., player.EVENT.CLOSE).
  • eventHandler — A function to call when the event fires.
player.on(player.EVENT.CLOSE, () => {
console.log("Player was closed");
});

player.off(eventName, eventHandler)

Removes a previously registered event listener. The second parameter must be the same function reference that was passed to player.on().

// Define a named handler
const handleClose = () => {
console.log("Close event was triggered");
};

// Register the listener
player.on(player.EVENT.CLOSE, handleClose);

// Later, remove the listener
player.off(player.EVENT.CLOSE, handleClose);

player.removeAllListeners()

Removes all event listeners registered via player.on(). Use this sparingly and with caution.

// After this call, no previously registered listeners will fire
player.removeAllListeners();

Player Control

player.close()

Closes the current player and removes it from the DOM.

player.close();

player.minimize(url?)

Minimizes the player to the Miniplayer. An optional URL can be passed to navigate the page behind the Miniplayer to that URL during minimization (useful for SPA navigation flows). See also the NAVIGATE_BEHIND_TO event.

Parameters:

  • url (string, optional) — A relative or absolute URL to navigate to behind the Miniplayer when minimizing.
// Simple minimize
player.minimize();

// Minimize and navigate behind
player.minimize('/product-page');

player.unminimize()

Restores the player from the minimized state.

player.unminimize();

Playback Control

player.play()

Starts or resumes playback.

player.play();

player.pause()

Pauses playback.

player.pause();

player.mute()

Mutes the player.

player.mute();

player.unmute()

Unmutes the player.

player.unmute();

player.seekToPercent(percentage)

Seeks the video timeline to a given percentage. The PLAYBACK_STATUS event fires when playback state changes after seeking.

Parameters:

  • percentage (number) — A value between 0 and 100 representing the position to seek to.
// Seek to the halfway point
player.seekToPercent(50);

Closed Captions

player.showCaptions()

Enables closed captions in the player. Activates the first available caption track, or restores the last enabled one. On success, the player emits CAPTIONS_SHOWN.

Returns: Promise<Object> — Resolves with the result:

{ success: true, languageCode: "en-US" }
// or on failure:
{ success: false, error: "error message" }

Usage example:

await player.showCaptions();

player.hideCaptions()

Disables all caption tracks. On success, the player emits CAPTIONS_HIDDEN.

Returns: Promise<Object> — Resolves with the result:

{ success: true }

Usage example:

await player.hideCaptions();

player.selectCaptionTrack(languageCode)

Selects a specific caption track by language code. If captions are not yet enabled, this also enables them.

Parameters:

  • languageCode (string, required) — The language code of the caption track to select (e.g., "en-US", "es-ES", "fr-FR"). Throws an error if missing or not a string.

Returns: Promise<Object> — Resolves with the result:

{ success: true, languageCode: "es-ES" }
// or on failure:
{ success: false, error: "error message" }

Usage example:

await player.selectCaptionTrack("es-ES");

player.getAvailableCaptions()

Returns the list of available caption tracks and the current captions state.

Returns: Promise<Object> — Resolves with:

{
availableCaptions: ["en-US", "es-ES", "fr-FR"], // Available language codes
currentTrack: "en-US", // Currently active track, or null if none
isEnabled: true // Whether captions are currently enabled
}

Usage example:

const captions = await player.getAvailableCaptions();
if (captions.availableCaptions.length > 0 && !captions.isEnabled) {
await player.showCaptions();
}
note

On mobile the result is wrapped in an event object: { "event": { "availableCaptions": ["sv-SE", "en-US"] } }. Full examples: iOS, Android, React Native.


player.enableHighContrast()

Forces high-contrast styling on the player for improved accessibility. When enabled, closed captions are rendered with solid backgrounds and a visible border. This is intended for WebView hosts that detect the OS-level prefers-contrast: more setting themselves and need to propagate it into the player.

Usage example:

player.enableHighContrast();

player.disableHighContrast()

Disables forced high-contrast styling previously set via player.enableHighContrast(). The OS-level prefers-contrast: more media query continues to apply on its own.

Usage example:

player.disableHighContrast();

Picture-in-Picture

player.requestPictureInPicture()

Requests the browser to enter Picture-in-Picture (PiP) mode for the underlying video element.

Returns: Promise — Resolves when the player enters PiP mode.

note

Most browsers require this to be called in direct response to a user gesture (e.g., click/tap). On success, the player emits ENTERED_PICTURE_IN_PICTURE.

Usage example:

// Enter PiP when a product is opened
player.on(player.EVENT.SHOW_PRODUCT_VIEW, () => {
player.requestPictureInPicture();
});

player.exitPictureInPicture()

Exits Picture-in-Picture while keeping the web player instance active in the DOM. Triggers EXITED_PICTURE_IN_PICTURE.

Returns: Promise — Resolves when the player exits PiP mode.

To fully close the player after exiting PiP, call player.close() separately.

Usage example:

player.exitPictureInPicture();

UI Control

player.hideUI()

Hides all of the player's UI chrome while keeping video playback visible. Useful when embedding in Android PiP or other WebView-driven scenarios where your app draws its own controls. Reverse it with player.showUI().

// Hide the player UI
player.hideUI();

// Bring it back
player.showUI();
note

hideUI() is all-or-nothing. To hide individual elements, use configuration.ui at configuration time instead — for example ui: { hideCartButton: true, hideShareButton: true } hides just those controls, and ui: { hideAll: true } is the declarative equivalent of hideUI().


player.showUI()

Shows the player's UI chrome after it has been hidden via player.hideUI().

player.showUI();

player.setRootFontSize(fontSize)

Sets the root font size of the player UI for scaling text, which can be useful for accessibility purposes. The change is applied dynamically.

Parameters:

  • fontSize (number | string) — The desired font size. A number is interpreted as pixels. A string must use px units (e.g., '16px').

Usage example:

// Set the root font size to 20 pixels
player.setRootFontSize(20);

// Or use a string value
player.setRootFontSize('32px');

player.patchTheme(themeOverrides)

Applies runtime theme overrides to the player. Partial updates accumulate via deep merge, so you only need to pass the fields you want to change — previously applied overrides are preserved. Safe to call before the player is ready; the accumulated state is applied once it loads.

Throws an error if the argument is not a plain object. Unknown keys are silently ignored.

Parameters:

  • themeOverrides (object, required) — A plain object containing the theme properties to override. Currently supported properties:
PathTypeDefaultDescription
playerSettings.closedCaptions.foregroundColorString (CSS color)rgba(0, 0, 0, 1)Text color of closed captions
playerSettings.closedCaptions.backgroundColorString (CSS color)rgba(255, 255, 255, 0.9)Background color of closed captions

Usage example:

// Override closed caption colors
player.patchTheme({
playerSettings: {
closedCaptions: {
foregroundColor: 'rgba(255, 255, 255, 1)',
backgroundColor: 'rgba(0, 0, 0, 0.7)',
},
},
});

// Later: update just one field. Previous overrides are preserved.
player.patchTheme({
playerSettings: {
closedCaptions: {
backgroundColor: 'rgba(255, 0, 0, 0.5)',
},
},
});

player.updateSafeAreaInsets(insets)

Dynamically updates the safe area insets while the player is active. Complements the overrideSafeAreaInsets configuration.

Parameters:

  • insets (object) — { top?: number, right?: number, bottom?: number, left?: number } in pixels.

Usage example:

// Increase bottom spacing when a transient control overlaps the timeline
player.updateSafeAreaInsets({ bottom: 100 });

player.showProductList()

Programmatically opens the product list inside the player. Triggers the SHOW_PRODUCT_LIST event.

player.showProductList();

player.hideProductList()

Programmatically closes the product list inside the player. Triggers the HIDE_PRODUCT_LIST event.

player.hideProductList();

player.getHighlightedProductsList()

Returns a Promise that resolves with the list of currently highlighted products. Related event: UPDATE_PRODUCT_HIGHLIGHT.

Returns: Promise<Array> — The list of highlighted products.

const products = await player.getHighlightedProductsList();
console.log("Highlighted products:", products);

player.getEventInfoState()

Returns a Promise that resolves with the current event/show info state, including details about the show such as its status, title, and scheduled time. Related event: UPDATE_SHOW_STATUS.

Returns: Promise<Object> — The event info state.

const eventInfo = await player.getEventInfoState();
console.log("Event info:", eventInfo);

Product Management

player.updateProduct(productId, productFactory)

Updates all necessary product details that allow the player to properly display a product. This method uses a chainable builder pattern.

Parameters:

ArgumentTypeDescription
productIdstringThe Bambuser-generated ID for each product, found in the PROVIDE_PRODUCT_DATA event payload (event.products[].id).
productFactoryfunctionCallback that receives a product factory and returns a finished product via chaining.
Builder Pattern API Reference

The productFactory uses a chainable builder pattern with multiple levels. Each level provides methods for constructing that part of the product data.

productFactory (top level)

MethodArgument typeRequiredDescription
.product(fn)functionYesTakes a function receiving productDetailFactory, returns product details
.inheritFromPlaceholder()NoInherits scraped/workspace product data as base (see Inherit from scraped product)
.publicUrl(url)stringNoOverrides the product's PDP URL (see Override products URL)
.hidden(bool)booleanNoHides the product from the viewer (see Hide a product)

productDetailFactory

MethodArgument typeRequiredDescription
.name(name)stringYesProduct display name
.sku(sku)stringYesProduct identifier (should match your workspace product reference)
.brandName(name)stringNoBrand name
.introduction(text)stringNoShort introductory text
.description(html)stringNoProduct description (supports HTML)
.defaultVariationIndex(n)numberNoIndex of the default variation to display
.variations(fn)functionYesTakes function receiving variationFactory, returns array of variations

variationFactory()

MethodArgument typeRequiredDescription
.name(name)stringYesVariation name (shown if colorName is not set)
.sku(sku)stringYesVariation-level SKU
.imageUrls(urls)string[]YesArray of image URLs, ordered as you want them displayed
.attributes(fn)functionNoTakes a function with .colorName(string), .colorHexCode(string) and .colorImage(url). colorName defaults to the variation's .name().
.sizes(fn)functionYesTakes function receiving sizeFactory, returns array of sizes

sizeFactory()

MethodArgument typeRequiredDescription
.name(name)stringYesSize display name (used in dropdowns)
.sku(sku)stringYesSize-level SKU (used for add-to-cart)
.inStock(bool)booleanNoWhether this variation/size is in stock. Defaults to true.
.capacity(obj)objectNoCapacity metadata, { value, unit } (see Product capacity)
.price(fn)functionYesTakes function with pricing chain methods

priceFactory

MethodArgument typeRequiredDescription
.currency(code)stringNoOverrides the default currency
.current(amount)numberYesCurrent price
.original(amount)numberNoOriginal price (used to show sale pricing)
.discountPercentage(n)numberNoDiscount percentage to show on the badge (see Discount percentage)
.perUnit(amount)numberNoPer-unit price (e.g., $77 / 100ml)
.unitAmount(n)numberNoUnit amount
.unitDisplayName(name)stringNoUnit display name (e.g., "ml", "st")
Product capacity

Each size may carry optional capacity metadata describing how much product it contains — useful for beauty, food, and beverage catalogs where the size name is not the volume.

.sizes((s) => [
s()
.name('50 ml')
.sku('SKU-50')
.capacity({ value: 50, unit: 'ml' })
.price((pr) => pr.current(29)),
])

The same object can be set on a size passed to player.updateProductWithData().

  • value — a positive, finite number or numeric string.
  • unit — a non-empty string.

Invalid or incomplete capacity is ignored. The player formats the number using the player locale and renders your unit exactly as provided — no conversion, translation, pluralization, or inference — following the number-unit spacing convention (50 ml).

note

Capacity is independent of the per-unit pricing fields (perUnit, unitAmount, unitDisplayName). Set both if you want to show a volume and a price per unit.

Discount percentage

When discount badges are enabled for your workspace theme, the player can show a percentage badge on product prices. You can supply the value yourself:

.price((pr) =>
pr
.currency('USD')
.current(75)
.original(100)
.discountPercentage(25)
)
  • Accepts a finite, nonzero number between -100 and 100. The sign is ignored, so -25 and 25 render the same badge.
  • A badge is only shown when original is greater than current and both are positive.
  • An invalid value logs a warning and is discarded.
  • If your theme is configured to calculate missing discounts, the player derives the percentage from original and current whenever you do not supply one (rounded down, capped at 99).
note

Badge visibility and the calculate-when-missing behavior are controlled by your theme settings in Bam Hub. Supplying discountPercentage alone does not enable the badge.

Update product details

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
.product((productDetailFactory) =>
productDetailFactory
.name(yourProduct.name)
.brandName(yourProduct.brand)
.introduction(yourProduct.shortDescription)
.description(yourProduct.description)
.sku(yourProduct.productId)
.defaultVariationIndex(0)
.variations((variationFactory) =>
yourProduct.colors.map((variation) =>
variationFactory()
.attributes((attributeFactory) =>
attributeFactory
.colorName(variation.colorName)
.colorHexCode(variation.colorHexCode)
)
.imageUrls(variation.images)
.name(variation.name)
.sku(variation.variationId)
.sizes((sizeFactory) =>
variation.sizes.map((size) =>
sizeFactory()
.name(size.name)
.inStock(size.quantityInStock > 0)
.sku(size.sizeId)
.price((priceFactory) =>
priceFactory
.currency(size.currency)
.current(size.current)
.original(size.original)
.perUnit(size.perUnit)
.unitAmount(size.unitAmount)
.unitDisplayName(size.unitDisplayName),
)
)
)
)
)
)
);
});
});

Inherit from scraped product

By default, when you hydrate a product using the updateProduct() method, it creates a new empty product — requiring you to provide all details since the previously scraped (or manually inserted) product information from the workspace gets overridden.

Bambuser offers an option to inherit product information from the scraped product (e.g., name, brand) as a base, so you only need to override the fields that differ.

Chain inheritFromPlaceholder() to productFactory:

player.on(player.EVENT.PROVIDE_PRODUCT_DATA, (event) =>
event.products.forEach(({ ref: sku, id: productId }) => {
yourGetProductDataMethod(sku).then((currentProduct) =>
player.updateProduct(productId, (productFactory) =>
productFactory
.inheritFromPlaceholder()
.product((detailsFactory) =>
detailsFactory
.name(currentProduct.title)
.sku(currentProduct.id)
.brandName(currentProduct.brand)
.variations((variationFactory) =>
// ... build variations
)
)
)
);
})
);

Using inheritFromPlaceholder() also unlocks additional methods such as overriding product URLs and hiding products.


Override products URL

If you use different domains across different markets, you may need to update product details with market-specific PDP URLs. Override the PDP URL by passing the current market's URL to publicUrl() for each product.

player.on(player.EVENT.PROVIDE_PRODUCT_DATA, (event) =>
event.products.forEach(({ ref: sku, id: productId }) => {
yourMethodThatGetsLocalizedProductData(sku).then((currentProduct) =>
player.updateProduct(productId, (productFactory) =>
productFactory
.inheritFromPlaceholder()
.publicUrl(currentProduct.url)
)
);
})
);

Hide a product

You can hide a product from the viewer through the Player API.

player.on(player.EVENT.PROVIDE_PRODUCT_DATA, (event) => {
event.products.forEach(({ ref: sku, id: productId }) => {
getLocalizedProductBySku(sku).then((currentProduct) =>
player.updateProduct(productId, (productFactory) => {
return productFactory
.inheritFromPlaceholder()
.hidden(!currentProduct.isAvailable);
})
);
});
});
Additional example: Hide product if not available
player.on(player.EVENT.PROVIDE_PRODUCT_DATA, (event) => {
event.products.forEach(({ ref: sku, id, url }) => {
yourGetProductMethod(sku).then((item) => {
if (!item.available) {
// Product is unavailable — hide it
player.updateProduct(id, (productFactory) => {
return productFactory
.inheritFromPlaceholder()
.hidden(true);
});
} else {
// Product is available — hydrate as usual
player.updateProduct(id, (productFactory) =>
productFactory.product((detailsFactory) =>
detailsFactory
.name(item.title)
.sku(item.id)
.brandName(item.brand)
.variations((variationFactory) =>
// ... build variations
)
)
);
}
});
});
});

player.updateProductWithData(productId, productData)

An alternative to updateProduct() that accepts a plain data object instead of using the builder/factory pattern. This is the same method used internally by the Swift and Kotlin SDKs (invoke("updateProductWithData", ...)), but is also available directly on the Web player API.

Parameters:

ArgumentTypeDescription
productIdstringThe Bambuser-generated ID from the PROVIDE_PRODUCT_DATA event payload.
productDataobjectA plain JSON-serializable object containing product details.

Product data structure:

{
sku: "product-sku",
name: "Product Name",
brandName: "Brand",
introduction: "Short description",
description: "<p>HTML description</p>",
defaultVariationIndex: 0,
variations: [
{
sku: "variation-sku",
name: "Variation Name",
colorName: "black",
colorHexCode: "#000000",
imageUrls: ["https://example.com/image.png"],
sizes: [
{
sku: "size-sku",
name: "Small",
inStock: true, // or a number (truthy = in stock)
capacity: { value: 50, unit: "ml" }, // optional, see Product capacity
currency: "USD",
current: 100,
original: 120,
discountPercentage: 25, // optional, see Discount percentage
perUnit: 50,
unitAmount: 1,
unitDisplayName: "piece"
}
]
}
]
}

Example:

player.on(player.EVENT.PROVIDE_PRODUCT_DATA, (event) => {
event.products.forEach(async ({ ref: sku, id: bambuserId }) => {
const product = await yourGetProductMethod(sku);
player.updateProductWithData(bambuserId, {
sku: product.sku,
name: product.name,
brandName: product.brand,
variations: product.variations, // Make sure this matches the expected structure
});
});
});

player.updateWishlistStatus(data)

Updates the wishlist status for products in the player. Call this in response to the PROVIDE_WISHLIST_STATUS event to inform the player which products are already in the user's wishlist. Learn more about Wishlist Integration.

Parameters:

  • data (object, required) — An object with the following structure:
{
statuses: {
[productRef: string]: boolean // key = product ref (SKU), value = true if in wishlist
}
}

Both data and data.statuses must be plain objects. Throws an error if either is not.

Example:

player.on(player.EVENT.PROVIDE_WISHLIST_STATUS, (event) => {
const statuses = {};
if (event.products) {
event.products.forEach(({ ref }) => {
statuses[ref] = isInWishlist(ref);
});
}
player.updateWishlistStatus({ statuses });
});

Cart Control

player.updateCart(cartData)

Updates the player cart state.

Parameters:

  • cartData (object, required) — An object containing:
    • items (Array, required) — An array of cart items. Currently only an empty array ([]) is supported for clearing the cart.
note

Currently, updateCart only supports emptying the cart by passing { items: [] }. This is useful when the shopper completes checkout or empties the cart and returns to the player.

Usage example:

player.on(player.EVENT.SYNC_CART_STATE, () => {
if (isOnSiteCartEmpty()) {
player.updateCart({ items: [] });
}
});

player.showCheckout(checkoutPageUrl)

Navigates to a checkout page (or any other page) when invoked. This method uses the checkout button configuration to determine how to navigate:

  • checkout: player.BUTTON.MINIMIZE — Minimizes the player and opens the link in the same window
  • checkout: player.BUTTON.LINK — Opens the link in a new tab

If no configuration is provided, it opens the URL in a new tab.

Parameters:

  • checkoutPageUrl (string, required) — An absolute URL including protocol (http:// or https://). Throws an error if the URL is missing, not a string, or lacks a protocol.

Usage example:

player.on(player.EVENT.CHECKOUT, () => {
player.showCheckout("https://example.com/checkout");
});

callback()

A callback function provided exclusively in the payload of the ADD_TO_CART and UPDATE_ITEM_IN_CART events as the second argument to the event handler. You must call this function to let the player know whether the cart operation succeeded or failed, so the player can display the appropriate message to the viewer.

Accepted inputs:

InputPlayer message
callback(true)"Added to cart!"
callback(false)"Problem adding product to basket, please try again!"
callback({ success: false, reason: 'out-of-stock' })"The selected size has been sold out!"
callback({ success: false, reason: 'custom-error', message: 'your message' })Your custom message
warning

The callback must be invoked within 30 seconds of the event being fired. If it is not called within this window, the player treats the operation as failed and shows an error message to the viewer.

tip

The default callback messages (e.g., "Added to cart!", "The selected size has been sold out!") are automatically localized based on the player's configured language. You can customize these messages through Translations in the Bambuser dashboard.

Examples:

Cart operation succeeded
player.on(player.EVENT.ADD_TO_CART, (addedItem, callback) => {
yourAddToCartMethod(addedItem.sku, 1)
.then(() => callback(true));
});
Cart operation failed
player.on(player.EVENT.ADD_TO_CART, (addedItem, callback) => {
yourAddToCartMethod(addedItem.sku, 1)
.then(() => callback(true))
.catch(() => callback(false));
});
Out of Stock Error
callback({
success: false,
reason: 'out-of-stock',
});
Custom Cart Error
callback({
success: false,
reason: 'custom-error',
message: 'This is my custom error message',
});

For a visual overview of the callback flow, see Cart Integration — callback flow diagram.


Data & Tracking

setTrackingTags(trackingTags)

Sends a list of custom tracking tags once at the beginning of the session. The tags are sent via the on-configuration event and are not attached to all tracking events. Instead, Bambuser's backend aggregation system stitches them together with the session data.

Learn more about Custom Tracking Tags.

Parameters:

  • trackingTags (Array, required) — An array of tag objects. Each tag must have:
    • key (string, required) — The tag identifier. Must be a non-empty string.
    • value (string | number | boolean, required) — The tag value. String values are limited to 1 KB in size.
note

A maximum of 20 tags can be sent. If more are provided, only the first 20 are used. Duplicate keys are deduplicated (last value wins).

Usage example:

player.setTrackingTags([
{ key: 'customerId', value: '123-abc' },
{ key: 'membership', value: 'premium' },
]);

Constants

A list of available constants to be used throughout the player integration. For Web/JavaScript, use the constant references (e.g., player.BUTTON.CLOSE). For Swift and Kotlin, use the equivalent string values (e.g., "close").

player.BUTTON

Used to dictate the functionality of certain buttons inside the player. See configuration.buttons for usage.

Web SDK Behavior
player.BUTTON.AUTO"auto"The default behavior (actual behavior depends on context).
player.BUTTON.CLOSE"close"Close the player overlay.
player.BUTTON.INLINE"inline"Opens the target inline within the player (e.g., product view or action card).
player.BUTTON.LINK"link" The button behaves like a link — opens the product URL or checkout URL in a new browser tab.
player.BUTTON.MINIMIZE"minimize" Minimize the player.
player.BUTTON.NONE"none"Does nothing. The button may be hidden depending on the context.
player.BUTTON.EVENT"event"Triggers an event that can be handled by your custom event handler.

Usage example:

player.configure({
buttons: {
checkout: player.BUTTON.MINIMIZE,
},
});

player.EVENT

Complete reference table of all player events. Each event name links to its detailed documentation above.

Web Constant SDK Event String Trigger
player.EVENT.LOAD"load"Player app loaded
player.EVENT.READY"ready"Player GUI ready
player.EVENT.CLOSE"close"Player closed
player.EVENT.LOAD_ERROR"load-error"Failed to load show
player.EVENT.UPDATE_SHOW_STATUS"should-update-show-status"Show status changed
player.EVENT.PROVIDE_PRODUCT_DATA"provide-product-data"Product data requested
player.EVENT.SHOW_PRODUCT_VIEW"should-show-product-view"Product clicked
player.EVENT.HIDE_PRODUCT_VIEW"should-hide-product-view"Product view closed
player.EVENT.SHOW_PRODUCT_LIST"should-show-product-list"Product list opened
player.EVENT.HIDE_PRODUCT_LIST"should-hide-product-list"Product list closed
player.EVENT.UPDATE_PRODUCT_HIGHLIGHT"should-update-product-highlight"Highlighted product updated
player.EVENT.ADD_TO_CART"should-add-item-to-cart"Add to cart clicked
player.EVENT.UPDATE_ITEM_IN_CART"should-update-item-in-cart"Cart item quantity changed
player.EVENT.CHECKOUT"goto-checkout"Checkout button pressed
player.EVENT.SYNC_CART_STATE"should-sync-cart-state"Cart sync requested
player.EVENT.SHOW_CART"should-show-cart"Cart view shown
player.EVENT.HIDE_CART"should-hide-cart"Cart view closed
player.EVENT.PROVIDE_WISHLIST_STATUS"provide-wishlist-status"Wishlist status requested
player.EVENT.ADD_TO_WISHLIST"add-to-wishlist"Add to wishlist clicked
player.EVENT.REMOVE_FROM_WISHLIST"remove-from-wishlist"Remove from wishlist clicked
player.EVENT.OPEN_WISHLIST"open-wishlist"View wishlist clicked
player.EVENT.OPEN_WISHLIST_LOGIN"open-wishlist-login"Wishlist login clicked
player.EVENT.MINIMIZE"minimize"Player minimized
player.EVENT.NAVIGATE_BEHIND_TO"navigate-behind-to"SPA navigation requested
player.EVENT.NOTIFY_URL_CHANGE"notify-url-change"URL changed in iframe
player.EVENT.MUTED"muted"Player muted
player.EVENT.UNMUTED"unmuted"Player unmuted
player.EVENT.PLAYBACK_STATUS"playback-status"Playback status changed
player.EVENT.CAPTIONS_SHOWN"captions-shown"Captions enabled
player.EVENT.CAPTIONS_HIDDEN"captions-hidden"Captions disabled
player.EVENT.CAPTION_TRACK_CHANGED"caption-track-changed"Caption track changed
player.EVENT.ENTERED_PICTURE_IN_PICTURE"entered-picture-in-picture"Entered PiP mode
player.EVENT.EXITED_PICTURE_IN_PICTURE"exited-picture-in-picture"Exited PiP mode
player.EVENT.SHOW_CHAT_OVERLAY"should-show-chat-overlay"Chat overlay shown
player.EVENT.HIDE_CHAT_OVERLAY"should-hide-chat-overlay"Chat overlay closed
player.EVENT.SHOW_SHARE"should-show-share"Share dialog opened
player.EVENT.SHOW_ADD_TO_CALENDAR"should-show-add-to-calendar"Add to calendar opened
player.EVENT.SHOW_EMOJI_BATCH"should-show-emoji-batch"Emoji batch shown
player.EVENT.ACTION_CARD_CLICKED"action-card-clicked"Action card clicked
player.EVENT.TOP_UI_ELEMENT_SHOWN"top-ui-element-shown"Top notification shown
player.EVENT.TOP_UI_ELEMENT_HIDDEN"top-ui-element-hidden"Top notification hidden
player.EVENT.PLAYER_CONTAINER_UPDATE"player-container-update"Player container updated
player.EVENT.OPEN_URL"open-url"URL opened from player
player.EVENT.PREVIEW_SHOULD_EXPAND"preview-should-expand"Preview requests expansion
player.EVENT.FOCUS_WEB_COMPONENT_OUTSIDE_IFRAME"focus-web-component-outside-iframe"Focus requested outside iframe
player.EVENT.CHAT_MESSAGES"chat-messages"New chat messages
player.EVENT.PLAYER_SWIPE_UP"player-swipe-up"Swipe up gesture
player.EVENT.PLAYER_SWIPE_DOWN"player-swipe-down"Swipe down gesture
player.EVENT.PLAYER_SWIPE_LEFT"player-swipe-left"Swipe left gesture
player.EVENT.PLAYER_SWIPE_RIGHT"player-swipe-right"Swipe right gesture

player.MINIMIZED_POSITION

Contains the available initial positions of the Miniplayer. The default position is bottom right.

Web SDK
player.MINIMIZED_POSITION.BOTTOM_RIGHT"bottom-right"
player.MINIMIZED_POSITION.BOTTOM_LEFT"bottom-left"
player.MINIMIZED_POSITION.TOP_LEFT"top-left"
player.MINIMIZED_POSITION.TOP_RIGHT"top-right"

Usage example:

player.configure({
minimizedPosition: player.MINIMIZED_POSITION.BOTTOM_RIGHT,
});

player.MINIPLAYER_SIZE

Contains the available sizes for the Miniplayer. The default size is small.

Web SDK
player.MINIPLAYER_SIZE.SMALL"small"
player.MINIPLAYER_SIZE.LARGE"large"

Usage example:

player.configure({
miniplayerSize: player.MINIPLAYER_SIZE.SMALL,
});

player.FLOATING_PLAYER_NAVIGATION_MODE

Contains the available navigation modes for the floating player. See configuration.floatingPlayer for usage.

  • player.FLOATING_PLAYER_NAVIGATION_MODE.IFRAME — Navigation happens in an iframe layered behind the floating player (default).
  • player.FLOATING_PLAYER_NAVIGATION_MODE.MANUAL — Only the floating player is shown; navigation is handled by your app. Best for SPAs.

Usage example:

player.configure({
floatingPlayer: {
navigationMode: player.FLOATING_PLAYER_NAVIGATION_MODE.MANUAL,
},
});