Skip to main content

Events

BambuserVideoView surfaces the player's lifecycle and runtime events through callback props. All callbacks receive a synthetic event with the payload under e.nativeEvent.

onStatus

Playback state changed.

{ id: string; state: BambuserPlayerState }

state is one of:

'ready' · 'loading' · 'playing' · 'paused' · 'stopped' · 'completed' · 'error' · 'idle' · 'buffering'

onProgress

Periodic progress updates.

{ id: string; duration: number; currentTime: number }

Both values are in seconds.

onError

An unrecoverable error occurred (for example, an invalid or unpublished show ID, or a network failure during initialisation).

{ id: string; message: string }

When the player enters an error state, onStatus also fires with state: 'error'.

onEvent

Custom events emitted by the player (add-to-cart, wishlist, share, action-card-clicked, etc.).

{ id: string; type: string; data: any }

The data shape depends on the event type. See the Bambuser Player API Reference for the full event catalog.

Platform differences

The native iOS and Android SDKs surface event payloads slightly differently. Read both locations to stay portable:

callbackKey: on iOS the callback key lives at data.callbackKey; on Android it is at the top level (e.nativeEvent.callbackKey):

const callbackKey = e.nativeEvent.callbackKey ?? e.nativeEvent.data?.callbackKey;

Event data shape: some event payloads nest data under data.event on iOS and at the top level on Android. For example, an add-to-wishlist SKU is at data.event.sku (iOS) or data.sku (Android):

const sku = Platform.OS === 'ios'
? e.nativeEvent.data?.event?.sku
: e.nativeEvent.data?.sku;

Example: respond to should-add-item-to-cart

function onEvent(e) {
const { type, data } = e.nativeEvent;
const callbackKey = e.nativeEvent.callbackKey ?? data?.callbackKey;

if (type === 'should-add-item-to-cart' && callbackKey) {
const sku = Platform.OS === 'ios' ? data?.event?.sku : data?.sku;

addToCart(sku).then((success) => {
playerRef.current?.notify(callbackKey, {
success,
reason: success ? undefined : 'out-of-stock',
});
});
}
}

See Player API › notify for the response contract.

onPiPStateChanged

Picture-in-Picture state changed.

{ id: string; state: BambuserPiPState }

state is one of:

StateFires whenPlatform
'willStart'Right before PiP begins.Both
'started'PiP is active.Both
'willStop'Right before PiP ends (programmatic stop).Both
'stopped'PiP has ended.Both
'restored'User tapped "Go to full screen" from the PiP window.iOS only

onThumbnailTapped (iOS)

User tapped the video thumbnail before playback started.

{ id: string }

Full example

import { useRef } from 'react';
import { Platform, StyleSheet } from 'react-native';
import {
BambuserVideoView,
type BambuserVideoViewRef,
} from '@bambuser/react-native-commerce-sdk';

export function LivePlayerScreen() {
const playerRef = useRef<BambuserVideoViewRef>(null);

const handleEvent = (e) => {
const { type, data } = e.nativeEvent;
const callbackKey = e.nativeEvent.callbackKey ?? data?.callbackKey;

if (type === 'provide-product-data') {
const products = Platform.OS === 'ios'
? data?.event?.products
: data?.products;

products?.forEach((product) => {
const hydrationJson = buildProductJson(product.ref);
playerRef.current?.invoke(
'updateProductWithData',
`'${product.id}', ${hydrationJson}`,
);
});
}

if (type === 'should-add-item-to-cart' && callbackKey) {
const sku = Platform.OS === 'ios' ? data?.event?.sku : data?.sku;
addToCart(sku).then((success) =>
playerRef.current?.notify(callbackKey, { success }),
);
}
};

return (
<BambuserVideoView
ref={playerRef}
style={StyleSheet.absoluteFill}
id="your-show-id"
configuration={{ autoplay: true, currency: 'USD', locale: 'en-US' }}
onEvent={handleEvent}
onStatus={(e) => console.log('state:', e.nativeEvent.state)}
onError={(e) => console.error('player error:', e.nativeEvent.message)}
/>
);
}