> For the complete documentation index, see [llms.txt](https://docs.firework.com/firework-for-developers/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.firework.com/firework-for-developers/ios-sdk/integration-guide-for-ios-sdk/shopping-ios.md).

# Shopping (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 `FireworkVideoShoppingDelegate` delegate to receive important shopping events.

```swift
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 configurations

Please refer to [Shopping configurations (iOS)](/firework-for-developers/ios-sdk/integration-guide-for-ios-sdk/customization-ios/shopping-configurations-ios.md).

### **Customize** click behaviors for shopping

Please refer to [Customize click behaviors for shopping](https://docs.firework.com/firework-for-developers/ios-sdk/integration-guide-for-ios-sdk/customization-ios/customize-click-behaviors-ios#customize-click-behaviors-for-shopping).

### **Global 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.

```swift
func fireworkShopping(
    _ fireworkShopping: FireworkVideoShopping,
    updateDetailsForProducts products: [ProductID],
    forVideo video: VideoDetails,
    _ productHydrator: any ProductHydrating) {
    // Retrieve the most up-to-date product details
    // based on the product IDs from the host app server

    // Introduce a delay to mimic a network request that fetches
    // updated product data after the hydration callback is triggered.
    DispatchQueue.global().asyncAfter(wallDeadline: .now() + 3) {
        // Get product model list
        let productModels = productHydrator.products
        // 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)

                // Set to true to hide the product, or false to keep it visible
                productBuilder.hidden(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.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.

### 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` from your order confirmation (purchase complete) screen. Send every purchase event, without any client-side filtering, so Firework can identify attributed vs non-attributed purchases.

```swift
let orderValue: Decimal = // The final amount paid, including taxes, shipping, and any discounts applied
let shippingPrice: Decimal = // The shipping price
let subtotal: Decimal = // The cost of the items before discounts, taxes, and shipping
let totalDiscounts: Decimal = // The total discounts applied to the order
let lineItems: [LineItem] = [
    LineItem(
        sku: // The ID that can be linked back to the product or product unit.
             // It can be the SKU, barcode, GTIN, MPN, product_unit.external_id,
             // or product.external_id.
        price: // The unit price, including line-level discounts
        quantity: // Quantity
        productName: // The product variant or unit name (optional)
    )
]
FireworkVideoSDK.trackPurchase(
    orderID: "<Order ID of User Purchase>",
    orderValue: orderValue,
    currencyCode: Locale.current.currencyCode ?? "USD",
    countryCode: Locale.current.regionCode,
    shippingPrice: shippingPrice,
    subtotal: subtotal,
    totalDiscounts: totalDiscounts,
    lineItems: lineItems,
    /// Any additional information associated to the purchase.
    /// Reserved keys: order_id, order_value, currency, country, shipping_price,
    /// subtotal, total_discounts, line_items.
    /// Any values passed in the additionalInfo that use a reserved key will be ignored.
    [
        "additionalKey1": "additionalValue1",
        "additionalKey2": "additionalValue2",
        "additionalKey3": "additionalValue3"
    ]
)
```

The parameters are described in the following table:

| Parameter        | Type                | Required | Description                                                                  |
| ---------------- | ------------------- | -------- | ---------------------------------------------------------------------------- |
| `orderID`        | `String`            | Yes      | A unique identifier for the user's order.                                    |
| `orderValue`     | `Decimal`           | Yes      | The final amount paid, including taxes, shipping, and any discounts applied. |
| `currencyCode`   | `String`            | Yes      | The ISO 4217 currency code of the purchase value.                            |
| `countryCode`    | `String?`           | No       | The country code of the purchase.                                            |
| `shippingPrice`  | `Decimal?`          | No       | The shipping price of the order.                                             |
| `subtotal`       | `Decimal`           | Yes      | The cost of the items before discounts, taxes, and shipping.                 |
| `totalDiscounts` | `Decimal?`          | No       | The total discounts applied to the order.                                    |
| `lineItems`      | `[LineItem]`        | Yes      | The purchased items associated with the purchase.                            |
| `additionalInfo` | `[String: String]?` | No       | Any additional information associated to the purchase.                       |

Each `LineItem` has the following fields:

| Field         | Type      | Required | Description                                                                                                                                                 |
| ------------- | --------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sku`         | `String`  | Yes      | The ID that can be linked back to the product or product unit. It can be the SKU, barcode, GTIN, MPN, `product_unit.external_id`, or `product.external_id`. |
| `price`       | `Decimal` | Yes      | The unit price, including line-level discounts.                                                                                                             |
| `quantity`    | `Int`     | Yes      | The product quantity.                                                                                                                                       |
| `productName` | `String?` | No       | The product variant or unit name.                                                                                                                           |
