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
- Web
- Swift
- Kotlin
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.
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
Once you set up BambuserCommerceSDK in SPM, you can initialize the SDK with environment and create a player view instance.
// Import the SDK
import BambuserCommerceSDK
// Initialize the Bambuser video player with the server region
// You can choose between .US or .EU based on your region
let videoPlayer = BambuserVideoPlayer(server: .US) // or .EU
// Create the player view with video configuration
let playerView = videoPlayer.createPlayerView(
videoConfiguration: .init(
type: .live(id: "YOUR_SHOW_ID"),
// List of events to listen to; use ["*"] for all events
events: ["*"],
// Configuration settings for the player
// Pass configuration based on requirement. It can be [String: Any]
configuration: ["key": "value"]
)
)
playerView.delegate = self
How it works
First, add a new maven repository to your dependency resolution management, and then add the dependency into your app/build.gradle:
repositories {
google()
mavenCentral()
// Add the Bambuser Commerce SDK repository
maven {
url "https://repo.repsy.io/mvn/bambuser/bambuser-commerce-sdk"
}
}
// In gradle
implementation("com.bambuser:commerce-sdk:$insert the latest version")
You need to initialize the SDK before using it. In your Application class, add the following code, and then use the composable function GetLiveView. This function requires two mandatory parameters:
videoConfiguration— The configuration for the video player.videoPlayerDelegate— The delegate to receive events and errors.
// Initialize the SDK with your organization's server region
// Use OrganizationServer.US or OrganizationServer.EU based on your region
globalBambuserSDK = BambuserSDK(
applicationContext = this,
organizationServer = OrganizationServer.US,
)
// For EU region:
euBambuserSDK = BambuserSDK(
applicationContext = this,
organizationServer = OrganizationServer.EU,
)
Create a live view from either of the SDK references:
application.globalBambuserSDK.GetLiveView(
modifier = Modifier.padding(innerPadding),
// This is the configuration for the video player
videoConfiguration = BambuserVideoConfiguration(
// Pass list of events you want to receive
// Or "*" to receive all events
events = listOf("*"),
// Pass the configuration for the video player
configuration = mapOf(
"buttons" to mapOf("dismiss" to "none"),
"currency" to "USD", // Mandatory for product hydration
"autoplay" to false,
),
// Pass the asset you want to play
videoType = BambuserVideoAsset.Live(id),
)
)
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)
- Web
- Swift
- Kotlin
player.configure({
currency: "USD",
locale: "en-US",
buttons: {
dismiss: player.BUTTON.MINIMIZE,
checkout: player.BUTTON.MINIMIZE,
},
});
configuration: [
"buttons": [
"dismiss": "none",
"checkout": "minimize",
],
"currency": "USD",
"locale": "en-US"
]
configuration = mapOf(
"buttons" to mapOf(
"dismiss" to "none",
"checkout" to "minimize",
),
"currency" to "USD",
"locale" to "en-US"
)
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.
Translation updates may take up to 30 minutes to reflect due to caching.
Usage example:
- Web
- Swift
- Kotlin
player.configure({
locale: "en-US",
});
Dynamic locale example:
const userLocale = yourMethodToGetUserLocale(); // e.g., "sv-SE" for Swedish
player.configure({
locale: userLocale,
});
configuration: ["locale": "en-US"]
configuration = mapOf("locale" to "en-US")
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:
- Web
- Swift
- Kotlin
player.configure({
currency: "USD",
});
configuration: ["currency": "USD"]
configuration = mapOf("currency" to "USD")
configuration.autoplay
- Value type:
boolean - Default:
true
Controls whether the video automatically plays when the player is presented.
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:
- Web
- Swift
- Kotlin
player.configure({
autoplay: false, // Video will not play automatically when player is presented
});
configuration: ["autoplay": false]
configuration = mapOf("autoplay" to false)
configuration.externalTitle and configuration.innerTitle
- Value type:
string - Default:
externalTitle="Bambuser Live Shopping Player",innerTitle= value ofexternalTitle
Define accessibility titles for the player:
externalTitlesets the iframetitleattribute outside the player.innerTitlesets the player pagedocument.titleinside the iframe.
innerTitle is escaped and capped at 200 characters. externalTitle is used verbatim, so keep it short yourself.
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.
| Button | Description | Available Behaviors | Default Behavior |
|---|---|---|---|
dismiss | The button in the upper right corner of the player | CLOSE, MINIMIZE, NONE, EVENT | AUTO |
checkout | The checkout button | LINK, MINIMIZE, EVENT | AUTO |
product | Click on a product reference, in the highlight or the product list | LINK, MINIMIZE, INLINE, NONE, EVENT | AUTO |
minimize | The minimize button in the player | EVENT | AUTO |
actionCard | Click on an action card | LINK, INLINE, NONE, EVENT | AUTO |
productList | The product list (and cart) button | EVENT | AUTO |
addToCart | The add-to-cart button on products and the product highlight | EVENT | AUTO |
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.
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:
- Web
- Swift
- Kotlin
player.configure({
audioTrackLocale: "de-DE", // Sets German dubbed audio as the default
});
configuration: ["audioTrackLocale": "de-DE"]
configuration = mapOf("audioTrackLocale" to "de-DE")
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)instapaperlineliveJournalmailRuodnoklassnikipocketreddittelegramtumblrvibervkwechatweiboworkplace
Usage example:
player.configure({
shareTargets: ['reddit', 'telegram'],
});
configuration.minimizedPosition
- Value type:
stringor 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:
- Web
- Swift
- Kotlin
player.configure({
checkoutOnCartClick: true,
});
configuration: ["checkoutOnCartClick": true]
configuration = mapOf("checkoutOnCartClick" to 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:
- Web
- Swift
- Kotlin
player.configure({
shareBaseUrl: 'https://example.com/live-shopping?referer=joe',
});
configuration: [
"shareBaseUrl": "https://example.com/live-shopping?referer=joe"
]
configuration = mapOf(
"shareBaseUrl" to "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:
- Web
- Swift
- Kotlin
player.configure({
trackingTags: [{ key: 'memberId', value: '123-abc' }],
});
configuration: [
"trackingTags": [
["memberId": "123-abc"]
]
]
configuration = mapOf(
"trackingTags" to listOf(
mapOf("key" to "memberId", "value" to "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:
- Web
- Swift
- Kotlin
player.configure({
allowShareAutoplay: false,
});
configuration: ["allowShareAutoplay": false]
configuration = mapOf("allowShareAutoplay" to 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.
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_shidand_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:
- Web
- Swift
- Kotlin
player.configure({
trimPriceTrailingZeros: true,
});
configuration: ["trimPriceTrailingZeros": true]
configuration = mapOf("trimPriceTrailingZeros" to true)
configuration.deeplink
- 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.
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:
- Web
- Swift
- Kotlin
player.configure({
deeplink: "f00ba5@100",
});
// Alternative: pass deeplink at initialization
window.initBambuserLiveShopping({
showId: 'YOUR_SHOW_ID',
deeplink: "f00ba5@100",
});
configuration: ["deeplink": "f00ba5@100"]
configuration = mapOf("deeplink" to "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 oncehideActionBarhideAddToCalendarhideAddToCalendarButton— Hides only the button that opens the add-to-calendar dialoghideCartButtonhideCartViewhideChatOverlayhideClosedCaptionsButton— Hides the closed captions (subtitles) buttonhideEmojiOverlayhidePlaybackRateButton— Hides the playback speed control buttonhideProductListhideProductViewhidePromotedShows— Hides promoted shows shown at the end of a videohideShareButtonhideShareFromTimestampButton— Hides the share-from-timestamp buttonhideShareViewhideVolumeButton— Hides the volume control buttonhideWishlistshowShareButtonInMobileActionBar— Shows the share button in the mobile action bar (defaultfalse)
Use hideAll: true to hide every UI element in one go.
Usage example:
- Web
- Swift
- Kotlin
// Hide all UI elements
player.configure({
ui: {
hideAll: true,
},
});
// Or hide individual elements
player.configure({
ui: {
hideAddToCalendar: true,
hideShareView: true,
},
});
configuration: [
"ui": [
"hideAddToCalendar": true,
"hideShareView": true
]
]
configuration = mapOf(
"ui" to mapOf(
"hideAddToCalendar" to true,
"hideShareView" to 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:
- Web
- Swift
- Kotlin
player.configure({
startMuted: true,
});
configuration: ["startMuted": true]
configuration = mapOf("startMuted" to 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:
- Web
- Swift
- Kotlin
player.configure({
disableChatInput: true,
});
configuration: ["disableChatInput": true]
configuration = mapOf("disableChatInput" to 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:
stringor 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. Useplayer.FLOATING_PLAYER_NAVIGATION_MODEconstants. 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:
- Web
- Swift
- Kotlin
player.configure({
themeId: "your-theme-id",
});
configuration: ["themeId": "your-theme-id"]
configuration = mapOf("themeId" to "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:
- Web
- Swift
- Kotlin
player.configure({
playerOrientation: "landscape",
});
configuration: ["playerOrientation": "landscape"]
configuration = mapOf("playerOrientation" to "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.
Only relevant when the Miniplayer is enabled via buttons.dismiss: player.BUTTON.MINIMIZE. Otherwise the button is always a close button.
Usage example:
- Web
- Swift
- Kotlin
player.configure({
allowMinimizeOnCurtains: false,
});
configuration: ["allowMinimizeOnCurtains": false]
configuration = mapOf("allowMinimizeOnCurtains" to 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:
- Web
- Swift
- Kotlin
player.configure({
disableTouchMoveScrollPrevention: true,
});
configuration: ["disableTouchMoveScrollPrevention": true]
configuration = mapOf("disableTouchMoveScrollPrevention" to 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.
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 totrue.sandboxAttributes(string) — Applies the provided value as-is to the player and surf iframes'sandboxattribute.credentiallessIframes(boolean) — Adds thecredentiallessattribute 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
- Web
- Swift
- Kotlin
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();
Specify which events to receive in the events array of BambuserVideoConfiguration. Use ["*"] to receive all events, or specify individual event strings.
BambuserVideoConfiguration(
type: .live(id: "YOUR_SHOW_ID"),
events: ["*"], // or ["ready", "goto-checkout"]
configuration: [/* player configs */]
)
Handle events in the BambuserVideoPlayerDelegate method:
func onNewEventReceived(playerId: String, _ event: BambuserEventPayload) {
if event.type == "ready" {
// Handle ready event
}
}
Specify which events to receive in the events list of BambuserVideoConfiguration. Use listOf("*") to receive all events, or specify individual event strings.
BambuserVideoConfiguration(
events = listOf("*"), // or listOf("ready", "goto-checkout")
configuration = mapOf(/* player configs */),
videoType = BambuserVideoAsset.Live(id),
)
Handle events using the BambuserVideoPlayerDelegate:
videoPlayerDelegate = object : BambuserVideoPlayerDelegate {
override fun onNewEventReceived(
playerId: String,
event: BambuserEventPayload,
viewActions: ViewActions,
) {
when (event.event) {
"ready" -> {
// Handle ready event
}
}
}
}
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
}
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 }
| Status | String 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
)
);
});
});
});
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 */ }
}
| Field | Description |
|---|---|
vendor | Always the constant "hydratable-product". A schema marker, not a merchant or brand identifier — safe to ignore. |
id | Bambuser-generated product ID, the same one used with player.updateProduct() |
ref | Your product reference as configured on the show |
sku | Resolved SKU for the product |
title | Product name |
url | Public product URL with the player's tracking parameters appended if enabled |
actionOrigin | Where the click came from: highlight, highlightCta, productsList, bundle, lightPDP, or externalApiCall. Absent for clicks from the in-player cart. |
actionTarget | What 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 |
raw | Catalog feed columns, catalog-sourced products only |
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);
});
You can also query the current highlight imperatively with player.getHighlightedProductsList().
Raw catalog feed data
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;
// ...
});
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 */ }
}
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 */ ]
}
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.
NAVIGATE_BEHIND_TO
- 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.
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"
}
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.
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>
| Field | Type | Description |
|---|---|---|
c | string | Client type — "p" (player) or "m" (moderator) |
n | string | Sender display name |
m | string | Message text |
r | number | Relative time in the broadcast (seconds) |
p | object | Published 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 fromplayer.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.
- Web
- Swift
- Kotlin
player.play();
try await playerView?.invoke(
function: "play",
arguments: ""
)
viewActions.invoke(
function = "play",
arguments = ""
)
player.pause()
Pauses playback.
- Web
- Swift
- Kotlin
player.pause();
try await playerView?.invoke(
function: "pause",
arguments: ""
)
viewActions.invoke(
function = "pause",
arguments = ""
)
player.mute()
Mutes the player.
- Web
- Swift
- Kotlin
player.mute();
try await playerView?.invoke(
function: "mute",
arguments: ""
)
viewActions.invoke(
function = "mute",
arguments = ""
)
player.unmute()
Unmutes the player.
- Web
- Swift
- Kotlin
player.unmute();
try await playerView?.invoke(
function: "unmute",
arguments: ""
)
viewActions.invoke(
function = "unmute",
arguments = ""
)
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 between0and100representing 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:
- Web
- Swift
- Kotlin
await player.showCaptions();
try await playerView?.invoke(function: "showCaptions", arguments: "")
viewActions.invoke(function = "showCaptions", arguments = "")
player.hideCaptions()
Disables all caption tracks. On success, the player emits CAPTIONS_HIDDEN.
Returns: Promise<Object> — Resolves with the result:
{ success: true }
Usage example:
- Web
- Swift
- Kotlin
await player.hideCaptions();
try await playerView?.invoke(function: "hideCaptions", arguments: "")
viewActions.invoke(function = "hideCaptions", arguments = "")
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:
- Web
- Swift
- Kotlin
await player.selectCaptionTrack("es-ES");
try await playerView?.invoke(
function: "selectCaptionTrack",
arguments: "'es-ES'"
)
viewActions.invoke(
function = "selectCaptionTrack",
arguments = "'\"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:
- Web
- Swift
- Kotlin
const captions = await player.getAvailableCaptions();
if (captions.availableCaptions.length > 0 && !captions.isEnabled) {
await player.showCaptions();
}
let result = try await playerView?.invoke(
function: "getAvailableCaptions",
arguments: ""
)
val result = viewActions.invoke(
function = "getAvailableCaptions",
arguments = ""
) as? Map<*, *>
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.
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();
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 usepxunits (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:
| Path | Type | Default | Description |
|---|---|---|---|
playerSettings.closedCaptions.foregroundColor | String (CSS color) | rgba(0, 0, 0, 1) | Text color of closed captions |
playerSettings.closedCaptions.backgroundColor | String (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:
| Argument | Type | Description |
|---|---|---|
productId | string | The Bambuser-generated ID for each product, found in the PROVIDE_PRODUCT_DATA event payload (event.products[].id). |
productFactory | function | Callback 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)
| Method | Argument type | Required | Description |
|---|---|---|---|
.product(fn) | function | Yes | Takes a function receiving productDetailFactory, returns product details |
.inheritFromPlaceholder() | — | No | Inherits scraped/workspace product data as base (see Inherit from scraped product) |
.publicUrl(url) | string | No | Overrides the product's PDP URL (see Override products URL) |
.hidden(bool) | boolean | No | Hides the product from the viewer (see Hide a product) |
productDetailFactory
| Method | Argument type | Required | Description |
|---|---|---|---|
.name(name) | string | Yes | Product display name |
.sku(sku) | string | Yes | Product identifier (should match your workspace product reference) |
.brandName(name) | string | No | Brand name |
.introduction(text) | string | No | Short introductory text |
.description(html) | string | No | Product description (supports HTML) |
.defaultVariationIndex(n) | number | No | Index of the default variation to display |
.variations(fn) | function | Yes | Takes function receiving variationFactory, returns array of variations |
variationFactory()
| Method | Argument type | Required | Description |
|---|---|---|---|
.name(name) | string | Yes | Variation name (shown if colorName is not set) |
.sku(sku) | string | Yes | Variation-level SKU |
.imageUrls(urls) | string[] | Yes | Array of image URLs, ordered as you want them displayed |
.attributes(fn) | function | No | Takes a function with .colorName(string), .colorHexCode(string) and .colorImage(url). colorName defaults to the variation's .name(). |
.sizes(fn) | function | Yes | Takes function receiving sizeFactory, returns array of sizes |
sizeFactory()
| Method | Argument type | Required | Description |
|---|---|---|---|
.name(name) | string | Yes | Size display name (used in dropdowns) |
.sku(sku) | string | Yes | Size-level SKU (used for add-to-cart) |
.inStock(bool) | boolean | No | Whether this variation/size is in stock. Defaults to true. |
.capacity(obj) | object | No | Capacity metadata, { value, unit } (see Product capacity) |
.price(fn) | function | Yes | Takes function with pricing chain methods |
priceFactory
| Method | Argument type | Required | Description |
|---|---|---|---|
.currency(code) | string | No | Overrides the default currency |
.current(amount) | number | Yes | Current price |
.original(amount) | number | No | Original price (used to show sale pricing) |
.discountPercentage(n) | number | No | Discount percentage to show on the badge (see Discount percentage) |
.perUnit(amount) | number | No | Per-unit price (e.g., $77 / 100ml) |
.unitAmount(n) | number | No | Unit amount |
.unitDisplayName(name) | string | No | Unit 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).
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
-25and25render the same badge. - A badge is only shown when
originalis greater thancurrentand 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
originalandcurrentwhenever you do not supply one (rounded down, capped at 99).
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
- Dynamic implementation
- Sample product data
- Static implementation
- Swift implementation
- Kotlin implementation
player.on(player.EVENT.PROVIDE_PRODUCT_DATA, (event) => {
event.products.forEach(async ({ ref: sku, url, id: bambuserId }) => {
const yourProduct = await yourGetProductMethod(sku);
player.updateProduct(bambuserId, (productFactory) =>
productFactory
.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),
)
)
)
)
)
)
);
});
});
{
"productId": "1111",
"name": "Bambuser Hoodie",
"brand": "Bambuser",
"shortDescription": "World's best hoodie",
"description": "<p>Jacket in sweatshirt fabric with a jersey-lined drawstring hood...</p>",
"colors": [
{
"variationId": "1111-black",
"name": "Black Bambuser Hoodie",
"colorName": "black",
"colorHexCode": "#000000",
"images": [
"https://demo.bambuser.shop/wp-content/uploads/2021/07/black-hoodie-front.png",
"https://demo.bambuser.shop/wp-content/uploads/2021/07/black-hoodie-right.jpeg"
],
"sizes": [
{
"sizeId": "1111-black-small",
"currency": "SEK",
"current": 100,
"original": 120,
"name": "Small",
"quantityInStock": 9
},
{
"sizeId": "1111-black-xlarge",
"currency": "SEK",
"current": 100,
"original": 120,
"name": "X-Large",
"quantityInStock": 3,
"perUnit": 100,
"unitAmount": 1,
"unitDisplayName": "piece"
}
]
},
{
"variationId": "1111-white",
"name": "White Bambuser Hoodie",
"colorName": "white",
"colorHexCode": "#FFFFFF",
"images": [
"https://demo.bambuser.shop/wp-content/uploads/2021/07/white-hoodie-front.png",
"https://demo.bambuser.shop/wp-content/uploads/2021/07/white-hoodie-right.jpeg"
],
"sizes": [
{
"sizeId": "1111-white-small",
"currency": "SEK",
"current": 100,
"original": 120,
"name": "Small",
"quantityInStock": 8
},
{
"sizeId": "1111-white-xlarge",
"currency": "SEK",
"current": 100,
"original": 120,
"name": "X-Large",
"quantityInStock": 0
}
]
}
]
}
// This is only for demonstration purposes
// Hardcoding product data is not recommended
player.on(player.EVENT.PROVIDE_PRODUCT_DATA, (event) => {
event.products.forEach(async ({ ref: sku, url, id: bambuserId }) => {
player.updateProduct(bambuserId, (productFactory) =>
productFactory.product((productDetailFactory) =>
productDetailFactory
.brandName("Bambuser")
.defaultVariationIndex(0)
.introduction("World's best hoodie")
.description("<p>Jacket in sweatshirt fabric...</p>")
.name("Bambuser Hoodie")
.sku("1111")
.variations((variationFactory) => [
variationFactory()
.attributes((attributeFactory) =>
attributeFactory.colorName("black").colorHexCode("#000000")
)
.imageUrls([
"https://demo.bambuser.shop/wp-content/uploads/2021/07/black-hoodie-front.png",
])
.name("Black Bambuser Hoodie")
.sku("1111-1")
.sizes((sizeFactory) => [
sizeFactory()
.name("Small")
.inStock(true)
.sku("1111-black-small")
.price((priceFactory) =>
priceFactory.currency("SEK").current(100).original(120)
),
]),
variationFactory()
.attributes((attributeFactory) =>
attributeFactory.colorName("white").colorHexCode("#FFFFFF")
)
.imageUrls([
"https://demo.bambuser.shop/wp-content/uploads/2021/07/white-hoodie-front.png",
])
.name("White Bambuser Hoodie")
.sku("1111-2")
.sizes((sizeFactory) => [
sizeFactory()
.name("Small")
.inStock(true)
.sku("1111-white-small")
.price((priceFactory) =>
priceFactory.currency("SEK").current(100).original(120)
),
]),
])
)
);
});
});
Host app receives the event through the delegate and uses the event data to get available product IDs/SKUs. Call the hydrate function for all available products in the show:
func onNewEventReceived(playerId: String, _ event: BambuserEventPayload) {
if event.type == "provide-product-data" {
Task {
try await self.hydrate(data: event.data)
}
}
}
The hydrate method calls the SDK's invoke() method for each product using a raw JSON string:
func hydrate(data: [String: Any]) async throws {
guard let event = data["event"] as? [String: Any],
let products = event["products"] as? [[String: Any]] else { return }
for product in products {
guard let id = product["id"] as? String else { return }
try await self.playerView.invoke(
function: "updateProductWithData",
arguments: """
'\(id)', {
sku: '7777',
name: 'Bambuser Hoodie',
brandName: 'Bambuser',
introduction: 'A nice hoodie that keeps you warm',
description: "<div><h2>World's best hoodie</h2></div>",
variations: [
{
sku: '1111-black',
name: 'Black Bambuser Hoodie',
colorName: 'black',
imageUrls: [
'https://demo.bambuser.shop/wp-content/uploads/2021/07/black-hoodie-front.png',
],
sizes: [
{
sku: '1111-black-small',
currency: 'USD',
current: 120,
original: 120,
name: 'Small',
inStock: 9,
},
],
},
],
}
"""
)
}
}
Using Builder function
You can use the Builder function from the demo app on GitHub to create properly formatted product data from your own data source.
func hydrateUsingProductBuilder(data: [String: Any]) async throws {
guard let event = data["event"] as? [String: Any],
let products = event["products"] as? [[String: Any]] else { return }
for product in products {
guard let sku = product["ref"] as? String,
let id = product["id"] as? String else { continue }
guard let productDetails = ProductHydrationDataSource.mockClientProduct(for: sku)
else { continue }
let hydratedProduct = try HydratedProduct(sku: productDetails.sku)
.withName(productDetails.productName)
.withBrandName(productDetails.brand)
.withVariations(
productDetails.variations.map { variation in
try Variation()
.withSku(variation.sku)
.withColorName(variation.colorName)
.withName(variation.name)
.withImageUrls(variation.imageUrls)
.withSizes(
variation.sizes.map { size in
try ProductSize()
.withSku(size.sku)
.withCurrentPrice(size.current)
.withInStock(size.inStock)
.withName(size.name)
.build()
}
)
.build()
}
)
.build()
let hydrationString = "'\(id)', \(try hydratedProduct.toJSON())"
try await playerView?.invoke(
function: "updateProductWithData",
arguments: hydrationString
)
}
}
Host app receives the event through the delegate and uses the event data to get available product IDs/SKUs:
override fun onNewEventReceived(
playerId: String,
event: BambuserEventPayload,
viewActions: ViewActions,
) {
when (event.event) {
"provide-product-data" -> {
(event.data["products"] as? List<Map<String, Any>>)?.let { products ->
products.forEach { product ->
product["id"]?.toString()?.let { productId ->
lifecycleScope.launch {
viewActions.invoke(
function = "updateProductWithData",
arguments = getArguments(productId)
)
}
}
}
}
}
}
}
Example product hydration data:
fun getArguments(productId: String) = """
'$productId', {
sku: '7777',
name: 'Bambuser Hoodie',
brandName: 'Bambuser',
introduction: 'A nice hoodie that keeps you warm',
description: "<div><h2>World's best hoodie</h2></div>",
variations: [
{
sku: '1111-black',
name: 'Black Bambuser Hoodie',
colorName: 'black',
imageUrls: [
'https://demo.bambuser.shop/wp-content/uploads/2021/07/black-hoodie-front.png',
],
sizes: [
{
sku: '1111-black-small',
currency: 'USD',
current: 120,
original: 120,
name: 'Small',
inStock: 9,
},
],
},
],
}
"""
Builder functions are currently not available in the Android demo project.
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.
- Web
- Swift
- Kotlin
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.
Inheriting from scraped product data is already handled in the mobile SDK's updateProductWithData function. If new data is passed, it overrides the existing data set in the dashboard; otherwise, the pre-set data is used.
Inheriting from scraped product data is already handled in the mobile SDK's updateProductWithData function. If new data is passed, it overrides the existing data set in the dashboard; otherwise, the pre-set data is used.
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:
| Argument | Type | Description |
|---|---|---|
productId | string | The Bambuser-generated ID from the PROVIDE_PRODUCT_DATA event payload. |
productData | object | A 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.
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:
- Web
- Swift
- Kotlin
player.on(player.EVENT.SYNC_CART_STATE, () => {
if (isOnSiteCartEmpty()) {
player.updateCart({ items: [] });
}
});
func onNewEventReceived(playerId: String, _ event: BambuserEventPayload) {
if event.type == "should-sync-cart-state" {
try await self.playerView.invoke(
function: "updateCart",
arguments: """{ "items": [] }"""
)
}
}
when (event.event) {
"should-sync-cart-state" -> {
viewActions.invoke(
function = "updateCart",
arguments = """{"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 windowcheckout: 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://orhttps://). 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:
| Input | Player 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 |
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.
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
- Web
- Swift
- Kotlin
player.on(player.EVENT.ADD_TO_CART, (addedItem, callback) => {
yourAddToCartMethod(addedItem.sku, 1)
.then(() => callback(true));
});
guard let callbackKey = event.data["callbackKey"] as? String else { return }
yourAddToCartMethod(sku: sku, quantity: quantity) { result in
DispatchQueue.main.async {
self.playerView.notify(callbackKey: callbackKey, info: true)
}
}
lifecycleScope.launch {
yourAddToCartMethod(sku, quantity)
event.callbackKey?.let {
viewActions.notifyView(callbackKey = it, info = true)
}
}
Cart operation failed
- Web
- Swift
- Kotlin
player.on(player.EVENT.ADD_TO_CART, (addedItem, callback) => {
yourAddToCartMethod(addedItem.sku, 1)
.then(() => callback(true))
.catch(() => callback(false));
});
guard let callbackKey = event.data["callbackKey"] as? String else { return }
yourAddToCartMethod(sku: sku, quantity: quantity) { result in
DispatchQueue.main.async {
switch result {
case .success:
self.playerView.notify(callbackKey: callbackKey, info: true)
case .failure:
self.playerView.notify(callbackKey: callbackKey, info: false)
}
}
}
lifecycleScope.launch {
try {
yourAddToCartMethod(sku, quantity)
event.callbackKey?.let {
viewActions.notifyView(callbackKey = it, info = true)
}
} catch (e: Exception) {
event.callbackKey?.let {
viewActions.notifyView(callbackKey = it, info = false)
}
}
}
Out of Stock Error
- Web
- Swift
- Kotlin
callback({
success: false,
reason: 'out-of-stock',
});
self.playerView.notify(
callbackKey: callbackKey,
info: "{ success: false, reason: 'out-of-stock' }"
)
viewActions.notifyView(
callbackKey = it,
info = """{"success": false, "reason": "out-of-stock"}""",
)
Custom Cart Error
- Web
- Swift
- Kotlin
callback({
success: false,
reason: 'custom-error',
message: 'This is my custom error message',
});
self.playerView.notify(
callbackKey: callbackKey,
info: "{ success: false, reason: 'custom-error', message: 'This is my custom error message' }"
)
viewActions.notifyView(
callbackKey = it,
info = """{"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.
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:
- Web
- Swift
- Kotlin
player.setTrackingTags([
{ key: 'customerId', value: '123-abc' },
{ key: 'membership', value: 'premium' },
]);
try await playerView?.invoke(
function: "setTrackingTags",
arguments: "[{key: 'customerId', value: '123-abc'}]"
)
viewActions.invoke(
function = "setTrackingTags",
arguments = """[{"key": "customerId", "value": "123-abc"}]"""
)
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:
- Web
- Swift
- Kotlin
player.configure({
buttons: {
checkout: player.BUTTON.MINIMIZE,
},
});
configuration: [
"buttons": [
"dismiss": "none", // Hides the close button
]
]
configuration = mapOf(
"buttons" to mapOf(
"dismiss" to "none", // Hides the close button
),
)
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:
- Web
- Swift
- Kotlin
player.configure({
minimizedPosition: player.MINIMIZED_POSITION.BOTTOM_RIGHT,
});
configuration: [
"minimizedPosition": "bottom-right" // Sets the Miniplayer initial position
]
configuration = mapOf(
"minimizedPosition" to "bottom-right", // Sets the Miniplayer initial position
)
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,
},
});