Shoppable Videos
The shopping feature enables your audience to browse and purchase products while watching videos. With this feature, users can view product details, explore available options (colors, sizes, etc.), and add items to their cart without leaving the video experience.
Note: The SDK does not provide payment processing. You are responsible for managing the shopping cart and checkout flow through the provided callbacks.
Overview
Firework SDK provides:
Product Display: Built-in UI to display product lists and handle user interactions
Shopping Cart: Callbacks for cart management and checkout flow
Product Details: Integrated product detail pages (PDP) with customizable actions
Purchase Tracking: Analytics integration for conversion tracking
UI Themes
The SDK provides two color themes for the shopping interface:
FireworkSdk.shopping.setShoppingViewOptions(
ShoppingViewOptions(
theme = ShoppingTheme.LIGHT // or ShoppingTheme.DARK
)
)

New Product Cards
Important: New Product Cards are only available when using Player Version 2 (V2). The Version 1 product cards described below are maintained for backward compatibility but will not receive new features.
The Firework SDK provides an enhanced product card experience in Player Version 2 with improved UI, better performance, and new features. To access the new product cards, you must enable V2 for both the video player and livestream player.




Why Use Player Version 2?
✅ All future updates and new features are only available in V2 &#xNAN;⚠️ V1 is in maintenance mode and will not receive new features
Player Version 2 provides:
Enhanced Product Cards: Improved UI with better animations and interactions
Better Performance: Faster rendering and smoother scrolling
Modern Design: Updated visual design aligned with current standards
Active Development: Ongoing improvements and new features
Bug Fixes: Priority bug fixes and updates
How to Enable Player Version 2
To use the new product cards, enable V2 for both video player and livestream player before SDK initialization:
Step 1: Set Player Versions in Application Class
import android.app.Application
import com.firework.sdk.FireworkSdk
import com.firework.sdk.FireworkSdkConfig
import com.firework.sdk.player.FwVideoPlayerVersion
import com.firework.sdk.player.FwLivestreamPlayerVersion
import com.firework.imageloading.glide.GlideImageLoaderFactory
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
// ✅ STEP 1: Set player versions to V2 (BEFORE SDK initialization)
FireworkSdk.setVideoPlayerVersion(FwVideoPlayerVersion.V2)
FireworkSdk.setLivestreamPlayerVersion(FwLivestreamPlayerVersion.V2)
// STEP 2: Build SDK configuration
val config = FireworkSdkConfig.Builder(context = this)
.clientId("YOUR_CLIENT_ID")
.imageLoader(GlideImageLoaderFactory.createInstance(context = this))
.build()
// STEP 3: Initialize SDK
FireworkSdk.init(
fireworkSdkConfig = config,
onSuccess = {
Log.d("FireworkSDK", "SDK initialized with V2 players")
},
onError = { error ->
Log.e("FireworkSDK", "Initialization failed", error)
}
)
}
}Step 2: Enable Livestream Support (If Needed)
If you're using livestream features, also add the livestream player dependency:
dependencies {
// Video player (required)
implementation("com.firework.external:FireworkSDK:X.Y.Z")
// Livestream player (only if you need livestream features)
implementation("com.firework.external.livestream:singleHostPlayer:X.Y.Z")
}And configure the livestream initializer:
import com.firework.external.livestream.singlehost.SingleHostLivestreamPlayerInitializer
val config = FireworkSdkConfig.Builder(context = this)
.clientId("YOUR_CLIENT_ID")
.imageLoader(GlideImageLoaderFactory.createInstance(context = this))
.addLivestreamPlayerInitializer(SingleHostLivestreamPlayerInitializer())
.build()Available Player Versions
Short Video Player:
FireworkSdk.setVideoPlayerVersion(FwVideoPlayerVersion.V1) // Default, maintenance mode
FireworkSdk.setVideoPlayerVersion(FwVideoPlayerVersion.V2) // Recommended, actively developedLivestream Player:
FireworkSdk.setLivestreamPlayerVersion(FwLivestreamPlayerVersion.V1) // Default, maintenance mode
FireworkSdk.setLivestreamPlayerVersion(FwLivestreamPlayerVersion.V2) // Recommended, actively developedImportant Notes
⚠️ Player versions must be set before
FireworkSdk.init()✅ Both players are independent - you can use V2 for one and V1 for the other
✅ However, we strongly recommend using V2 for both players
✅ V1 will continue to work but will not receive new features
✅ New product cards are automatically enabled when using V2 players
Verification
After enabling V2, you can verify the product cards are using the new version by observing:
Improved animations when scrolling through products
Enhanced visual design with updated spacing and typography
Better touch feedback on product card interactions
Smoother transitions when opening product details
Product Card Click Handler
By default, clicking a product card opens the product detail page (PDP). You can override this behavior:
FireworkSdk.shopping.setOnProductCardClickListener { productId, unitId, productWebUrl, videoInfo ->
// Let fullscreen player jump into picture in picture mode
FireworkSdk.enterPip()
// Perform custom navigation
// Return true to indicate the navigation is handled by your app
return true
}Version 1 Product Cards Configuration
Product cards display a list of available products in the video. Each card represents a product with its image, title, price, and action button.
Configurable Properties
Corner Radius: Rounded corners of product cards
CTA Button Label: "Shop now" or "Buy now"
CTA Button Visibility: Show or hide the action button
Click Action: Custom handler for card clicks
Corner Radius
The default corner radius is 4dp. You can customize it:
FireworkSdk.shopping.setShoppingViewOptions(
ShoppingViewOptions(
productCardsOptions = ProductCardsOptions.Default(
cornerRadius = resources.getDimensionPixelSize(R.dimen.corner_radius)
),
),
)Visual Comparison:


CTA Button Label
The default label is "Shop now". You can change it to "Buy now":
FireworkSdk.shopping.setShoppingViewOptions(
ShoppingViewOptions(
productCardsOptions = ProductCardsOptions.Default(
ctaButtonText = ProductCardsOptions.Text.BUY_NOW
// or ProductCardsOptions.Text.SHOP_NOW
),
),
)
CTA Button Visibility
Control whether the CTA button is shown on product cards:
FireworkSdk.shopping.setShoppingViewOptions(
ShoppingViewOptions(
productCardsOptions = ProductCardsOptions.Default(
isCtaVisible = true // or false
),
),
)Visual Comparison:


Custom Product Cards
Important: Custom product cards require enablement by your Firework account manager.
The SDK allows you to provide a fully custom view for product cards:
FireworkSdk.shopping.setShoppingViewOptions(
ShoppingViewOptions(
theme = ShoppingTheme.LIGHT,
productCardsOptions = ProductCardsOptions.Custom(
widthPx = width,
heightPx = height,
spaceBetweenItems = spaceBetweenItems,
cardViewStartEndPadding = padding,
customViewProvider = { MyCustomProductCard(this) },
),
),
)Implementing Custom Product Card View
Create a custom view by extending FwProductCardView:
class MyCustomProductCard @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0,
) : FwProductCardView(context, attrs, defStyle) {
private val title: TextView
private val price: TextView
private val image: ImageView
init {
inflate(context, R.layout.custom_product_card_item, this)
title = findViewById(R.id.title)
price = findViewById(R.id.price)
image = findViewById(R.id.image)
}
override fun bind(product: ProductCardDetails, videoInfo: VideoInfo) {
title.text = product.productTitle
price.text = "${product.price?.amount ?: 0.0} ${product.price?.currencyCode}"
Glide.with(image.context)
.load(product.productImageUrl)
.placeholder(R.drawable.ic_product_placeholder)
.error(R.drawable.ic_product_placeholder)
.into(image)
}
}Important Notes
Size Requirements: Width and height must be in pixels. The SDK may limit card size to respect the safe zone specifications.
Click Handling: Custom product cards cannot have clickable elements. All clicks are intercepted by the SDK.
Shopping CTA Button
The shopping CTA button appears on the product detail page and triggers the add-to-cart or shop-now action.

CTA Button Click Listener
Handle clicks on the shopping CTA button:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
FireworkSdk.shopping.setOnCtaButtonClicked { productId, unitId, productWebUrl, videoInfo ->
// Handle CTA click
// Add product to cart, navigate to checkout, etc.
}
}
override fun onDestroy() {
FireworkSdk.shopping.setOnCtaButtonClicked(null)
super.onDestroy()
}
}CTA Button Status
For long-running operations (e.g., adding to cart via API), notify the SDK of the operation status:
FireworkSdk.shopping.setOnCtaButtonClicked { productId, unitId, productWebUrl, videoInfo ->
// Set loading state
FireworkSdk.shopping.setCtaButtonStatus(CtaButtonStatus.Loading)
try {
val result = api.addToCart(productId, unitId)
if (result.isSuccess) {
FireworkSdk.shopping.setCtaButtonStatus(CtaButtonStatus.Success)
} else {
FireworkSdk.shopping.setCtaButtonStatus(CtaButtonStatus.Error)
}
} catch (e: Exception) {
FireworkSdk.shopping.setCtaButtonStatus(CtaButtonStatus.Error)
}
}Status Types:
CtaButtonStatus.Loading- Operation in progressCtaButtonStatus.Success- Operation completed successfullyCtaButtonStatus.Error- Operation failed
Note: If status is not provided within 10 seconds, the SDK assumes the operation failed.
CTA Button Text
Choose between "Add to cart" and "Shop now" labels:
FireworkSdk.shopping.setShoppingViewOptions(
ShoppingViewOptions(
productDetailsOptions = ProductDetailsOptions(
shoppingCtaButtonOptions = ShoppingCtaButtonOptions(
text = ShoppingCtaButtonOptions.Text.SHOP_NOW
// or ShoppingCtaButtonOptions.Text.ADD_TO_CART
),
),
)
)Usage Guidelines:
Add to cart: Use when shopping cart is enabled
Shop now: Use for direct navigation to product pages without cart
Customize Shopping CTA Button
You can customize the "Add to Cart" button appearance by overriding the FwShoppingCtaButtonStyle in your app's theme:
Basic Styling
<resources>
<style name="FwShoppingCtaButtonStyle" parent="FwShoppingCtaButtonParentStyle">
<item name="android:backgroundTint">@color/backgroundColor</item>
<item name="android:textColor">@color/myTextColor</item>
<item name="android:textSize">16sp</item>
</style>
</resources>Shape Customization
To customize button shape (rounded corners, etc.):
<resources>
<style name="FwShoppingCtaButtonStyle" parent="FwShoppingCtaButtonParentStyle">
<item name="shapeAppearanceOverlay">@style/MyAddToCartButtonShapeStyle</item>
</style>
<style name="MyAddToCartButtonShapeStyle">
<item name="cornerFamily">rounded</item> <!-- "rounded" or "cut" -->
<item name="cornerSizeTopLeft">6dp</item>
<item name="cornerSizeBottomLeft">6dp</item>
<item name="cornerSizeBottomRight">6dp</item>
<item name="cornerSizeTopRight">6dp</item>
</style>
</resources>Shopping Cart
The SDK does not manage the shopping cart internally. You are responsible for:
Maintaining cart state
Managing cart items
Handling checkout flow
The SDK provides callbacks and configuration options for cart integration.
Cart Behavior
Configure how the shopping cart behaves using CartBehaviour:
FireworkSdk.shopping.setShoppingCartBehaviour(behaviour: CartBehaviour)Available Behaviors:
CartBehaviour.NoCart (Default)
Shopping cart icon is hidden
Suitable for "Shop now" mode without cart
CartBehaviour.Callback
Cart icon is shown
OnCartActionListener.onCartClickedis triggered when clickedUse when opening cart as a separate activity
CartBehaviour.Embedded
Cart icon is shown
Fragment from
EmbeddedCartFactoryis displayed when clickedRequires calling
setEmbeddedCartFactoryfirst
Embedded Cart Example
class MainActivity : AppCompatActivity() {
private val embeddedCartFactory = object : EmbeddedCartFactory {
override fun getInstance(): Fragment {
return CustomShoppingCartFragment()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Set the factory
FireworkSdk.shopping.setEmbeddedCartFactory(embeddedCartFactory)
// Enable embedded cart behavior
FireworkSdk.shopping.setShoppingCartBehaviour(
Shopping.CartBehaviour.Embedded(title = "Shopping Cart")
)
}
}Cart Click Listener
Important: This listener only works with
CartBehaviour.Callback.

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Set callback behavior
FireworkSdk.shopping.setShoppingCartBehaviour(Shopping.CartBehaviour.Callback)
// Handle cart clicks
FireworkSdk.shopping.setOnCartClickListener { videoInfo ->
// Open cart activity or fragment
startActivity(Intent(this, CartActivity::class.java))
}
}
override fun onDestroy() {
FireworkSdk.shopping.setOnCartClickListener(null)
super.onDestroy()
}
}Product Detail Page (PDP)
PDP Link Button Click Listener

Handle clicks on the PDP link button:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
FireworkSdk.shopping.setOnProductLinkClickListener { productId, unitId, productWebUrl, videoInfo ->
// Let fullscreen player jump into picture in picture mode
FireworkSdk.enterPip()
// Handle custom navigation
// Return true to handle it yourself, false to let SDK handle it
openProductPage(productWebUrl)
return true
}
}
override fun onDestroy() {
FireworkSdk.shopping.setOnProductLinkClickListener(null)
super.onDestroy()
}
}Return Value:
true- Your app handles the navigationfalse- SDK opens the product page
PDP Link Button Visibility
Control whether the PDP link button is shown:
FireworkSdk.shopping.setShoppingViewOptions(
ShoppingViewOptions(
productDetailsOptions = ProductDetailsOptions(
linkButtonOptions = LinkButtonOptions(isVisible = false),
)
)
)Product Hydration
Product hydration allows you to provide real-time product data from your backend. See Product Hydration for detailed information.
"Shop Now" Mode
Configure the SDK for direct product page navigation without a shopping cart:
private fun setupShopNowMode() {
with(FireworkSdk.shopping) {
// Hide cart button
setShoppingCartBehaviour(Shopping.CartBehaviour.NoCart)
// Configure PDP options
setShoppingViewOptions(
ShoppingViewOptions(
productDetailsOptions = ProductDetailsOptions(
linkButtonOptions = LinkButtonOptions(isVisible = false),
shoppingCtaButtonOptions = ShoppingCtaButtonOptions(
text = ShoppingCtaButtonOptions.Text.SHOP_NOW
),
),
),
)
// Handle CTA clicks
setOnCtaButtonClicked { productId, unitId, productWebUrl, videoInfo ->
openWebUrlInBrowser(productWebUrl)
FireworkSdk.enterPip() // Move player to PIP
}
}
}Error Handling
Implement OnShoppingErrorListener to receive shopping error events:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
FireworkSdk.shopping.setOnShoppingErrorListener { error ->
when (error) {
is ShoppingError.AddToCartError -> handleCartError(error)
is ShoppingError.ShowProductInfoError -> handleProductError(error)
}
}
}
private fun handleCartError(error: ShoppingError.AddToCartError) {
when (error) {
ShoppingError.AddToCartError.NullProductId ->
Log.e(TAG, "Product ID is null")
ShoppingError.AddToCartError.NullProductUnitId ->
Log.e(TAG, "Product unit ID is null")
ShoppingError.AddToCartError.NullCartActionListener ->
Log.e(TAG, "Cart listener not set")
ShoppingError.AddToCartError.Timeout ->
Log.e(TAG, "Add to cart timeout")
}
}
private fun handleProductError(error: ShoppingError.ShowProductInfoError) {
when (error) {
ShoppingError.ShowProductInfoError.FailedToLaunchUrl ->
Log.e(TAG, "Failed to launch product URL")
ShoppingError.ShowProductInfoError.NullProductId ->
Log.e(TAG, "Product ID is null")
ShoppingError.ShowProductInfoError.NullUnitId ->
Log.e(TAG, "Unit ID is null")
ShoppingError.ShowProductInfoError.NullProductWebUrl ->
Log.e(TAG, "Product URL is null")
}
}
override fun onDestroy() {
FireworkSdk.shopping.setOnShoppingErrorListener(null)
super.onDestroy()
}
}Error Types
sealed interface ShoppingError {
sealed interface AddToCartError : ShoppingError {
object NullProductId : AddToCartError
object NullProductUnitId : AddToCartError
object NullCartActionListener : AddToCartError
object Timeout : AddToCartError
}
sealed interface ShowProductInfoError : ShoppingError {
object FailedToLaunchUrl : ShowProductInfoError
object NullProductId : ShowProductInfoError
object NullUnitId : ShowProductInfoError
object NullProductWebUrl : ShowProductInfoError
}
}Programmatic Control
Dismiss Shopping UI
Close the shopping interface programmatically:
FireworkSdk.shopping.dismiss()Open Shopping Cart
Open the shopping cart programmatically:
FireworkSdk.shopping.openShoppingCart()Purchase Tracking
Track completed purchases for analytics and conversion tracking.
Function Signature
fun trackPurchase(
orderId: String,
value: Double?,
currencyCode: String?,
countryCode: String?,
additionalInfo: Map<String, String>,
products: List<ProductItem>?,
shippingPrice: Double?,
subtotal: Double?,
)Parameters
orderId
String
✅
Unique identifier for the order/transaction
value
Double?
❌
Total transaction value (defaults to 0.0 if null)
currencyCode
String?
❌
Currency code (defaults to "USD" if null)
countryCode
String?
❌
Country code (defaults to device locale if null)
additionalInfo
Map<String, String>
✅
Additional custom tracking information
products
List<ProductItem>?
❌
List of purchased products
shippingPrice
Double?
❌
Shipping cost for the order
subtotal
Double?
❌
Subtotal before shipping and taxes
ProductItem Structure
data class ProductItem(
val productId: String, // External product identifier
val price: Double, // Price of the product
val quantity: Int, // Quantity purchased
)Usage Examples
Basic Purchase Tracking
import com.firework.FireworkSdk
import com.firework.common.tracking.ProductItem
FireworkSdk.shopping.trackPurchase(
orderId = "ORDER_123456",
value = 99.99,
currencyCode = "USD",
countryCode = "US",
additionalInfo = emptyMap(),
products = null,
shippingPrice = null,
subtotal = null
)Complete Purchase with Products
import com.firework.FireworkSdk
import com.firework.common.tracking.ProductItem
import java.util.Locale
// Create product items
val purchasedProducts = listOf(
ProductItem(
productId = "PROD_001",
price = 29.99,
quantity = 2
),
ProductItem(
productId = "PROD_002",
price = 39.99,
quantity = 1
)
)
// Track complete purchase
FireworkSdk.shopping.trackPurchase(
orderId = "ORDER_789012",
value = 109.97,
currencyCode = "USD",
countryCode = Locale.getDefault().country,
additionalInfo = mapOf(
"customer_id" to "CUST_12345",
"campaign_id" to "SUMMER_SALE_2024",
"payment_method" to "credit_card"
),
products = purchasedProducts,
shippingPrice = 9.99,
subtotal = 99.98
)Minimal Configuration
// Track with minimal required parameters
FireworkSdk.shopping.trackPurchase(
orderId = "ORDER_MIN_001",
value = null, // Defaults to 0.0
currencyCode = null, // Defaults to "USD"
countryCode = null, // Defaults to device locale
additionalInfo = emptyMap(),
products = null,
shippingPrice = null,
subtotal = null
)Related Documentation
Product Hydration - Real-time product data integration
Analytics - Event tracking and analytics
Last updated