Product Hydration
Introduction
Product hydration lets you update product information at runtime before it is displayed to the user. This is useful for syncing prices, availability, descriptions, and variants with your own backend.
The Firework SDK supports two hydration modes:
Video-level
A video or ivestream with products starts playing
Products from a single video/livestream
setOnProductHydrationListener
Feed-level
A page of feed data is loaded
Products aggregated from all videos in the page
setOnFeedProductHydrationListener
Both modes use the same ProductHydrator API to modify products. The sections below explain each mode and the full hydration API.
Hydration Level
Feed-Level Product Hydration
Note: Feed-level hydration currently only supports short videos. Livestream content is not supported.
Feed-level hydration batches all products from a loaded page of feed data into a single callback, instead of issuing one callback per video. Products are aggregated across all videos in the page and deduplicated by product ID.
This is the recommended approach for feed views (e.g. FwPlayerDeckView) where multiple videos are loaded at once, as it reduces the number of hydration requests from N (one per video) to 1 (one per page).
Setup
Register the listener via FireworkSdk.shopping.setOnFeedProductHydrationListener:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
...
FireworkSdk.shopping.setOnFeedProductHydrationListener { products, hydrator ->
// Fetch latest product data from your backend
val updatedProducts = myApi.fetchProducts(products.mapNotNull { it.id })
for (product in products) {
val productId = product.id ?: continue
val updated = updatedProducts[productId] ?: continue
hydrator.hydrate(productId) {
name(updated.name)
description(updated.description)
isAvailable(updated.inStock)
for (unit in product.units) {
val unitId = unit.id ?: continue
variant(unitId) {
price(updated.variants[unitId]?.price ?: 0.0)
}
}
this
}
}
hydrator.completeHydration()
}
}
override fun onDestroy() {
FireworkSdk.shopping.setOnFeedProductHydrationListener(null)
super.onDestroy()
}
}Callback Parameters
products
List<Product>
Aggregated and deduplicated products from all videos in the loaded page.
hydrator
ProductHydrator
Builder used to modify product fields. Same API as video-level hydration.
Unlike video-level hydration, the callback does not include a videoInfo parameter because the products span multiple videos.
❗ You must call hydrator.completeHydration() when finished. Without this call, updated values will not be applied.
Behavior
Applies to all view types: Feed-level hydration is a global listener. Once set, it takes effect for all SDK view components (
FwPlayerDeckView,FwVideoFeedView,FwStoryBlockView).Automatic per-item disabling (DeckView inline only): When a feed-level listener is set, per-item hydration is automatically disabled only for
FwPlayerDeckViewinline cards. It does not disable per-item hydration for fullscreen playback (whether launched fromFwPlayerDeckVieworFwVideoFeedView) orFwStoryBlockView.Coexistence: Setting both
setOnFeedProductHydrationListenerandsetOnProductHydrationListenerat the same time is technically supported. If both are set, feed-level handles DeckView inline hydration while video-level handles fullscreen and StoryBlock. However, this is not recommended — see Best Practices below.Timeout: The SDK waits up to 10 seconds for
completeHydration()to be called. If the timeout is exceeded or an exception occurs, the original (non-hydrated) products are displayed.Pagination: Each page load triggers a separate hydration callback. Products that were already hydrated in a previous page are not requested again.
Video-Level Product Hydration
Video-level hydration is triggered each time a video with associated products starts playing. The SDK calls your listener with the products for that specific video.
Register the listener via FireworkSdk.shopping.setOnProductHydrationListener:
Callback Parameters
products
List<Product>
Products associated with the video that is about to play.
hydrator
ProductHydrator
Builder used to modify product fields.
videoInfo
VideoInfo
Information about the video that requested hydration.
❗ You must call hydrator.completeHydration() when finished. Without this call, updated values will not be applied.
❗ All code examples below only show the hydrate {} block for brevity. Refer to the example above for the full listener setup pattern. Remember to always call hydrator.completeHydration() after all hydrations are done.
Best Practices
For the simplest and most predictable integration, set only one hydration listener — either feed-level or video-level — rather than both.
Feed-level only (setOnFeedProductHydrationListener)
Your app uses FwPlayerDeckView and you want to reduce hydration requests from N-per-page to 1-per-page.
Video-level only (setOnProductHydrationListener)
You need per-video videoInfo in the callback, or your app primarily uses video and also livestream.
Setting a single listener avoids confusion about which listener handles which context, simplifies debugging, and ensures consistent hydration logic across all surfaces.
Product Hydration
Use ProductBuilder methods inside the hydrate {} block to modify product-level properties. These methods apply to both video-level and feed-level hydration.
Basic Attributes
name(name: String)
Sets or updates the product name.
description(description: String)
Sets or updates the product description.
subtitle(subtitle: String?)
Sets or updates the product subtitle. Pass null to clear.
currency(currency: String)
Sets the product-level currency code string (e.g. "USD", "EUR").
isAvailable(isAvailable: Boolean)
Sets the availability status of the product.
Main Product Image
mainProductImage(url: String)
Sets or updates the main product image URL. If a main image already exists, updates its URL; otherwise creates a new image entry.
Display Control
isDisabled(isDisabled: Boolean)
Sets the disabled status of the product. A disabled product is treated as unavailable.
hidePrice(hidePrice: Boolean)
Controls whether the product price is hidden from display.
hidden(hidden: Boolean?)
Sets whether the product should be hidden entirely. Pass null to use the default behavior.
CTA (Call-To-Action) Customization
customCTATitle(title: String?)
Sets a custom CTA button title. Pass null to clear.
customCTATitleTranslation(title: String?)
Sets a translated CTA title for localization. Pass null to clear.
customCTAUrl(url: String?)
Sets the URL the CTA button links to. Pass null to clear.
customCTATarget(target: String?)
Sets the CTA target identifier. Pass null to clear.
hidePrimaryCTA(hide: Boolean?)
Controls whether the primary CTA button is hidden. Pass null to use the default.
Backend-selected variants
Since 6.35.1, a product can represent a specific variant selected by the backend. When several variants are selected, the SDK can render a separate display item for each, with its own image, price, availability, and initial product-detail selection.
Product.selectedProductUnitId
SDK identifier for the selected variant; not a commerce SKU. null means no specific selection.
Product.selectedUnit
Resolved selected variant; null if no selection exists or no variant matches.
Product.selectedProductSKU
Selected variant's commerce ID (selectedUnit?.id); null if unavailable.
Use selectedProductSKU or selectedUnit?.id when matching your commerce variants. Do not use selectedProductUnitId as a commerce SKU.
Feed-level hydration still receives one entry per product ID, even when that product produces multiple variant cards. The callback entry has no per-card selectedProductUnitId. Hydrate the whole product and its variants; the SDK applies the result to each display item while preserving its selection.
Updating selected variants
When replacing variants, reuse the same ProductUnit.id values used by your commerce system. This keeps selections, stock updates, and offers associated with the correct variants.
A backend-selected variant needed by a display item is retained even if it is omitted from replaceVariants(...). This protection also applies when the feed-level callback product has no selected ID of its own. Use variant(id) to update an existing variant's fields rather than deleting and recreating it under a different commerce ID.
Variant Management
Add a new variant
Appends a new variant to the existing list of product variants. Image management is handled automatically.
Remove a variant
removeVariant(id) is deprecated since 6.35.1. It does nothing when the ID belongs to a backend-selected variant needed for display. For other variants it removes the variant and its associated image.
Migrate to replaceVariants(variantsToKeep) using the variants you want to retain. Backend-selected variants remain protected even if omitted. To update a selected variant, use variant(id).
Clear all existing variants
clearVariants() is deprecated since 6.35.1. It retains backend-selected variants and their images, so the resulting list is not necessarily empty.
Migrate from clearVariants() followed by addVariant(...) to a single replaceVariants(...) call. Reuse the existing commerce variant IDs. See the replacement example below.
Replace existing variants with new variants
Updates the variant list in one call. Use the existing commerce IDs for variants that you are updating. Backend-selected variants needed for display are retained, unchanged, if omitted from the replacement list. The final list may therefore contain more variants than the list you supply.
Modify existing variants
Locates a variant by its unique identifier and applies modifications through a ProductVariantBuilder block. If no variant with the given ID is found, the call is a no-op.
Important Notes
allowedVariantOptions
Sets the list of attribute names that are permissible for product variants. This ensures that all product variants conform to the expected attributes such as color, size, material, etc.
❗ Call this method before replaceVariants() or adding new variants, so their option names match the configured attributes.
completeHydration()
Must be called after all hydrate() calls are finished. Without this call, the SDK will not apply any hydrated values.
API Reference
Last updated
Was this helpful?