> 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/react-native-sdk/integration-guide-v2/shopping.md).

# Shopping (React Native)

### Shopping configurations

**Please refer to** [Shopping configurations (React Native)](/firework-for-developers/react-native-sdk/integration-guide-v2/customization-react-native/shopping-configurations-react-native.md).

### Customize shopping click behaviors <a href="#customize-product-card-click-behavior" id="customize-product-card-click-behavior"></a>

Please refer to [Customize shopping click behaviors](/firework-for-developers/react-native-sdk/integration-guide-v2/customization-react-native/customize-click-behaviors-react-native.md).

### Product Hydration

Product hydration lets your app refresh the SDK's product information with the latest data from your own commerce system, such as prices, availability, names, and images. When the SDK calls `onUpdateProductDetails`, fetch the requested products from your backend and return their updated details. The SDK uses your response to update the products shown to the user.

#### Why there may be fewer product IDs than product cards

**Hydration updates products, not individual product cards.** If you select several units (variants) of the same product for a video, the SDK can display a separate card for each selected unit. Those cards still belong to the same product, so their hydration request can be combined under one product ID. Fewer IDs in `event.productIds` than cards on screen does not mean that cards were skipped.

For example, a video might show three cards:

| Card         | Product ID | Selected unit |
| ------------ | ---------- | ------------- |
| Red T-shirt  | `tshirt`   | `red`         |
| Blue T-shirt | `tshirt`   | `blue`        |
| Hat          | `hat`      | `black`       |

The callback may request just `['tshirt', 'hat']`. Return one product object for `tshirt`, with both `red` and `blue` in its `units` array, and one product object for `hat`, with its `black` unit. You do not need to return a separate copy of `tshirt` for each card. The SDK applies the product update to the matching cards while preserving which unit each card represents.

**Fetch and return updated data for all units of each requested product, not just the first unit or the one currently visible.** Put shared fields such as the product name on the product object, and put each unit's price, availability, image, and other unit-specific values on its entry in `units`. Updating product-level fields alone does not refresh every unit's price or stock information. With the default hydration behavior, units omitted from your response keep their existing data, which may be out of date.

Keep `productId` and each `unitId` consistent with the product and unit identifiers supplied to Firework. The callback identifies the products to refresh; it does not provide a separate request for every selected unit. Fetch the units from your own product catalog. If a callback contains repeated product IDs, process each distinct ID once, as shown below.

#### Update product details

Implement `onUpdateProductDetails` as shown below. Replace the example values with the latest product and unit data from your backend.

```tsx
FireworkSDK.getInstance().shopping.onUpdateProductDetails = async (event) => {
  let products: Product[] = [];
  for (const productId of new Set(event.productIds)) {
    let product: Product = { productId: productId };

    // The latest product information can be fetched from the servers of the host app.

    // Product-level properties
    product.name = "latest-product-name";
    product.subtitle = "latest-product-subtitle";
    // Product-level currency string (e.g. "USD", "EUR")
    product.currency = "USD";
    product.description = "latest-product-description";
    product.isAvailable = true;
    product.mainProductImage = "https://example.com/product-image.jpg";
    // Set to true to hide the product price
    product.hidePrice = false;
    // The translated custom CTA title displayed to the user
    product.customCTATitleTranslation = "Buy Now";
    // Set to true to hide the primary CTA button
    product.hidePrimaryCTA = false;
    product.customCTATarget = "_blank";
    product.customCTAUrl = "https://example.com/product";
    // The custom CTA title key (untranslated)
    product.customCTATitle = "Add to Cart";
    // Set to true to hide the product, or false to keep it visible
    product.hidden = true;

    // Include updated data for all units of this product, including every selected unit.
    // IMPORTANT: unitId must match the unit id from the Firework SDK.
    // The SDK matches units by unitId to determine which variant to hydrate.
    // With the default behavior, omitted units retain their existing values.
    product.units = [
      {
        unitId: "unit-id-1",
        name: "Variant 1",
        url: "https://example.com/product/variant-1",
        imageUrl: "https://example.com/variant-1-image.jpg",
        // Current selling price
        price: {
          amount: 19.99,
          currencyCode: "USD",
        },
        // Original price before discount (used to show strikethrough price)
        originalPrice: {
          amount: 39.99,
          currencyCode: "USD",
        },
        // Whether this variant is available for purchase
        isAvailable: true,
        // Variant options such as color, size, etc.
        options: [
          { name: "Color", value: "Red" },
          { name: "Size", value: "M" },
        ],
      },
      {
        unitId: "unit-id-2",
        name: "Variant 2",
        url: "https://example.com/product/variant-2",
        imageUrl: "https://example.com/variant-2-image.jpg",
        price: {
          amount: 24.99,
          currencyCode: "USD",
        },
        originalPrice: {
          amount: 49.99,
          currencyCode: "USD",
        },
        isAvailable: false,
        options: [
          { name: "Color", value: "Blue" },
          { name: "Size", value: "L" },
        ],
      },
    ];

    products.push(product);
  }

  // Return the hydrated product list to the SDK.
  // All properties are optional except productId and unitId.
  // Only set the properties you want to override;
  // unset properties will retain their original values from the SDK.
  return products;
};
```

## Reference

[VideoShopping](https://eng.firework.com/react-native-firework-sdk/v2/classes/VideoShopping.html)
