Shoppable Videos (iOS)

FireworkVideoSDK contains a shopping property that enables video shopping integration. There are two main points of integration both located on the FireworkVideoShopping type.

FireworkVideoShoppingDelegate

Assign a FireworkVideoShoppingDelegate to receive important shopping events.

FireworkVideoSDK.shopping.delegate = <Your delegate>

The shopping lifecycle events provide opportinities to customize the product views, hydrate product information and handle when a user adds a product variant to the cart.

Shopping View Configuration

When the fireworkShopping(_:willDisplayProductInfo:forVideo:) method is called it gives the host app a chance to configure the view that will be displayed. Similar to how view configurations work on the VideoFeedViewController the properties are value types and must be reassigned to the configurator before the changes will be applied.

The following items can be configured:

  1. Shopping Cart icon

    1. isHidden - Important: When setting this value to false ensure the cartProvider is added.

    2. indicator - (Used to indicate to the user that there is an item in their cart)

      1. isHidden - if the indicator is hidden or not

  2. CTA Button

    1. Button color

    2. Button font

    3. Button text color

    4. Button Label - Shop Now or Add to Cart

  3. Unavailable text

  4. Product card

    1. Appearance mode

    2. Hide Price

    3. Corner Radius

    4. Product card CTA Button text

    5. Hide product card CTA Button

func fireworkShopping(
    _ fireworkShopping: FireworkVideoShopping,
    willDisplayProductInfo productInfoViewConfigurator: ProductInfoViewConfigurable,
    forVideo video: VideoDetails
) {
    var shoppingCartConfig = ShoppingCartIconConfiguration()
    // To show the shopping cart icon set to false
    shoppingCartConfig.isHidden = false
    // Next we can show or hide the red indicator on the shopping cart based on if the cart items are empty
    shoppingCartConfig.indicator.isHidden = cartItems.isEmpty
    // We must set the config on the configurator for the updates to take place
    productInfoViewConfigurator.shoppingCartIconConfiguration = shoppingCartConfig

    var detailConfig = ProductDetailsContentConfiguration()
    // The CTA button can also be configured
    var ctaButtonConfig = detailConfig.ctaButton
    // Here we update the background of the CTA
    ctaButtonConfig.buttonConfiguration.backgroundColor = AppTheme.ctaButtonColor
    // Updating the CTA Button label to Shop Now.
    ctaButtonConfig.text = .shopNow
    // There are other button properties that can be updated like font and text color.
    detailConfig.ctaButton = ctaButtonConfig
    // Customize unavailabe text. Default to "Unavailable".
    // The custom text need to be translated if your app supports multiple languages.
    detailConfig.unavailableText = .custom("custom text")
    productInfoViewConfigurator.productDetailsConfiguration = detailConfig

    // The product card can be configured
    var productCardConfig = ProductCardConfiguration()
    // Updating appearance mode
    productCardConfig.appearance = .light
    // Hiding the price labels
    productCardConfig.priceConfiguration.isHidden = true
    // Changing corner radius property
    productCardConfig.cornerRadius = 4
    // Changing CTA button Text
    productCardConfig.ctaConfig.text = .buyNow
    // Hiding CTA button
    productCardConfig.ctaConfig.isHidden = true
    productInfoViewConfigurator.productCardConfiguration = productCardConfig
}

For more detailed examples see the Sample App Code.

Product Hydration

The fireworkShopping(_:updateDetailsForProducts:forVideo:_:) method will be called when a video will be shown that contains products. It is at this point when the host app will be able to update the associated product information. In fireworkShopping(_:updateDetailsForProducts:forVideo:_:), you could use ProductHydrating API to hydrate products. For example, you could update product names, descriptions, and variants.

func fireworkShopping(
    _ fireworkShopping: FireworkVideoShopping,
    updateDetailsForProducts products: [ProductID],
    forVideo video: VideoDetails,
    _ productHydrator: any ProductHydrating) {
    // Fetch latest product info
    // based on product id list from host app server

    // Call hydration API
    for productID in products {
        productHydrator.hydrateProduct(productID) { productBuilder in
            // Update product info
            productBuilder
                .name("Latest product name")
                .description("Latest product description")
                .isAvailable(true)

            // Update product variants.
            // The strategy can be merge or replace.
            // With merge strategy, we will merge these new variants into existing variants. We use variant id to match the variant.
            // With `replace` strategy, we will replace existing variants with these new variants.
            productBuilder.variants(.merge) { variantsBuilder in
                // Build variant
                variantsBuilder.variant("variant id1") { variantBuilder in
                    variantBuilder.name("Latest variant name1")
                        .formattedPrice(100, currencyCode: "USD")
                        .formattedOriginalPrice(120, currencyCode: "USD")
                        .url("Latest variant url1")
                        .imageUrl("Latest variant image url1")
                        .isAvailable(true)
                        .options([
                            "Color": "Latest variant color1",
                            "Size": "Latest variant size1"
                        ])
                    return variantBuilder
                }

                // Build variant
                variantsBuilder.variant("variant id2") { variantBuilder in
                    variantBuilder.name("Latest variant name2")
                        .formattedPrice(110, currencyCode: "USD")
                        .formattedOriginalPrice(130, currencyCode: "USD")
                        .url("Latest variant url2")
                        .imageUrl("Latest variant image url2")
                        .isAvailable(true)
                        .options([
                            "Color": "Latest variant color2",
                            "Size": "Latest variant size2"
                        ])
                    return variantBuilder
                }
                return variantsBuilder
            }
            return productBuilder
        }
    }
}

Strategy for hydrating product variants

  1. With merge strategy, we will merge these new variants into existing variants. We use variant id to match the variant.

  2. With replace strategy, we will replace existing variants with these new variants.

Handle primary product CTA button

The fireworkShopping(_:productVariantCTASelected:fromVideo:_:) method is called when the user has selected the CTA Button ("Add to cart"/"Shop now") and will pass the ids of the product and variant of the selected item.

The host app must call the ctaCompletionHandler to inform the next action to perform.

  • showEmbeddedCart - When sepecifying this action the SDK will request a CartViewController from the FireworkVideoSDK.shopping.cartProvider; see Providing an embedded cart view for more details.

  • dismissWithFeedback - When specifying this action the SDK will dismiss the Product summary drawer and display a toast message to the user.

  • feedbackOnly - When specifying this action the SDK will only display a toast message to the user.

  • none - When specifying this option the SDK won't perform any action.

Note: If no action is provided within 2 seconds the SDK will assume the item was not successfully added.

Important: it is at this point when the host app should add the item to the user's cart as they have indicated intent to buy this product.

Providing an embedded cart view

The host app can embed their own custom cart view which will be displayed directly within the Firework Video Player. This custom cart view can be shown within the Firework Video Player after the following actions occur:

  • User clicks cart icon - The host app must setup the configuration to show a shopping icon; see Shopping View Configuration for more details.

  • Host app returns showEmbeddedCart as the AddToCartAction - This is sequence occurs after the user selects "Add to cart".

The host app must supply a mechanism that conforms to CartViewProviding in order to provide a CartViewController. A provider must be assigned on the FireworkVideoSDK.shopping.cartProvider property. If no provider is set the actions above will be replaced with these actions; respectively:

  • User clicks cart icon - Nothing.

  • Host app returns showEmbeddedCart as the AddToCartAction - SDK treats this as a success and will use the dismissWithFeedback with success.

The CartViewController has a drawerController: DrawerControllerRepresentable property which provides a func to close the cart view container.

The default action of the product link button is to open the product URL in a web view. By default, this button would be visible, but this button can be hidden if required within the event callback of the FireworkVideoShoppingDelegate

func fireworkShopping(
    _ fireworkShopping: FireworkVideoShopping,
    willDisplayProductInfo productInfoViewConfigurator: ProductInfoViewConfigurable,
    forVideo video: VideoDetails
) {
    productInfoViewConfigurator.productDetailsConfiguration.linkButtonConfiguration.isHidden = true
}
// Implement didTapLinkButtonAt method to receive the tap link event
func fireworkShopping(
        _ fireworkShopping: FireworkVideoShopping,
        didTapLinkButtonAt item: SelectedProductVariant,
        fromVideo video: VideoDetails,
        withURL itemURL: String
    ) -> Bool {
        // Perform custom navigation here
        // Return true to indicate that the navigation is handled by your app
        return true
}

Callback event for product card click

// Implement didTapProductVariant method to receive the tap product card event
func fireworkShopping(
        _ fireworkShopping: FireworkVideoShopping,
        didTapProductVariant item: SelectedProductVariant,
        forVideo video: VideoDetails
    ) -> Bool {
        // Perform custom navigation here
        // Return true to indicate that the navigation is handled by your app
        return true
}

Handle cart icon

// Customize handling cart icon click event
FireworkVideoSDK.shopping.cartAction = .custom

// Implement the following delegate method to customize the navigation
func fireworkShopping(
    _ fireworkShopping: FireworkVideoShopping,
    didTapCartIconForVideo videoDetails: VideoDetails
) {
    // Perform custom navigation here
}

Purchase tracking

The host app can record a purchase which will help get a full picture of the user journey flow.In order to do this, call FireworkVideoSDK.trackPurchase whenever the purchase happens.

let totalPurchaseValue: Double = // The total value of the purchase
FireworkVideoSDK.trackPurchase(
            orderID: "<Order ID of User Purchase>",
            value: totalPurchaseValue,
            currencyCode: Locale.current.currencyCode,
            countryCode: Locale.current.regionCode,
            [
                "additionalKey1": "additionalValue1",
                "additionalKey2": "additionalValue2",
                "additionalKey3": "additionalValue3"
            ]
        )

Last updated