---
agentTools:
  projectIndex: https://docs.storyly.io/llms.txt
---

# Shoppable Content

This guide covers how to implement shopping cart management, product analytics tracking, product hydration and product wishlist to create engaging shopping experiences.

# What is Shoppable Content

Storyly Placement SDK provides powerful shoppable features that enable seamless e-commerce integration within widgets.

> 📘 Features
>
> * **Manage shopping cart** operations with real-time feedback
> * **Track product analytics** through comprehensive event callbacks
> * **Hydrate products** from your latest data source, ensuring up-to-date pricing, availability, and product information
> * **Product wishlist** for user's favorite products

> 📘 Architecture
>
> ### Listener-Based Control
>
> Cart and wishlist operations are handled through `STRProductListener` callbacks, giving your application complete control over state management, API integration, and user experience.
>
> ### Approve-Reject Mechanism
>
> The SDK uses a callback-based mechanism where you must explicitly approve or reject each cart/wishlist update by calling `onSuccess` or `onFail`, ensuring your backend always has the final say.

> 🚧 Prerequisites
>
> * Storyly Placement SDK integrated and initialized in your Android application as described in [Initial Setup](https://docs.storyly.io/v3.0/docs/initial-setupbeta-copy-1).
> * [Shoppable Content](https://docs.storyly.io/docs/content-creation-copy) user guide must be followed and integrations on [Storyly Dashboard](https://dashboard.storyly.io/) must be completed.
> * Wishlist feature must be turned on under Brand settings before creating shoppable content on the [Storyly Dashboard](https://dashboard.storyly.io/).

# Update Shopping Cart

This section explains how to update cart which allows users to add products to their shopping cart directly from Storyly widgets. Storyly SDK notifies your app when cart operations occur, giving you full control over the cart logic.

## Setup Listener

The `onUpdateCart` callback is triggered when a user attempts to add items in the cart through the widget. Your app is responsible for handling the actual cart operation and informing Storyly SDK of the result.

> 🚧 Warning
>
> You must call either `onSuccess` or `onFail` to inform Storyly SDK of the operation result. This allows Storyly SDK to update the UI accordingly (e.g., show success animation or error message).

```kotlin Kotlin
strPlacementView.productListener = object : STRProductListener {
    override fun onUpdateCart(
        widget: STRWidgetController,
        item: STRCartItem?,
        onSuccess: (() -> Unit)?,
        onFail: ((String) -> Unit)?
    ) {
        // Call your cart API to check product availability

        // Notify SDK in case of success
        onSuccess?.invoke()

        // Notify SDK in case of fail
        onFail?.invoke("Failed to add product to your cart")
    }
}
```

# Track Product Analytics

This section explains how to track user behavior and integrate with your analytics platforms in the context of product. The `STRProductEvent` enum represents various product-related events that can occur within the widget.

## Product Analytic Events

This section shows the list of product analytic events and their description.

| Event                   | Description                                       |
| ----------------------- | ------------------------------------------------- |
| ProductAddToCartSuccess | A product is successfully added to the cart       |
| ProductAddToCartFail    | Adding a product to the cart fails                |
| ProductSheetOpened      | A product detail sheet is opened                  |
| WishlistAdded           | A product is added to the wishlist                |
| WishlistRemoved         | A product is removed from the wishlist            |
| WishlistFailed          | A wishlist operation fails                        |
| GoToCartButtonClicked   | The cart button is clicked from the success sheet |
| ProductSelected         | A product is selected by the user                 |

## Setup Listener

The `onProductEvent` callback is triggered when a user takes any product related action.

```kotlin
strPlacementView.productListener = object : STRProductListener {
    override fun onProductEvent(
        widget: STRWidgetController,
        event: STRProductEvent
    ) {
        // Track product events
    }
}
```

# Hydrate Products

This section explains how to hydrate products with latest information from your own data. This ensures that prices, availability, and other product details are always up-to-date.

> 📘 Why use hydration?
>
> * Show latest product data instead of daily updated product feed data
> * Ensure real-time pricing accuracy
> * Display current stock availability
> * Show personalized product information
> * Maintain consistency between your app and Storyly widgets

## Setup Listener

The `onHydration` callback in `STRDataProviderProductListener` is triggered when Storyly widgets contain products that may need to be updated.

```kotlin
productListener = object : STRDataProviderProductListener {
    override fun onHydration(products: List<STRProductInformation>) {
        // Extract product IDs
        val productIds = products.mapNotNull { it.productId }
        
        // Fetch latest product data 
        val latestProducts = ...

        // Hydrate the data provider with updated products
        strPlacementDataProvider.hydrateProducts(latestProducts)
    }
}
```

# Product Wishlist

This section explains how to add products to wishlist directly from Storyly widgets. You can pre-populate the wishlist state and handle wishlist updates through dedicated callbacks.

## Setup Listener

The `onUpdateWishlist` callback is triggered when a user adds or removes a product from their wishlist through the widget. Your app handles the actual wishlist operation and informs Storyly SDK of the result.

> 🚧 Warning
>
> You must call either `onSuccess` or `onFail` to update the wishlist UI state in the widget.

```kotlin
strPlacementView.productListener = object : STRProductListener {
    override fun onUpdateWishlist(
        widget: STRWidgetController,
        item: STRProductItem?,
        event: STRProductEvent,
        onSuccess: (() -> Unit)?,
        onFail: ((String) -> Unit)?
    ) {
        try {
            when (event) {
                STRProductEvent.WishlistAdded -> {
                    // Add to wishlist
                }
                STRProductEvent.WishlistRemoved -> {
                    // Remove from wishlist
                }
                else -> {
                    // Check other events
                }
            }
            
            // Notify SDK in case of success
            onSuccess?.invoke()

        } catch (e: Exception) {
            // Notify SDK in case of fail
            onFail?.invoke("Wishlist operation failed")
        }
    }
}
```

## Hydrate Wishlisted Products

This section explains how to hydrate products that are already in the user's wishlist. This ensures the wishlist state is correctly displayed in the widget UI.

```kotlin
// Check user's wishlist
val wishlistProducts = ...

// Hydrate the wishlist
strPlacementDataProvider.hydrateWishlist(wishlistProducts)
```

# Supplemental Product Feeds

Storyly allows you to integrate you multi-market product feeds depending on language or country. You can use this feature to show different products to users in different countries or with different languages.

You need set the `locale` parameter in `STRPlacementConfig.Builder` to the end-user's locale in the [IETF BCP 47](https://www.ietf.org/rfc/bcp/bcp47.txt) format.

```kotlin
val placementProvider = PlacementDataProvider(applicationContext).apply {
    config = STRPlacementConfig.Builder()
        .setLocale(locale: <locale_for_end-user>)
        .build(token = "<your_placement_token>")
}
```