# App SDK Source: https://docs.whatmore.ai/integrations/app-sdk The Whatmore App SDK renders Whatmore's shoppable-video surfaces **natively** inside your app. It is **commerce-agnostic**: the SDK renders the experience and emits events through a single delegate / callbacks object — **your app owns the cart, checkout, navigation, and analytics**. This keeps the integration small; most of the work stays in the [Whatmore dashboard](https://dashboard.whatmore.live/), not in your codebase. ## Surfaces The SDK ships ready-to-embed templates that share the same store feed, player, products, and event model: | Surface | What it is | Typical placement | | ------------ | ----------------------------------------------- | -------------------------- | | **Reel** | Full-screen vertical, swipe-to-browse video | a "TV" / "Videos" tab | | **Feed** | Scrolling post feed | a creator / celebrity page | | **Carousel** | Autoplaying horizontal rail that opens the Reel | home, category, any screen | ## Platforms Every platform exposes the **same fingerprint** — the same surfaces, the same configuration object, the same event delegate, and the same product/event models — so an integration learned on one platform transfers directly to the others. | Platform | Package | Status | | -------------------------------------------------- | ------------------------------------------ | --------- | | **[iOS (Swift)](/integrations/sdk-ios)** | `WhatmoreStorefront` (Swift Package) | Available | | **[Android (Kotlin)](/integrations/sdk-android)** | `ai.whatmore:whatmore-storefront` (Gradle) | Available | | **[React Native](/integrations/sdk-react-native)** | `@whatmore-repo/whatmore-storefront` | Available | ## The integration model Every surface takes the **same configuration** (your Whatmore store id + theme) and reports user actions through the **same event hooks**. You wire those hooks once and reuse them across surfaces. ```mermaid actions={false} theme={null} sequenceDiagram autonumber participant U as Shopper participant A as Your app participant W as Whatmore SDK W-->>A: Renders Reel / Feed / Carousel in your app U->>W: Add to cart W->>A: onTapAddToCart(product, event) U->>W: Tap product or CTA W->>A: onTapProduct / onTapCTA(url, event) U->>W: Like / save / share W->>A: onToggleLike / onToggleSave / onTapShare Note over A: Your app owns cart, checkout, and navigation Note over A: Then report the sale via Order Tracking at checkout ``` * **Configure once** — a store id, optional theme, and a product provider. * **Handle events** — add-to-cart, product tap, CTA, like/save/share. The SDK never touches a cart, so you decide what each event does. * **Attribute purchases** — capture the products surfaced by the SDK and include them on the [Order Tracking](/integrations/order-tracking) call at checkout, so Whatmore can credit the video. Pick your platform for the full interface: **[iOS](/integrations/sdk-ios)** · **[Android](/integrations/sdk-android)** · **[React Native](/integrations/sdk-react-native)**. # Authentication Source: https://docs.whatmore.ai/integrations/authentication Whatmore's integration APIs are called by **your** backend and authenticated with a **bearer token**. You obtain the token from Whatmore using your `store_id`, then send it on every API call. ## Get an access token ```http theme={null} GET /auth/access-token?store_id= ``` Returns a bearer token (JWT) scoped to your store. The token is **long-lived — it does not expire** — so request it once from your server, cache it, and reuse it across all calls; there's no refresh flow to build. ## Call the APIs with the token Send the token as a bearer credential, and include `store_id` as a query parameter on the private tracking endpoints: ```http theme={null} POST /external-shop-order-tracking/private?store_id= Authorization: Bearer Content-Type: application/json ``` A missing or invalid token is rejected with **HTTP 401**. See [Errors & Conventions](/integrations/errors) for all status codes and response shapes. ## Base URL The API base URL is **`https://api.whatmore.live`**. You manage your store, videos, and integration settings in the dashboard at **[dashboard.whatmore.live](https://dashboard.whatmore.live/)**. Each environment issues its own `store_id` / token, so integration testing never touches live data. ## Credentials you receive | Credential | Used for | | ------------------ | -------------------------------------------------------------------- | | `store_id` | Identifies your store; used to fetch a token and on every call | | `brand` / Brand ID | Used by the [App SDK](/integrations/app-sdk) to render your surfaces | | Access token | Bearer auth on Catalog + Order Tracking APIs | Keep the `store_id` and access token **server-side**. The App SDK uses only the public Brand ID — never embed the token in client or mobile app code. # Catalog API Source: https://docs.whatmore.ai/integrations/catalog-api Whatmore keeps its own copy of your product data (title, price, image, availability) so videos can be made shoppable. You keep that copy in sync two ways: * **[Pull — how products get in](#pull-initial-load-and-refresh) (primary):** connect your product API once in the dashboard and add your product URLs. Whatmore reads each product from your API and stores it — for the initial load, for every new product you add, and on refresh. **This is all most integrations need.** * **[Push — real-time updates](#push-real-time-updates) (optional):** when price or availability changes, push the change via API so tagged products update immediately, without waiting for a refresh. Video upload and product tagging happen in the [Whatmore dashboard](https://dashboard.whatmore.live/). **Video & media are managed in the dashboard — there is no upload API to integrate.** Your only catalog job is exposing a product API Whatmore can read (pull); the real-time push is optional. Less to build on your side, faster go-live. ## Pull: initial load and refresh **You add products by their URL — there's no product-creation API to call.** In [dashboard.whatmore.live](https://dashboard.whatmore.live/) you connect your **product API** (an endpoint that returns a single product's detail, plus any auth it needs) and add your product page URLs. For each URL, Whatmore extracts the product id, calls your product API for that product, and stores the returned JSON. This is how the **initial load**, every **new product**, and each **refresh** work. ### How the product id is read from a URL Whatmore turns each product URL into a **product id** — the value it uses to query your API, and which it stores as your [`client_product_id`](#product-identity). * **Give us a regex to extract it exactly (recommended).** For a Nike-style URL `https://www.nike.com/t/air-max-90-shoes/CN8490-002`, a rule such as `([^/]+)$` (the last path segment) yields `CN8490-002`. A regex keeps extraction deterministic across all your URL shapes. * **Default behaviour today:** with no rule set, Whatmore takes the trailing token of the URL — it splits on `-` and uses the last segment. That works when the URL ends in the id, but is brittle for other URL patterns, so providing a regex is strongly recommended. ### Expected product JSON Your product API returns a **single product's** detail as JSON. The shape is flexible — you map fields to Whatmore's in the dashboard, and nested keys are supported (expand the tree view to pick them). A representative response: ```json theme={null} { "id": "CN8490-002", "name": "Nike Air Max 90", "permalink": "https://www.nike.com/t/air-max-90-shoes/CN8490-002", "price": "130.00", "regular_price": "150.00", "sale_price": "130.00", "currency": "USD", "description": "The Air Max 90 stays true to its running roots with the iconic Waffle sole.", "sku": "CN8490-002", "stock_status": "instock", "stock_quantity": 42, "images": [ { "src": "https://static.nike.com/air-max-90/CN8490-002.jpg" }, { "src": "https://static.nike.com/air-max-90/CN8490-002-alt.jpg" } ] } ``` Every field, its type, and where it maps in Whatmore: | Field | Type | Maps to → | Required | Notes | | ---------------- | ---------------------------- | ---------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string or integer | `client_product_id` | **Yes** | Stable, unique product id. Normally equals the id in the URL; it's the key you reuse in [order tracking](/integrations/order-tracking). | | `name` | string | Product title | **Yes** | Display title. | | `permalink` | string (URL) | `product_link` | **Yes** | Canonical product page URL. | | `price` | string | `price` | **Yes** | Current selling price as a decimal **string** (`"130.00"`), not a number. | | `sale_price` | string | `price` | Optional | Use in place of `price` when the product is on sale. | | `regular_price` | string | `compare_price` (MRP) | Recommended | Struck-through / original price. | | `currency` | string (ISO 4217) | Currency | Recommended | e.g. `"USD"`. If your API omits it, set it once in the dashboard. | | `images` | array of `{ "src": string }` | `thumbnail_image` | **Yes** | First entry (`images[0].src`) becomes the thumbnail. | | `description` | string | Description | Optional | May contain HTML. | | `sku` | string | `product_metadata.sku` | Optional | Stock-keeping unit. | | `stock_status` | string (enum) | Availability | Optional | One of `"instock"`, `"outofstock"`, `"onbackorder"`. | | `stock_quantity` | integer or `null` | Availability | Optional | Units in stock; `null` when inventory isn't tracked. | Field names above are illustrative — your API can use any names, and you map them in the dashboard (nested keys included). Only the **id**, **title**, **price**, **product URL**, and **first image** are strictly required; the rest are recommended or optional. See your platform guide for the exact endpoint and credentials: [WooCommerce](/integrations/platform-woocommerce) · [Custom / headless](/integrations/platform-custom) · [Magento](/integrations/platform-magento) · [SFCC](/integrations/platform-sfcc) · [BigCommerce](/integrations/platform-bigcommerce). ## Product identity * **`client_product_id`** — *your* product id, **extracted from the product URL** (see [above](#how-the-product-id-is-read-from-a-url)) and normally identical to the `id` your API returns. It is the key you reuse on every push and in [order tracking](/integrations/order-tracking): whatever value ends up here **must be the exact same value you send in `order_items[].product_id`**, or the item can't be attributed. * **`product_link`** — the product's URL. * Whatmore also assigns its own internal numeric `product_id` for its records. ## Push: real-time updates New products flow in through the pull above. Push is **optional** — use it only when you want a price or availability change to reflect **immediately**, without waiting for the next refresh. It uses a [bearer token](/integrations/authentication); the base URL is `https://api.whatmore.live`. Status codes and response conventions are on [Errors & Conventions](/integrations/errors). `POST /v2/product` **upserts** a product by `client_product_id` — creating it if it's new and updating it otherwise. The body is the product in Whatmore's field names, mirroring the [product JSON](#expected-product-json) above: ```http theme={null} POST /v2/product Authorization: Bearer Content-Type: application/json ``` ```json theme={null} { "client_product_id": "CN8490-002", "product_link": "https://www.nike.com/t/air-max-90-shoes/CN8490-002", "title": "Nike Air Max 90", "price": "130.00", "compare_price": "150.00", "currency": "USD", "description": "The Air Max 90 stays true to its running roots.", "thumbnail_image": "https://static.nike.com/air-max-90/CN8490-002.jpg", "sku": "CN8490-002", "stock_status": "instock", "stock_quantity": 42, "product_status": "active" } ``` | Field | Type | Required | Notes | | ------------------- | ----------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `client_product_id` | string | **Yes** | Identifies the product to upsert; must match your catalog + [order tracking](/integrations/order-tracking). | | `product_link` | string (URL) | **Yes** on create | Canonical product URL. | | `title` | string | **Yes** on create | Display title. | | `price` | string | **Yes** on create | Selling price as a decimal string. | | `compare_price` | string | Recommended | MRP / struck-through price. | | `currency` | string (ISO 4217) | Recommended | e.g. `"USD"`. | | `thumbnail_image` | string (URL) | **Yes** on create | Product image. | | `description` | string | Optional | May contain HTML. | | `sku` | string | Optional | Stored under `product_metadata`. | | `stock_status` | string (enum) | Optional | `"instock"`, `"outofstock"`, or `"onbackorder"` — inventory availability. | | `stock_quantity` | integer or `null` | Optional | Units in stock. | | `product_status` | string (enum) | Optional | `"active"` (shoppable) or `"inactive"` (taken down on your surfaces). Whether an out-of-stock product is hidden or shown as OOS is configured per store at onboarding. | On **update**, only the fields you send are changed — omit the rest. New products still flow in automatically through the pull; use `POST /v2/product` only when you need an immediate update. # Errors & Conventions Source: https://docs.whatmore.ai/integrations/errors Conventions that apply to every Core API call — [Authentication](/integrations/authentication), [Catalog](/integrations/catalog-api), and [Order Tracking](/integrations/order-tracking). ## Base URL & auth * Base URL: **`https://api.whatmore.live`**. * Every call carries a bearer token: `Authorization: Bearer `. * The token is **long-lived — it does not expire.** Fetch it once from `GET /auth/access-token?store_id=`, cache it server-side, and reuse it. There is no refresh flow. ## Response conventions * **Success is any `2xx`.** Write calls (`POST`/`PUT` on catalog, order tracking) return **HTTP 200 with an empty body** — `{}`. Don't wait for a payload; treat `200` as done. * **Reads** return JSON (an object or array) as documented on each endpoint. * **Prices are strings** (e.g. `"12.500"`), not numbers. `quantity` is an integer. * The **product identifier must be identical** everywhere — the `client_product_id` you sync to the catalog is the same value you send in `order_items[].product_id`. A mismatch means the item can't be attributed. ## Status codes | Code | Meaning | | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `200` | Success. Writes return `{}`; reads return the documented JSON. | | `401` | Missing or invalid bearer token. Re-fetch the token and retry. | | `404` | `Order Id already exists.` — the order was already recorded (see [idempotency](#idempotency--retries)). `Brand is invalid` — the `store_id` isn't recognised. | | `422` | Request body failed validation — e.g. a missing `client_product_id` on `POST /v2/product`, or a malformed [order-tracking](/integrations/order-tracking) payload. | Errors are returned in FastAPI's shape: `{ "detail": "" }`. ## Idempotency & retries Order tracking is **de-duplicated by `order_id`.** Re-sending the same `order_id` is rejected with **`404 Order Id already exists.`** rather than double-counted, so retries after a network failure are safe — use a stable `order_id` and treat the duplicate response as success. See [Order Tracking → idempotency](/integrations/order-tracking#idempotency--retries). ## Rate limits The default limit is **1,000 requests per minute per store**. This can be increased per client — ask your Whatmore contact if you expect higher volume. Because a token is long-lived, cache it rather than re-fetching per call, and push catalog updates **on change** rather than on a fixed schedule to stay comfortably within the limit. # Backend Questions & Clarifications Source: https://docs.whatmore.ai/integrations/faq Answers to the questions backend teams most commonly raise. ## 1. How does Whatmore get my product data? Two mechanisms (see [Catalog API](/integrations/catalog-api)): * **[Pull](/integrations/catalog-api#pull-initial-load-and-refresh) (primary):** you give Whatmore your product API endpoint + credentials and add product URLs in the dashboard; Whatmore **pulls** each product from your API — for the initial load, every new product, and on refresh. There is no product-creation API for you to call. * **[Push](/integrations/catalog-api#push-real-time-updates) (optional):** when price or availability changes, you **push** `POST /v2/product` so the change reflects immediately. Whatmore stores the data and serves it to the surfaces. **What fields does a product have?** Your product API returns them and you map them in the dashboard — see [Expected product JSON](/integrations/catalog-api#expected-product-json). ## 2. Catalog synchronization * **Initial load & refresh (pull):** point Whatmore at your product API in the dashboard and add product URLs; Whatmore reads each product on connect and on refresh. * **Real-time updates (push, optional):** when price or availability changes, send `POST /v2/product` by `client_product_id` so it reflects immediately. Because you reference products by *your own* `client_product_id` (extracted from the product URL — normally the same as the `id` your API returns), there is no separate id-mapping to maintain. **Video and media are managed in the dashboard — no upload API to build.** ## 3. How do I add or remove a product? **Add:** put its product page **URL** in the dashboard — Whatmore pulls it from your product API and stores it (new products are also picked up on refresh). There's no product-create or bulk API for you to call. **Remove / take down:** drop it from your catalog (reflected on refresh) or push `POST /v2/product` with `product_status: "inactive"`. ## 4. Order tracking / "webhooks" Order data is **pushed by you** to `POST /external-shop-order-tracking/private` on order completion — see [Order Tracking](/integrations/order-tracking). Key semantics: * **Idempotency:** orders are de-duplicated by `order_id`; a repeat is rejected (`Order Id already exists.`), never double-counted — so retries are safe. * **Timeout / retry:** send one call per order; on network failure, re-send the same `order_id`. Recommended retry cadence is confirmed at onboarding. ## 5. API Contracts Concrete request/response examples for every endpoint are on the [Catalog API](/integrations/catalog-api) and [Order Tracking](/integrations/order-tracking) pages. A formal OpenAPI/Swagger export can be provided on request. ## 6. Security * **Authentication:** all calls use a bearer access token obtained from `GET /auth/access-token` with your `store_id` — see [Authentication](/integrations/authentication). * **Environment separation:** production and staging issue separate `store_id`s and tokens. * **Token handling:** keep the token server-side; the App SDK uses only the public Brand ID. ## 7. Performance The default rate limit is **1,000 requests per minute per store**, and can be increased per client on request. Cache the long-lived access token rather than re-fetching it, and push catalog updates **on change** rather than on a schedule. See [Errors & Conventions](/integrations/errors) for status codes, response shapes, and limits. # Getting Started Source: https://docs.whatmore.ai/integrations/getting-started Prerequisites and a checklist for integrating a non-Shopify storefront with Whatmore. ## 1. Get access Your Whatmore contact provisions your store and issues: * A **`store_id`** — identifies your store; used to get an access token and on every API call. * A **Brand ID** — used by the [App SDK](/integrations/app-sdk) to render your surfaces. * Access to the Whatmore **dashboard** for managing videos and tagging products. You obtain a **bearer access token** yourself from `GET /auth/access-token?store_id=` and send it on every API call. See [Authentication](/integrations/authentication). ## 2. Environments The API base URL is `https://api.whatmore.live`; the dashboard is at [dashboard.whatmore.live](https://dashboard.whatmore.live/). Production and staging issue **separate `store_id`s and tokens**, so integration testing never touches live data. ## 3. Integration checklist * [ ] `store_id` + Brand ID received; access token obtained ([Auth](/integrations/authentication)) * [ ] Catalog [pull connected](/integrations/catalog-api#pull-initial-load-and-refresh) (product API + field mapping, product URLs added); [real-time push](/integrations/catalog-api#push-real-time-updates) wired *(optional — price / availability)* * [ ] Widget embedded from the dashboard-generated snippet (or [App SDK](/integrations/app-sdk) for apps) * [ ] [Order tracking](/integrations/order-tracking) called on order completion * [ ] Attribution verified in the dashboard ## Mental model * **The dashboard does the work.** You connect a catalog and report orders; video hosting, tagging, campaigns, and analytics live in the dashboard. * **Reference products by your own `client_product_id`** (commonly the product URL) — no separate id mapping. * **Attribution is per order item** — the widget's video-view / add-to-cart signals are matched to line items on the [order-tracking](/integrations/order-tracking) call. # Order Tracking Source: https://docs.whatmore.ai/integrations/order-tracking When an order completes, your backend reports it to Whatmore so purchases can be attributed to the videos that drove them. This is a single authenticated call. ## Endpoint ```http theme={null} POST https://api.whatmore.live/external-shop-order-tracking/private?store_id= Authorization: Bearer Content-Type: application/json ``` ## Payload ```json theme={null} { "order_id": "ORD-10293", "order_items": [ { "product_id": "CN8490-002", "item_id": "LI-1", "sku": "CN8490-002", "price": "130.00", "quantity": 1, "currency": "USD" }, { "product_id": "DA1234-100", "item_id": "LI-2", "sku": "DA1234-100", "price": "90.00", "quantity": 2, "currency": "USD" } ], "whatmore_video_view": "[{\"product_id\":\"CN8490-002\",\"widget_info\":\"carousel_84213\"}]", "whatmore_add_to_cart": "[{\"product_id\":\"CN8490-002\",\"widget_info\":\"carousel_84213\"}]" } ``` | Field | Type | Notes | | ---------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `order_id` | string | Your order identifier. Used for idempotency (see below). | | `order_items[]` | array | One entry per line item — see the table below. | | `whatmore_video_view` | **string** (JSON-encoded) | Products **watched in a video**. A JSON-encoded array of `{ product_id, widget_info }`. On web the widget stores it in `localStorage._whatmore_viewed_products`; pass it through as-is. Defaults to `"[]"`. | | `whatmore_add_to_cart` | **string** (JSON-encoded) | Same shape, for products **added to cart from a video**. On web, `localStorage._whatmore_add_to_cart_products`. Defaults to `"[]"`. | Each `order_items[]` entry: | Field | Type | Required | Notes | | ------------ | ----------------- | -------- | ----------------------------------------------------------------------- | | `product_id` | string | **Yes** | Your `client_product_id` — must match your catalog (see warning below). | | `price` | string | **Yes** | Unit price as a decimal string (`"130.00"`). | | `quantity` | integer | **Yes** | Units ordered. | | `currency` | string (ISO 4217) | **Yes** | e.g. `"USD"`. | | `item_id` | string | Optional | Your line-item id. | | `sku` | string | Optional | Stock-keeping unit. | ### What's inside the video-view / add-to-cart signals `whatmore_video_view` and `whatmore_add_to_cart` are **JSON-encoded strings** (not objects) — the App SDK / widget produces them and you pass them straight through from `localStorage`. You don't build these by hand. Decoded, the string is an array of small objects: ```json theme={null} [ { "product_id": "CN8490-002", "widget_info": "carousel_84213" } ] ``` | Field | Type | Notes | | ------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `product_id` | string | The `client_product_id` that was viewed / added from a video. | | `widget_info` | string | Identifies the surface + video credited, formatted `_` — e.g. `carousel_84213`. `widget_type` is one of `carousel`, `stories`, `collection`, `banner`, `embed`; `event_id` is the Whatmore video id. | The `product_id` you send in `order_items[]` **must be the same identifier your catalog uses for that product** (your `client_product_id`) — otherwise the item can't be matched to the video signal. A successful call returns **HTTP 200** with an empty body (`{}`). An item that matches no video signal is simply left unattributed — it is **not** an error. ## Ready-to-use snippet (web) On a web storefront the video widget records viewed / added-to-cart products into `localStorage`. Call this once on your order-confirmation page — it reads those signals and reports the order: ```javascript theme={null} async function sendOrderTrackingRequest({ orderId, orderItems, storeId, token }) { const url = `https://api.whatmore.live/external-shop-order-tracking/private?store_id=${encodeURIComponent(storeId)}`; const payload = { order_id: orderId, order_items: orderItems, whatmore_video_view: localStorage._whatmore_viewed_products || "[]", whatmore_add_to_cart: localStorage._whatmore_add_to_cart_products || "[]", }; const res = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` }, body: JSON.stringify(payload), }); if (!res.ok) throw new Error(`Order tracking failed: ${res.status} ${res.statusText}`); return res; } ``` Build `orderItems` from your order (`product_id`, `item_id`, `sku`, `price`, `quantity`, `currency` per line), then call `sendOrderTrackingRequest({ orderId, orderItems, storeId, token })`. ## How attribution works * Whatmore matches each **order item** to the SDK signals by `product_id` (your `client_product_id`). * Attribution is therefore **per line item** — items driven by a video are attributed; items bought independently are not. A single order can mix both. * `whatmore_video_view` and `whatmore_add_to_cart` carry the `widget_info` that identifies which surface/video is credited. ## Idempotency & retries * Orders are de-duplicated by `order_id`. If an order is submitted twice, the duplicate is rejected with **HTTP 404 (`Order Id already exists.`)** rather than double-counted. * This makes retries safe: re-sending the same `order_id` after a network failure cannot create a duplicate. Use a stable `order_id` and treat the duplicate response as success. * Full status-code list is on [Errors & Conventions](/integrations/errors). Send one tracking call per completed order. The `whatmore_video_view` / `whatmore_add_to_cart` strings are produced by the App SDK and passed through your checkout — see [App SDK → attribution](/integrations/app-sdk#the-integration-model). ## Cart tracking *(optional)* Cart events can additionally be reported to power funnel analytics between video view and purchase. Nice-to-have, not required for attribution — scope confirmed during onboarding. # Overview Source: https://docs.whatmore.ai/integrations/overview Integrate Whatmore's shoppable-video platform into **any** storefront — native mobile apps, custom / headless sites, and the major commerce platforms. This section is the technical reference for that integration. Whatmore's dashboard does the heavy lifting — video hosting, product tagging, campaigns, and analytics all live there. Your integration is deliberately small, so you go live fast. ## Platform support | Platform | How you integrate | | -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | | **[Shopify](/integrations/platform-shopify)** | Install the native app — no code | | **[Magento / Adobe Commerce](/integrations/platform-magento)** | Web widget + Core APIs | | **[Salesforce Commerce Cloud](/integrations/platform-sfcc)** | Web widget + Core APIs | | **[WooCommerce](/integrations/platform-woocommerce)** | Web widget + Core APIs | | **[BigCommerce](/integrations/platform-bigcommerce)** | Web widget + Core APIs | | **[Custom / headless](/integrations/platform-custom)** | Web widget + Core APIs (or [App SDK](/integrations/app-sdk) for apps) | | **Mobile apps** | [iOS](/integrations/sdk-ios) · [React Native](/integrations/sdk-react-native) · [Android](/integrations/sdk-android) | ## The integration surface Regardless of platform, an integration is made of three building blocks — you can build them in parallel: | Building block | What it does | | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | **[App SDK / web widget](/integrations/app-sdk)** | Renders the shoppable-video surfaces in your app or site | | **[Catalog](/integrations/catalog-api)** | Makes your products available to Whatmore (connect your product API in the dashboard, or push via API) | | **[Order Tracking](/integrations/order-tracking)** | Reports purchases so Whatmore can attribute them to videos | Everything else — uploading videos, tagging products to them, building campaigns, viewing analytics — happens in the **[Whatmore dashboard](https://dashboard.whatmore.live/)**, not in your code. ## How data flows Catalog data flows **into** Whatmore — Whatmore pulls your catalog for the initial load and refreshes, **and** you push event-based updates (price, stock, images) as they change. Whatmore then renders the shoppable surfaces **inside** your app, and your order backend reports purchases **back** for attribution. All API calls are authenticated with a [bearer token](/integrations/authentication). ```mermaid actions={false} theme={null} sequenceDiagram autonumber participant U as Shopper participant S as Your storefront participant W as Whatmore Note over S,W: Catalog (pull + push) W->>S: Pull product API — initial sync and refresh S-->>W: Product data (title, price, image, stock) S->>W: Push events — price, stock, quantity, image changes Note over U,W: Render W->>S: App SDK / widget renders Reel, Feed, Carousel U->>S: Watches videos, taps products, adds to cart Note over S: view / add-to-cart signals captured Note over S,W: Attribution U->>S: Completes purchase S->>W: POST order tracking — items + signals (Bearer token) W-->>S: Purchase attributed to the driving video ``` ## Key concepts * **`store_id`** — your store's identifier on Whatmore; used to get an access token and on every API call. * **`client_product_id`** — *your* product identifier (commonly the product URL). You reference products by it on every call, so Whatmore stays aligned with your catalog without a separate mapping layer. * **Attribution is per order item** — video-view / add-to-cart signals are matched to individual line items, so one order can attribute different items to different videos (or none). ## Start here 1. **[Getting Started](/integrations/getting-started)** — access token, `store_id`, checklist 2. **[App SDK](/integrations/app-sdk)** — mobile ([iOS](/integrations/sdk-ios) · [React Native](/integrations/sdk-react-native) · [Android](/integrations/sdk-android)) or web widget 3. **Core APIs** — [Authentication](/integrations/authentication) · [Catalog API](/integrations/catalog-api) · [Order Tracking](/integrations/order-tracking) 4. **Your platform** — [Shopify](/integrations/platform-shopify) · [Magento](/integrations/platform-magento) · [SFCC](/integrations/platform-sfcc) · [WooCommerce](/integrations/platform-woocommerce) · [BigCommerce](/integrations/platform-bigcommerce) · [Custom / Headless](/integrations/platform-custom) # BigCommerce Source: https://docs.whatmore.ai/integrations/platform-bigcommerce How a BigCommerce store integrates Whatmore — Stencil (hosted) or headless. The building blocks are the same as any non-Shopify store; this page maps them onto BigCommerce. ## 1. Connect your catalog Whatmore reads your products through the BigCommerce Catalog API and you map the fields in the dashboard. Your product endpoint is typically: ```bash theme={null} curl "https://api.bigcommerce.com/stores/STORE_HASH/v3/catalog/products/PRODUCT_ID" \ -H "X-Auth-Token: " ``` In [dashboard.whatmore.live](https://dashboard.whatmore.live/) select **BigCommerce**, enter the endpoint + token, and map fields to Whatmore's (title, `client_product_id`, price, compare-at, product URL, image) — see [Catalog API → Connect in the dashboard](/integrations/catalog-api#pull-initial-load-and-refresh). *(Also push price/stock/image updates via the [Catalog API](/integrations/catalog-api#push-real-time-updates).)* ## 2. Embed the widget In the dashboard, set up a surface, choose a template, and **copy the generated snippet**: * **Stencil:** paste it via **Script Manager** (Storefront → Script Manager) or a Stencil template (e.g. `product.html`). * **Headless:** mount it in your storefront app. The snippet is generated for your store — no hardcoded script URL. ## 3. Authentication For order tracking, fetch a bearer token from `GET /auth/access-token?store_id=` server-side (store the `store_id` / token in your app's secure config). See [Authentication](/integrations/authentication). ## 4. Order tracking On order completion (order-confirmation page, or a BigCommerce `store/order/*` webhook), call [Order Tracking](/integrations/order-tracking) with the order items. The web widget stores video-view / add-to-cart signals in `localStorage`, so the [ready-to-use snippet](/integrations/order-tracking#ready-to-use-snippet-web) picks them up. ## Verify * Products appear in your Whatmore dashboard catalog * Widget renders from the pasted snippet * Order tracking fires on confirmation and attribution shows in the dashboard # Custom / Headless Source: https://docs.whatmore.ai/integrations/platform-custom For a custom or headless storefront (any stack), you connect Whatmore in three steps: provide a product API, embed the widget snippet, and report orders. This is the most direct integration and uses the [Core APIs](/integrations/authentication) plus the dashboard. ## 1. Create your store in the dashboard Sign in at [dashboard.whatmore.live](https://dashboard.whatmore.live/), choose **Shoppable Videos**, and select **Custom** as the store type. ## 2. Connect your catalog Give Whatmore a **product API** — an endpoint that returns a single product's detail — plus any auth it needs: ```bash theme={null} curl https://yourstore.com/products/PRODUCT_IDENTIFIER \ -u YOUR_CONSUMER_KEY:YOUR_CONSUMER_SECRET ``` Whatmore fetches a sample response and you **map fields** to Whatmore's in the dashboard (see [Catalog API → Connect in the dashboard](/integrations/catalog-api#pull-initial-load-and-refresh)): | Whatmore field | Your API field (example) | | ---------------- | ------------------------ | | Product title | `name` | | Product ID / SKU | `id` | | Price | `price` | | Compare-at / MRP | `regular_price` | | Product URL | `permalink` | | Product image | `images[0].src` | | Currency | set manually | Whatmore then pulls product data itself. *(Prefer to push? Use the [Catalog API](/integrations/catalog-api#push-real-time-updates) instead.)* ## 3. Embed the widget In the dashboard, open a surface (e.g. **Homepage → Homepage Video Carousel → Setup**), choose a template, review the live preview, and **copy the generated snippet**. Paste it into your site where you want the surface. For mobile apps, use the [App SDK](/integrations/app-sdk) instead of a web snippet. ## 4. Authentication You receive a **`store_id`** and get a bearer **token** from `GET /auth/access-token?store_id=`. See [Authentication](/integrations/authentication). ## 5. Order tracking Add the order-tracking call to your order-confirmation page. The widget stores video-view / add-to-cart signals in `localStorage`, so the [ready-to-use snippet](/integrations/order-tracking#ready-to-use-snippet-web) picks them up: ```javascript theme={null} async function sendOrderTrackingRequest({ orderId, orderItems, storeId, token }) { const url = `https://api.whatmore.live/external-shop-order-tracking/private?store_id=${encodeURIComponent(storeId)}`; const payload = { order_id: orderId, order_items: orderItems, whatmore_video_view: localStorage._whatmore_viewed_products || "[]", whatmore_add_to_cart: localStorage._whatmore_add_to_cart_products || "[]", }; const res = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` }, body: JSON.stringify(payload), }); if (!res.ok) throw new Error(`Order tracking failed: ${res.status} ${res.statusText}`); return res; } ``` The `product_id` in `order_items[]` must be the **same identifier your product API returns** for that product, so items can be matched to the video signals. See [Order Tracking](/integrations/order-tracking). ## Verify * Products appear in your Whatmore dashboard catalog * Widget renders from the pasted snippet * Order tracking fires on confirmation and attribution shows in the dashboard # Magento / Adobe Commerce Source: https://docs.whatmore.ai/integrations/platform-magento How a Magento 2 / Adobe Commerce store integrates Whatmore — connect your catalog, embed the widget, and report orders. The building blocks are the same as any non-Shopify store; this page maps them onto Magento. ## 1. Connect your catalog Whatmore reads your products through Magento's REST API and you map the fields in the dashboard. Your product endpoint is typically: ```bash theme={null} curl https://yourstore.com/rest/V1/products/SKU \ -H "Authorization: Bearer " ``` In [dashboard.whatmore.live](https://dashboard.whatmore.live/) select **Magento**, enter the endpoint + token, and map fields to Whatmore's (title, `client_product_id`, price, compare-at, product URL, image) — see [Catalog API → Connect in the dashboard](/integrations/catalog-api#pull-initial-load-and-refresh). *(Also push price/stock/image updates via the [Catalog API](/integrations/catalog-api#push-real-time-updates).)* ## 2. Embed the widget In the dashboard, set up a surface, choose a template, and **copy the generated snippet**. Paste it into a custom `.phtml` template or a CMS block where you want the surface (PDP, homepage, category). The snippet is generated for your store — no hardcoded script URL. ## 3. Authentication For order tracking, fetch a bearer token from `GET /auth/access-token?store_id=` server-side (store `store_id` / token in Magento secure config). See [Authentication](/integrations/authentication). ## 4. Order tracking On order placement (e.g. `checkout_submit_all_after` / the order-success page), call [Order Tracking](/integrations/order-tracking) with the order items. The web widget stores video-view / add-to-cart signals in `localStorage`, so the [ready-to-use snippet](/integrations/order-tracking#ready-to-use-snippet-web) picks them up. ## Verify * Products appear in your Whatmore dashboard catalog * Widget renders from the pasted snippet * Order tracking fires on the success page and attribution shows in the dashboard # Salesforce Commerce Cloud (SFCC) Source: https://docs.whatmore.ai/integrations/platform-sfcc How an SFCC (B2C Commerce) store — SFRA or headless PWA Kit — integrates Whatmore. The building blocks are the same as any non-Shopify store; this page maps them onto SFCC. ## 1. Connect your catalog Whatmore reads your products through the SFCC Shopper Products API (SCAPI / OCAPI) and you map the fields in the dashboard. Your product endpoint is typically: ```bash theme={null} curl "https://yourinstance.commercecloud.salesforce.com/.../products/PRODUCT_ID" \ -H "Authorization: Bearer " ``` In [dashboard.whatmore.live](https://dashboard.whatmore.live/) select **Salesforce Commerce Cloud**, enter the endpoint + token, and map fields to Whatmore's (title, `client_product_id`, price, compare-at, product URL, image) — see [Catalog API → Connect in the dashboard](/integrations/catalog-api#pull-initial-load-and-refresh). *(Also push price/stock/image updates via the [Catalog API](/integrations/catalog-api#push-real-time-updates).)* ## 2. Embed the widget In the dashboard, set up a surface, choose a template, and **copy the generated snippet**: * **SFRA:** paste it into an ISML template (PDP, homepage), optionally packaged as a small **cartridge**. * **PWA Kit / headless:** mount it in your React storefront. The snippet is generated for your store — no hardcoded script URL. ## 3. Authentication For order tracking, fetch a bearer token from `GET /auth/access-token?store_id=` server-side (store credentials in SFCC service config). See [Authentication](/integrations/authentication). ## 4. Order tracking On order confirmation, call [Order Tracking](/integrations/order-tracking) with the order items. The web widget stores video-view / add-to-cart signals in `localStorage`, so the [ready-to-use snippet](/integrations/order-tracking#ready-to-use-snippet-web) picks them up. ## Verify * Products appear in your Whatmore dashboard catalog * Widget renders from the pasted snippet * Order tracking fires on confirmation and attribution shows in the dashboard # Shopify Source: https://docs.whatmore.ai/integrations/platform-shopify Shopify merchants use the **native Whatmore app** — there is no manual API or SDK integration to build. **Install the app → you're done.** [**Whatmore on the Shopify App Store**](https://apps.shopify.com/whatmore-live) ## What the app handles for you Once installed, the Whatmore Shopify app wires up everything automatically: * **Widget embedding** — shoppable-video surfaces render on your storefront via the app's theme integration (no manual script). * **Catalog** — your Shopify products sync automatically; no [Catalog API](/integrations/catalog-api) calls needed. * **Order tracking & attribution** — handled through Shopify's checkout / web-pixel integration; no manual [Order Tracking](/integrations/order-tracking) call. You manage videos, tagging, and campaigns in the **[Whatmore dashboard](https://dashboard.whatmore.live/)**, exactly as with any other platform. ## When to use the APIs instead The [Core APIs](/integrations/authentication) and [App SDK](/integrations/app-sdk) in this section are for **non-Shopify** storefronts (Magento, SFCC, WooCommerce, BigCommerce, custom / headless, and mobile apps). If you're on Shopify, you don't need them — install the app above. # WooCommerce Source: https://docs.whatmore.ai/integrations/platform-woocommerce How a WooCommerce (WordPress) store integrates Whatmore. You connect your catalog via WooCommerce's REST API, embed the widget with a dashboard-generated snippet, and report orders for attribution. ## 1. Connect your catalog Whatmore reads your products through the WooCommerce REST API and you map the fields in the dashboard — no export needed. **a. Generate WooCommerce API keys** * WordPress admin → **WooCommerce → Settings → Advanced → REST API → Add key** * Description: `Whatmore Integration`; Permissions: **Read/Write** * Copy the **Consumer key** (`ck_…`) and **Consumer secret** (`cs_…`) Your product endpoint looks like: ```bash theme={null} curl https://yourstore.com/wp-json/wc/v3/products/PRODUCT_ID \ -u ck_your_consumer_key:cs_your_consumer_secret ``` **b. Map fields in the dashboard** In [dashboard.whatmore.live](https://dashboard.whatmore.live/) select **WooCommerce**, enter your endpoint + keys, and map the fields Whatmore fetches from a sample response (see [Catalog API → Connect in the dashboard](/integrations/catalog-api#pull-initial-load-and-refresh)): | Whatmore field | WooCommerce field | | ---------------- | ----------------- | | Product title | `name` | | Product ID / SKU | `id` | | Price | `price` | | Compare-at / MRP | `regular_price` | | Product URL | `permalink` | | Product image | `images[0].src` | | Currency | set manually | ## 2. Embed the widget In the dashboard, set up a surface (e.g. Homepage Video Carousel), choose a template, and **copy the generated snippet**. Paste it where you want the surface — a block, a **Custom HTML** widget, or a theme template (e.g. `single-product.php`). No hardcoded script URL; the snippet is generated for your store. ## 3. Authentication For order tracking you need a `store_id` and a bearer token from `GET /auth/access-token?store_id=`. See [Authentication](/integrations/authentication). ## 4. Order tracking On order completion (`woocommerce_thankyou` or the `woocommerce_order_status_completed` hook), call [Order Tracking](/integrations/order-tracking) with the order items. Use the [ready-to-use web snippet](/integrations/order-tracking#ready-to-use-snippet-web) — the widget already stores video-view / add-to-cart signals in `localStorage`, so the snippet picks them up automatically. ## Verify * Products appear in your Whatmore dashboard catalog * Widget renders from the pasted snippet * Order tracking fires on the thank-you page and attribution shows in the dashboard # Android SDK (Kotlin) Source: https://docs.whatmore.ai/integrations/sdk-android `whatmore-storefront` — drop-in shoppable video for Android. One dependency, three ready-to-embed templates (Reel, Feed, Carousel) that share the same configuration and listener. Available for both **Views/Fragments** and **Jetpack Compose** hosts. It mirrors the [iOS SDK](/integrations/sdk-ios) surface-for-surface. ## Requirements | | Minimum | | ------- | ------------------------------------- | | Android | API 24 (Android 7.0) | | Kotlin | 1.9 | | UI | AndroidX Views **or** Jetpack Compose | ## Install (Gradle) ```kotlin theme={null} // build.gradle.kts dependencies { implementation("ai.whatmore:whatmore-storefront:1.0.0") } ``` ## Configure once Build the config and your listener once, then reuse them across every surface: ```kotlin theme={null} import ai.whatmore.storefront.* val config = WhatmoreStorefrontConfiguration(storeId = "STRNZFBL8TQ") val whatmore = AppWhatmoreListener() // your WhatmoreStorefrontListener ``` ```kotlin theme={null} data class WhatmoreStorefrontConfiguration( val storeId: String, // required — your Whatmore store id val statuses: List = listOf("live", "upcoming"), val theme: WhatmoreStorefrontTheme = WhatmoreStorefrontTheme.Default, val productProvider: ProductProvider = MockProductProvider() ) ``` ## Surfaces ### Reel — full-screen swipe (e.g. a "TV" tab) ```kotlin theme={null} // View val reel = WhatmoreReelView(context).apply { configure(config, startIndex = 0) listener = whatmore } // Fragment val fragment = WhatmoreReelFragment.newInstance(config, startIndex = 0).apply { listener = whatmore } ``` ```kotlin theme={null} // Jetpack Compose WhatmoreReel(configuration = config, startIndex = 0, listener = whatmore) ``` ### Feed — creator / celebrity page ```kotlin theme={null} // View / Fragment WhatmoreFeedFragment.newInstance(config, celebrityName = celebrity.name).apply { listener = whatmore } // Compose WhatmoreFeed(configuration = config, celebrityName = celebrity.name, listener = whatmore) ``` ### Carousel — autoplaying rail ```kotlin theme={null} // View WhatmoreCarouselView(context).apply { configure(config, title = "Trending Videos") // title optional listener = whatmore } // Compose WhatmoreCarousel(configuration = config, title = "Trending Videos", listener = whatmore) ``` Fully-visible cards autoplay muted; tapping opens the Reel at that video (the surface manages its own full-screen presentation). ## Handle events — `WhatmoreStorefrontListener` Implement once and attach to every surface. **Every method has a default no-op** — the SDK never touches a cart, so you decide what each event does. ```kotlin theme={null} interface WhatmoreStorefrontListener { fun onTapAddToCart(product: WhatmoreProduct, event: WhatmoreEvent) {} fun onTapProduct(product: WhatmoreProduct, event: WhatmoreEvent) {} fun onTapViewAllProducts(event: WhatmoreEvent) {} fun onTapCTA(url: Uri, event: WhatmoreEvent) {} fun onToggleLike(isLiked: Boolean, event: WhatmoreEvent) {} fun onToggleSave(isSaved: Boolean, event: WhatmoreEvent) {} fun onTapShare(event: WhatmoreEvent) {} } ``` | Method | Fires from | Meaning | | ---------------------- | ---------- | ---------------------------------------------- | | `onTapAddToCart` | Reel, Feed | "Add to cart" on a product tile | | `onTapProduct` | Reel, Feed | product tile tapped (open PDP) | | `onTapViewAllProducts` | Feed | "View All Products" tapped | | `onTapCTA` | Reel | event call-to-action link tapped | | `onToggleLike` | Reel, Feed | like toggled | | `onToggleSave` | Feed | save / bookmark toggled | | `onTapShare` | Reel, Feed | share tapped (SDK also presents a share sheet) | ```kotlin theme={null} class AppWhatmoreListener : WhatmoreStorefrontListener { override fun onTapAddToCart(product: WhatmoreProduct, event: WhatmoreEvent) { Cart.add(productId = product.id) } override fun onTapProduct(product: WhatmoreProduct, event: WhatmoreEvent) { Router.openPdp(product.id) } } ``` For **attribution**, record `product.id` / `event.eventId` from these callbacks and include them on your [Order Tracking](/integrations/order-tracking) call at checkout. ## Models ```kotlin theme={null} data class WhatmoreProduct( val id: String, val imageUrl: Uri?, val title: String, val price: BigDecimal, val comparePrice: BigDecimal?, // struck-through / original price val currencyCode: String // ISO 4217, e.g. "INR" ) { val priceText: String // localized, e.g. "₹1,299" val comparePriceText: String? // localized, null when no comparePrice } data class WhatmoreEvent( val eventId: Int, val brand: String?, val videoUrl: Uri?, val posterImageUrl: Uri?, val likeCount: Int, val shareCount: Int, val ctaUrl: Uri?, val pageId: Int ) ``` ## Theme ```kotlin theme={null} data class WhatmoreStorefrontTheme( val accent: Color = Color.White, // primary action tint val likeActive: Color = Color.Red // liked-heart tint ) { companion object { val Default = WhatmoreStorefrontTheme() } } ``` ## Product data — `ProductProvider` Products render in the bottom carousels via a provider. The SDK ships `MockProductProvider` (the default) so all surfaces are demoable before product tagging is wired up. Supply your own to render live catalog data — no UI changes required. ```kotlin theme={null} interface ProductProvider { suspend fun products(event: WhatmoreEvent): List } ``` # iOS SDK (Swift) Source: https://docs.whatmore.ai/integrations/sdk-ios `WhatmoreStorefront` — drop-in shoppable video for iOS. One Swift Package, three ready-to-embed templates (Reel, Feed, Carousel) that share the same configuration and delegate. SwiftUI + AVFoundation, no third-party dependencies; works in both UIKit and SwiftUI hosts. ## Requirements | | Minimum | | ----------- | ------- | | iOS | 17.0 | | Swift tools | 5.9 | | Xcode | 15+ | ## Install (Swift Package Manager) ```swift theme={null} dependencies: [ .package(url: "", from: "1.0.0") ], targets: [ .target(name: "YourApp", dependencies: [ .product(name: "WhatmoreStorefront", package: "WhatmoreStorefront") ]) ] ``` ## Configure once Build the config and your delegate once, reuse them across all surfaces: ```swift theme={null} import WhatmoreStorefront let config = WhatmoreStorefrontConfiguration(storeID: "STRNZFBL8TQ") let whatmore = AppWhatmoreHandler() // your WhatmoreStorefrontDelegate ``` ```swift theme={null} public struct WhatmoreStorefrontConfiguration { public init( storeID: String, // required — your Whatmore store id statuses: [String] = ["live", "upcoming"], // events to fetch theme: WhatmoreStorefrontTheme = .default, productProvider: ProductProviding = MockProductProvider() ) } ``` ## Surfaces ### Reel — full-screen swipe (e.g. a "TV" tab) ```swift theme={null} // UIKit let tv = WhatmoreReelViewController(configuration: config, startIndex: 0, delegate: whatmore) // SwiftUI WhatmoreReelView(configuration: config, startIndex: 0, delegate: whatmore) .ignoresSafeArea() ``` ### Feed — creator / celebrity page ```swift theme={null} // SwiftUI WhatmoreFeedView(configuration: config, celebrityName: celebrity.name, delegate: whatmore) // UIKit WhatmoreFeedViewController(configuration: config, celebrityName: celebrity.name, delegate: whatmore) ``` ### Carousel — autoplaying rail (SwiftUI only) ```swift theme={null} WhatmoreCarouselView(configuration: config, title: "Trending Videos", delegate: whatmore) ``` Fully-visible cards autoplay muted; tapping opens the Reel at that video (the view manages its own full-screen presentation). ## Handle events — `WhatmoreStorefrontDelegate` Implement once and pass to every surface. **Every method is optional** (default no-ops) — the SDK never touches a cart, so you decide what each event does. ```swift theme={null} public protocol WhatmoreStorefrontDelegate: AnyObject { func reelsDidTapAddToCart(_ product: WhatmoreProduct, in event: WhatmoreEvent) func reelsDidTapProduct(_ product: WhatmoreProduct, in event: WhatmoreEvent) func reelsDidTapViewAllProducts(in event: WhatmoreEvent) func reelsDidTapCTA(_ url: URL, in event: WhatmoreEvent) func reelsDidToggleLike(_ isLiked: Bool, in event: WhatmoreEvent) func reelsDidToggleSave(_ isSaved: Bool, in event: WhatmoreEvent) func reelsDidTapShare(_ event: WhatmoreEvent) } ``` | Method | Fires from | Meaning | | --------------------------------- | ---------- | ---------------------------------------------- | | `reelsDidTapAddToCart(_:in:)` | Reel, Feed | "Add to cart" on a product tile | | `reelsDidTapProduct(_:in:)` | Reel, Feed | product tile tapped (open PDP) | | `reelsDidTapViewAllProducts(in:)` | Feed | "View All Products" tapped | | `reelsDidTapCTA(_:in:)` | Reel | event call-to-action link tapped | | `reelsDidToggleLike(_:in:)` | Reel, Feed | like toggled | | `reelsDidToggleSave(_:in:)` | Feed | save / bookmark toggled | | `reelsDidTapShare(_:)` | Reel, Feed | share tapped (SDK also presents a share sheet) | ```swift theme={null} final class AppWhatmoreHandler: WhatmoreStorefrontDelegate { func reelsDidTapAddToCart(_ product: WhatmoreProduct, in event: WhatmoreEvent) { Cart.shared.add(productID: product.id) } func reelsDidTapProduct(_ product: WhatmoreProduct, in event: WhatmoreEvent) { Router.openPDP(product.id) } } ``` For **attribution**, record the `product.id` / `event.eventID` from these callbacks and include them on your [Order Tracking](/integrations/order-tracking) call at checkout. ## Models ```swift theme={null} public struct WhatmoreProduct: Identifiable, Hashable { public let id: String public let imageURL: URL? public let title: String public let price: Decimal public let comparePrice: Decimal? // struck-through / original price public let currencyCode: String // ISO 4217, e.g. "INR" // computed: public var priceText: String // localized, e.g. "₹1,299" public var comparePriceText: String? // localized, nil when no comparePrice } public struct WhatmoreEvent: Identifiable, Hashable { public let eventID: Int public let brand: String? public let videoURL: URL? public let posterImageURL: URL? public let likeCount: Int public let shareCount: Int public let ctaURL: URL? public let pageID: Int } ``` ## Theme ```swift theme={null} public struct WhatmoreStorefrontTheme { public init(accent: Color = .white, likeActive: Color = .red) public static let `default` = WhatmoreStorefrontTheme() } ``` ## Product data — `ProductProviding` Products render in the bottom carousels via a provider. The SDK ships `MockProductProvider` (the default) so all surfaces are demoable before product tagging is wired up. Supply your own to render live catalog data — no UI changes required. ```swift theme={null} public protocol ProductProviding { func products(for event: WhatmoreEvent) async -> [WhatmoreProduct] } ``` # React Native SDK Source: https://docs.whatmore.ai/integrations/sdk-react-native `@whatmore-repo/whatmore-storefront` — drop-in shoppable video for React Native. Renders **native** views (not a WebView) and ships three ready-to-embed surfaces (Reel, Feed, Carousel) that share the same configuration and event handlers. It mirrors the [iOS SDK](/integrations/sdk-ios) surface-for-surface. ## Install ```bash theme={null} npm install @whatmore-repo/whatmore-storefront ``` Native peer dependencies to link in your app: `react-native-video`, `react-native-svg`. ## Configure once Wrap your app in `WhatmoreStorefrontProvider` with a configuration and your event handlers; place the surfaces anywhere below it. ```tsx theme={null} import { WhatmoreStorefrontProvider, WhatmoreReel, WhatmoreFeed, WhatmoreCarousel, type WhatmoreStorefrontConfiguration, type WhatmoreStorefrontHandlers, } from '@whatmore-repo/whatmore-storefront'; const config: WhatmoreStorefrontConfiguration = { storeId: 'STRNZFBL8TQ', // required — your Whatmore store id statuses: ['live', 'upcoming'], theme: { accent: '#FFFFFF', likeActive: '#FF3B30' }, productProvider: async (event) => [ /* WhatmoreProduct[] */ ], }; const handlers: WhatmoreStorefrontHandlers = { onTapAddToCart: (product, event) => Cart.add(product.id), onTapProduct: (product, event) => Router.openPDP(product.id), }; {/* app */} ``` ```ts theme={null} interface WhatmoreStorefrontConfiguration { storeId: string; // required statuses?: string[]; // default ['live', 'upcoming'] theme?: WhatmoreStorefrontTheme; productProvider?: (event: WhatmoreEvent) => Promise; } interface WhatmoreStorefrontTheme { accent?: string; // hex, default '#FFFFFF' likeActive?: string; // hex, default '#FF3B30' } ``` ## Surfaces ### Reel — full-screen swipe (e.g. a "TV" tab) ```tsx theme={null} ``` ### Feed — creator / celebrity page ```tsx theme={null} ``` ### Carousel — autoplaying rail ```tsx theme={null} {/* title optional */} ``` Fully-visible cards autoplay muted; tapping opens the Reel at that video (the surface manages its own full-screen presentation). Any surface can also take its own `handlers` prop to override the provider's for that instance. ## Handle events — `WhatmoreStorefrontHandlers` Wire these once on the provider. **Every handler is optional** — the SDK never touches a cart, so you decide what each event does. ```ts theme={null} interface WhatmoreStorefrontHandlers { onTapAddToCart?: (product: WhatmoreProduct, event: WhatmoreEvent) => void; onTapProduct?: (product: WhatmoreProduct, event: WhatmoreEvent) => void; onTapViewAllProducts?: (event: WhatmoreEvent) => void; onTapCTA?: (url: string, event: WhatmoreEvent) => void; onToggleLike?: (isLiked: boolean, event: WhatmoreEvent) => void; onToggleSave?: (isSaved: boolean, event: WhatmoreEvent) => void; onTapShare?: (event: WhatmoreEvent) => void; } ``` | Handler | Fires from | Meaning | | ---------------------- | ---------- | ---------------------------------------------- | | `onTapAddToCart` | Reel, Feed | "Add to cart" on a product tile | | `onTapProduct` | Reel, Feed | product tile tapped (open PDP) | | `onTapViewAllProducts` | Feed | "View All Products" tapped | | `onTapCTA` | Reel | event call-to-action link tapped | | `onToggleLike` | Reel, Feed | like toggled | | `onToggleSave` | Feed | save / bookmark toggled | | `onTapShare` | Reel, Feed | share tapped (SDK also presents a share sheet) | For **attribution**, record `product.id` / `event.eventID` from these handlers and include them on your [Order Tracking](/integrations/order-tracking) call at checkout. ## Models ```ts theme={null} interface WhatmoreProduct { id: string; imageURL?: string; title: string; price: number; comparePrice?: number; // struck-through / original price currencyCode: string; // ISO 4217, e.g. "INR" priceText: string; // localized, e.g. "₹1,299" comparePriceText?: string; // localized, undefined when no comparePrice } interface WhatmoreEvent { eventID: number; brand?: string; videoURL?: string; posterImageURL?: string; likeCount: number; shareCount: number; ctaURL?: string; pageID: number; } ``` ## Product data — `productProvider` Products render in the bottom carousels via `configuration.productProvider`. The SDK ships a mock provider (the default) so all surfaces are demoable before product tagging is wired up. Supply your own to render live catalog data — no UI changes required. ```ts theme={null} productProvider: (event: WhatmoreEvent) => Promise ```