Shoppable Videos
Shopping feature allows your audience to buy products while watching the videos. With this feature enabled, a user can browse products, scroll through available options ( e.g colours, sizes, etc ) and make a purchase while watching the video. At present, the SDK doesn't provide a payment solution, but it provides the callbacks for your app to manage the shopping cart as well as the checkout process.
Firework SDK provides the user interface to display the product list and handles user interactions to browse products and add an item to the shopping cart. Currently, we don't provide a way to customize UX/UI except for the '
Add to Cart'
button. You can customize the look and feel of the Add to cart
button by overriding FwShoppingAddToCartButtonStyle
. Name of the style and the parent style must be exactly as specified in the example below:<resources xmlns:tools="http://schemas.android.com/tools">
<style name="FwShoppingAddToCartButtonStyle" parent="FwShoppingAddToCartButtonParentStyle">
<item name="android:backgroundTint">@color/backgroundColor</item>
<item name="android:textColor">@color/myTextColor</item>
<item name="android:textSize">16sp</item>
</style>
</resources>
To override the button shape properties (rounded corners radius for example) declare the separate style and apply it to
shapeAppearanceOverlay
style attribute:<resources>
<style name="FwShoppingAddToCartButtonStyle" parent="FwShoppingAddToCartButtonParentStyle">
<item name="shapeAppearanceOverlay">@style/MyAddToCartButtonShapeStyle</item>
</style>
<style name="MyAddToCartButtonShapeStyle">
<item name="cornerFamily">rounded</item> <!-- possible values "rounded" and "cut" -->
<item name="cornerSizeTopLeft">6dp</item>
<item name="cornerSizeBottomLeft">6dp</item>
<item name="cornerSizeBottomRight">6dp</item>
<item name="cornerSizeTopRight">6dp</item>
</style>
</resources>
OnCtaButtonClickListener
is called when the user clicks the shopping CTA button (3 on the picture below).
Product details page
Here is an example of how to use this interface:
Kotlin
Java
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
FireworkSdk.shopping.setOnCtaButtonClicked { productId, unitId, productUrl ->
// Handle CTA click here
}
}
override fun onDestroy() {
// Remove OnCtaButtonClickListener from the SDK
FireworkSdk.shopping.setOnCtaButtonClicked(null)
super.onDestroy()
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FireworkSdk.getShopping().setOnCtaButtonClicked(new Shopping.OnCtaButtonClickListener() {
@Override
public void onCtaButtonClick(@NonNull String productId, @NonNull String unitId, @NonNull String productUrl) {
// Handle CTA click here
}
});
}
@Override
protected void onDestroy() {
// Remove OnCtaButtonClickListener from the SDK
FireworkSdk.getShopping().setOnCtaButtonClicked(null);
super.onDestroy();
}
}
In case the host app needs to do long-running operations after the shopping CTA button is clicked, Firework SDK should be notified about the status of the operation by calling:
fun setCtaButtonStatus(status: CtaButtonStatus)
Kotlin
Java
FireworkSdk.shopping.setOnCtaButtonClickedListener { productId, unitId, _ ->
FireworkSdk.shopping.setCtaButtonStatus(CtaButtonStatus.Loading)
val result = api.doLongOpeartion()
if(result.isSuccess) {
FireworkSdk.shopping.setCtaButtonStatus(CtaButtonStatus.Success)
} else {
FireworkSdk.shopping.setCtaButtonStatus(CtaButtonStatus.Error)
}
}
}
FireworkSdk.getShopping().setOnCtaButtonClicked(new Shopping.OnCtaButtonClickListener() {
@Override
public void onCtaButtonClick(@NonNull String productId, @NonNull String unitId, @NonNull String productUrl) {
Response result = ShopCart.addProductToCart(productId, unitId); // A long api operation
if(result.isSuccess)
FireworkSdk.getShopping().setCtaButtonStatus(CtaButtonStatus.Success.INSTANCE);
else
FireworkSdk.getShopping().setCtaButtonStatus(CtaButtonStatus.Error.INSTANCE);
}
});
- CtaButtonStatus.Loading: to indicate that the CTA operation is in progress.
- CtaButtonStatus.Error: to indicate that the CTA operation failed.
- CtaButtonStatus.Success: to indicate that the CTA operation has proceeded successfully.
If the host app does not provide status to the CTA button for 10 seconds, SDK considers the action failed. This
To remove the listener:
FireworkSdk.shopping.setOnCtaButtonClickedListener(null)
Currently, Firework SDK provides two labels to the shopping CTA button:
Add to cart
and Shop now
. The Add to cart
label should be used when shopping is configured to use a shopping cart. The Shop now
label should be used when shopping is configured to work without a cart. In this case, after clicking the shopping CTA button, users are redirected directly to the product page.
To change the label, the following code is used: Kotlin
Java
FireworkSdk.shopping.setShoppingViewOptions(
ShoppingViewOptions(
ProductDetailsOptions(
shoppingCtaButtonOptions = ShoppingCtaButtonOptions(
text = ShoppingCtaButtonOptions.Text.SHOP_NOW
// text = ShoppingCtaButtonOptions.Text.ADD_TO_CART
),
),
)
)
FireworkSdk.getShopping().setShoppingViewOptions(
new ShoppingViewOptions(
new ProductDetailsOptions(
new LinkButtonOptions(),
new ShoppingCtaButtonOptions(ShoppingCtaButtonOptions.Text.SHOP_NOW, Color.WHITE)))
);
Firework SDK does not manage the shopping cart flow. As the host application, it is up to you to manage and maintain the shopping cart flow. Firework SDK provides callbacks when the shopping CTA button is clicked or when the user wants to view the shopping cart.
You can define the behaviour of the shopping cart by using:
fun setShoppingCartBehaviour(behaviour: CartBehaviour)
- CartBehaviour.NoCart: The shopping cart icon is not shown on the UI. This is the default cart behaviour if
setShoppingCartBehaviour
was not called by the host app. If applied shopping cart icon will not be shown. - CartBehaviour.Callback: When the shopping cart icon is clicked
OnCartActionListener.onCartClicked
callback is triggered. This is useful when the host app wants to open the checkout screen as a separate activity. - CartBehaviour.Embedded: When the shopping cart is clicked, the fragment generated using
EmbeddedCartFactory
will be shown. You must setEmbeddedCartFactory
by callingsetEmbeddedCartFactory
function when using this cart behaviour. OtherwiseIllegalStateException
is thrown when the shopping cart icon is clicked.
Example of customise shopping cart:
Kotlin
Java
class MainActivity : AppCompatActivity() {
// Declare EmbeddedCartFactory
private val embeddedCartFactory = object : EmbeddedCartFactory {
override fun getInstance(): Fragment {
// Host app fragmnet which will be shown when shopping cart is clicked
return CustomShoppingCartFragment()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Set EmbeddedCartFactory
FireworkSdk.shopping.setEmbeddedCartFactory(checkoutFragmentFactory)
// Set Shopping.CartBehaviour.Embedded
FireworkSdk.shopping.setShoppingCartBehaviour(Shopping.CartBehaviour.Embedded(title = "Custom cart"))
}
}
public class MainActivity extends AppCompatActivity {
private EmbeddedCartFactory checkoutFragmentFactory = new EmbeddedCartFactory() {
@NonNull
@Override
public Fragment getInstance() {
// Host app fragmnet which will be shown when shopping cart is clicked
return CustomShoppingCartFragment()
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
...
FireworkSdk.getShopping().setEmbeddedCartFactory(checkoutFragmentFactory);
FireworkSdk.getShopping().setShoppingCartBehaviour(new Shopping.CartBehaviour.Embedded("Shop Cart"));
}
}
OnCartActionListener
is called when the shopping cart icon (1 on the picture below) is clicked.
Product details page
interface OnCartActionListener {
fun onCartClicked()
}
****Important - this listener should be used only when
❗
Shopping.CartBehaviour.Callback
is applied to the SDK by calling:FireworkSdk.shopping.setShoppingCartBehaviour(Shopping.CartBehaviour.Callback)
With other Cart behaviours like
CartBehaviour.Embedded
or CartBehaviour.NoCart
the callback will not be triggered.Kotlin
Java
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Set CartBehaviour.Callback
FireworkSdk.shopping.setShoppingCartBehaviour(Shopping.CartBehaviour.Callback)
FireworkSdk.shopping.setOnCartClickListener {
// Handle click on shopping cart
}
}
override fun onDestroy() {
// Remove OnCartClickListener from the SDK
FireworkSdk.shopping.setOnCartClickListener(null)
super.onDestroy()
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// Set CartBehaviour.Callback
FireworkSdk.getShopping().setShoppingCartBehaviour(Shopping.CartBehaviour.Callback.INSTANCE);
FireworkSdk.getShopping().setOnCartClickListener(new Shopping.OnCartClickListener() {
@Override
public void onCartClick() {
// Handle click on shopping cart
}
});
}
@Override
protected void onDestroy() {
// Remove OnCartClickListener from the SDK
FireworkSdk.getShopping().setOnCartClickListener(null);
super.onDestroy();
}
}
OnProductLinkClickListener
is called when users click the shopping PDP button (2 on the picture below). 
Product details page
fun interface OnProductLinkClickListener {
fun onProductLinkClick(productId: String, unitId: String, productWebUrl: String?): Boolean
}
The host app has an opportunity to handle the click by itself or delegate it to the Firework SDK. Return
true
in onProductLinkClick
() to handle PDP flow after click action, on the contrary, return false
in onProductLinkClick()
to let Firework SDK handles the open product page flow.Here is an example of how to use this interface:
Kotlin
Java
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
FireworkSdk.shopping.setOnProductLinkClickListener{ productId, unitId, productUrl ->
// Handle click on pdp link button
return true
}
}
override fun onDestroy() {
// Remove OnProductLinkClickListener from the SDK
FireworkSdk.shopping.setOnProductLinkClickListener(null)
super.onDestroy()
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
...
FireworkSdk.getShopping().setOnProductLinkClickListener(new Shopping.OnProductLinkClickListener() {
@Override
public boolean onProductLinkClick(@NonNull String productId, @NonNull String unitId, @Nullable String productUrl) {
// Handle click on pdp link button
return true;
}
});
}
@Override
protected void onDestroy() {
// Remove OnProductLinkClickListener from the SDK
FireworkSdk.getShopping().setOnProductLinkClickListener(null)
super.onDestroy();
}
}
Change PDP button visibility by setting
ShoppingViewOptions
, see the example below: Kotlin
Java
FireworkSdk.shopping.setShoppingViewOptions(
ShoppingViewOptions(
ProductDetailsOptions(
linkButtonOptions = LinkButtonOptions(isVisible = false),
)
)
)
FireworkSdk.getShopping().setShoppingViewOptions(
new ShoppingViewOptions(
new ProductDetailsOptions(
new LinkButtonOptions(false),
new ShoppingCtaButtonOptions(ShoppingCtaButtonOptions.Text.SHOP_NOW, Color.WHITE)))
);
Product hydration - is a process of updating information about products on the runtime.
Firework SDK requests product hydration when a video associated with the products starts playing.
To implement product hydration, the host app should override
OnProductActionListener.onProductHydration()
callback.
This callback has two parameters:
products
- list of products for which hydration is requested.hydrator
- a builder that the host app should use to modify fields of a specific product.
After hydration is completed the host app should notify the SDK by calling
❗
hydrator.completeHydration()
.Without this, updated values will not be applied to Firework SDK.
Please refer to the sample app to see a complete example of the product hydration.
A simple example of product hydration may look like this:
Kotlin
Java
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
...
FireworkSdk.shopping.setOnProductHydrationListener { products, hydrator ->
val firstProduct = products.first()
// Hydrate the first product in the list
hydrator.hydrate(firstProduct.id) {
name("Modified product name")
description("Modified product description.")
isAvailable(false)
}
// Tell the SDK that to apply hydration to the products
hydrator.completeHydration()
}
}
}
override fun onDestroy() {
// Remove OnCartActionListener from the SDK
FireworkSdk.shopping.setOnProductHydrationListener(null)
super.onDestroy()
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
...
FireworkSdk.getShopping().setOnProductHydrationListener((products, hydrator) -> {
if(products.size() == 0) return;
Product firstProduct = products.get(0);
if(firstProduct.getId() == null) return;
// Hydrate the first product in the list
hydrator.hydrate(firstProduct.getId(), productBuilder -> {
productBuilder.name("Modified product name");
productBuilder.description("Modified product description.");
productBuilder.isAvailable(false);
return productBuilder;
});
// Tell the SDK that to apply hydration to the products
hydrator.completeHydration();
});
}
@Override
protected void onDestroy() {
// Remove OnProductHydrationListener from the SDK
FireworkSdk.getShopping().setOnProductHydrationListener(null);
super.onDestroy();
}
}a
To start receiving shopping error events, host app should implement the
OnShoppingErrorListener
interface./**
* Implement the interface to receive a callback when a shopping error occurs.
*/
interface OnShoppingErrorListener {
fun onShoppingError(error: ShoppingError)
}
Firework SDK provides the following functions to add and remove
OnProductActionListener
: /**
* Registers callback to be invoked when shopping-related errors occur.
* @param listener – The callback that will run
*/
fun setOnShoppingErrorListener(listener: OnShoppingErrorListener?)
To remove the listener call:
Firework.shopping.setOnShoppingErrorListener(null)
/**
* All possible errors that can occur with shopping
*/
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
}
}
To dismiss shopping UI programmatically call:
Kotlin
Java
FireworkSdk.shopping.dismiss()
FireworkSdk.getShopping().dismiss();
To open a shopping cart programmatically:
Kotlin
Java
FireworkSdk.shopping.openShoppingCart()
FireworkSdk.getShopping().openShoppingCart();
Some apps do not want to navigate the user to the shopping cart and instead prefer to open the product page right after the user clicked the shopping CTA button.
Here is the example of the setup where after clicking on the CTA product page is opened:
Kotlin
Java
private fun setupCtaModeShopping() {
with(FireworkSdk.shopping) {
setShoppingCartBehaviour(Shopping.CartBehaviour.NoCart) // Hides the cart button in top right corner
setShoppingViewOptions(
ShoppingViewOptions(
ProductDetailsOptions(
linkButtonOptions = LinkButtonOptions(false), // hides pdp link button
shoppingCtaButtonOptions = ShoppingCtaButtonOptions(text = ShoppingCtaButtonOptions.Text.SHOP_NOW),
),
),
)
setOnCtaButtonClicked { _, _, productWebUrl ->
openWebUrlInBrowser(productWebUrl)
FireworkSdk.enterPip() // move player to PIP when another screen is opened
}
}
}
FireworkSdk.getShopping().setShoppingCartBehaviour(Shopping.CartBehaviour.NoCart.INSTANCE);
FireworkSdk.getShopping().setShoppingViewOptions(
new ShoppingViewOptions(
new ProductDetailsOptions(
new LinkButtonOptions(false),
new ShoppingCtaButtonOptions(ShoppingCtaButtonOptions.Text.SHOP_NOW, Color.WHITE)))
);
FireworkSdk.getShopping().setOnCtaButtonClicked(new Shopping.OnCtaButtonClickListener() {
@Override
public void onCtaButtonClick(@NonNull String productId, @NonNull String unitId, @NonNull String productWebUrl) {
openWebUrlInBrowser(productWebUrl);
FireworkSdk.INSTANCE.enterPip(); // move player to PIP when another screen is opened
}
});
Last modified 1d ago