Live MarketSDK docs
Developer guide · Binary integration

Video commerce, in your iOS app.

Integrate the compiled LiveMarketSDK with a native player surface, a fixed WebView renderer, and your own cart. You do not need SDK source to use its public Swift API.

iOS 18+Swift 6SwiftUI + UIKitCompiled XCFramework
01

Quick start

Set up the host app first. Then create one player for one screen.

  1. Add the binary package. Check its archive SHA-256 against the release record. Extract it. In Xcode, use File > Add Package Dependencies > Add Local. Select the extracted binary package folder. Add LiveMarketSDK to the app target.
  2. Set the app target. Use iOS 18 or later, Swift 6, and Xcode 26 or later. Add WKAppBoundDomains to the app target's Info.plist.
  3. Create the configuration. Supply the tenant client ID and content token through the host's approved secret path. Pick one environment and cart mode.
  4. Install the cart callback. Set onAddToCart before load(_:).
  5. Own the lifecycle. Keep the player on the main actor for the screen lifetime. Call destroy() when ownership ends.

The binary package contains an XCFramework and a small Package.swift. The separate integration archive contains Markdown guides and the host integration skill. This website contains the HTML guide.

The host app requires iPhone 12 or newer. Use the same approved archive and SHA-256 in each build configuration and CI run. Keep the extracted package path available to CI.

Info.plist
<key>WKAppBoundDomains</key>
<array/>

An empty array is valid for this player. Keep domains that other host WebViews need. Do not add a broad App Transport Security exception.

Swift · minimum host setup
import LiveMarketSDK

let business = try LiveMarketBusiness(
    clientID: clientID,
    contentToken: contentToken
)
let config = LiveMarketSDKConfiguration(
    environment: .staging,
    business: business,
    cartMode: .message
)
let selection = try LiveMarketSelection(placementTag: placementTag)
let player = LiveMarketPlayer(configuration: config)

player.onAddToCart = { request in
    guard !Task.isCancelled else {
        return .rejected(message: "Cart request canceled.", retryAllowed: true)
    }
    // Apply request.requestID at most once in the host cart.
    return .rejected(message: "Connect the host cart.", retryAllowed: true)
}
player.load(selection, presentation: .single)

Use LiveMarketPlayerView(player:) in SwiftUI. Use LiveMarketPlayerUIView(player:) in UIKit. The view displays native controls and products around the video renderer.

SwiftUI · attach the view
LiveMarketPlayerView(player: player)
    .frame(height: player.height)
UIKit · attach the view
let playerView = LiveMarketPlayerUIView(player: player)
playerView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(playerView)
NSLayoutConstraint.activate([
    playerView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
    playerView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
    playerView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
    playerView.heightAnchor.constraint(equalToConstant: player.height)
])
02

How it works

The host owns the app. Native SDK code owns content review, player state, cart handoff, and analytics. A locked WebView plays the selected video.

Host app

Owns business actions

Supplies credentials, consent, screen lifetime, cart service, checkout, and approved image origins.

Native SDK

Checks and coordinates

Loads and reviews placement data. Renders lists, controls, and product cards. Validates cart requests. Sends consented analytics.

WebView

Plays video

Loads fixed bundled HTML, CSS, and JavaScript. Plays approved media. Reports bounded playback messages to native code.

Load path

The SDK requests the selected placement with the content token. It checks the first page, its videos, resource URLs, and the requested presentation before it mounts the fixed local renderer. For a grid, it checks each later page before it adds those videos. The WebView does not receive the content or collector token. Native code accepts only validated bridge messages from the current player generation.

What is native?

Carousel, grid, feed selection, preview cards, product cards, playback controls, state, cart handoff, analytics, and diagnostics are native. The video element and its media events run inside the bundled WebView. The SDK keeps network origins and bridge commands fixed.

Boundary. The SDK rejects an unreviewed origin, changed placement, stale message, or invalid cart relationship. The host must not turn rejected content into a direct WebView URL.

03

Configuration

Create a new immutable configuration for each tenant and environment.

InputOptionsUse
environment.staging, .productionChooses the fixed content and collector service profile.
businessLiveMarketBusiness(clientID:contentToken:collectorToken:)Use one tenant's credentials. A separate collector token is required when analytics is enabled.
cartMode.message, .get, .postFixes the host cart adapter mode for this player. The SDK sends no cart URL.
analytics.disabled by default, .enabledEnabled only permits analytics after host consent.
productImageOriginsUp to eight exact HTTPS originsAdd only reviewed product image origins. Invalid values are filtered.
styleLiveMarketPlayerStyleSets native accent, text, surface, price colors, and type design.
selectionplacementTag, optional contentLanguageSelects one placement. The language asks the service for multilingual content. It does not change UI text.

The SDK uses the app locale for its native control text. English and Polish are bundled. Other locales use English.

Swift · optional style and analytics
let style = LiveMarketPlayerStyle(
    accent: LiveMarketColor(red: 18, green: 96, blue: 180),
    text: LiveMarketColor(red: 20, green: 20, blue: 20),
    surface: LiveMarketColor(red: 255, green: 255, blue: 255),
    price: LiveMarketColor(red: 160, green: 24, blue: 40),
    typeDesign: .rounded
)
let business = try LiveMarketBusiness(
    clientID: clientID,
    contentToken: contentToken,
    collectorToken: collectorToken
)
let config = LiveMarketSDKConfiguration(
    environment: .staging,
    business: business,
    cartMode: .post,
    analytics: .enabled,
    productImageOrigins: ["https://images.example.com"],
    style: style
)
let selection = try LiveMarketSelection(
    placementTag: placementTag,
    contentLanguage: "pl"
)

Style affects SDK-owned native UI. It does not change the renderer or network policy. Use host-managed secret delivery. A mobile app user can inspect an app-owned token, so the service must limit its authority and support rotation.

04

Presentations

SurfaceLoad callBehavior
Singleload(selection, presentation: .single)Shows one returned video and its products.
Carouselload(selection, presentation: .carousel)Shows a horizontal preview list. Tap or select a video to open fullscreen playback.
Gridload(selection, presentation: .grid)Shows two columns. Tap or select a video to open fullscreen playback. Loads up to 50 videos first and the next page near the end. Loads visible covers and offers a retry control if a page fails.
Feedload(selection, presentation: .feed, startingAt: index)Shows one active video. Swipe or select the next or previous video.
Server choiceload(selection)Uses a validated single, carousel, or grid component.

A feed needs a carousel or grid placement with at least two videos. The requested presentation must match the service component. A new load replaces the old generation and cancels its work. A new video starts muted. Carousel and grid lists do not play until a video opens.

Fullscreen playback

Carousel and grid open fullscreen while the selected video loads. Swipe left for the next video. Swipe right for the previous video. The list does not wrap at either end. The same fullscreen surface stays open when the video changes.

At the end of the loaded grid videos, a forward swipe requests the next page. The current video stays open while the SDK reviews that page. The SDK opens the next video only after review succeeds. Swipe again after a failed page request to retry.

Swipe up or down, or use Close video, to close playback and return to the same list position. Playback and product controls keep their own gestures. Call closeActiveItem() to close the video from host code. Closing a carousel or grid video pauses playback.

Single video uses a manual fullscreen button. Exit returns the video to its inline view. Feed uses vertical swipes to change videos. The unused inline renderer space is transparent. The fullscreen background is black.

iOS host lifecycle. The SDK presents fullscreen with .overFullScreen. Keep the player alive during this presentation. In viewWillDisappear(_:), pause only when the screen leaves for another reason. Call destroy() when ownership ends.

UIKit · preserve fullscreen playback
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    if presentedViewController?.modalPresentationStyle != .overFullScreen {
        player.pause()
    }
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    if isMovingFromParent || isBeingDismissed {
        player.destroy()
    }
}

If a custom container removes the controller, its owner must call destroy(). In SwiftUI, pause on a temporary disappearance if the host keeps the screen for later use. Destroy the player only when the screen lifetime ends.

Use itemCount for reviewed videos now loaded. Use totalItemCount for the reported total. The SDK accepts up to 500 videos in ten pages of 50. A grid requests the next page as the shopper nears the end of the loaded cards. It loads covers for visible cards and releases distant covers.

Grid paging tradeoff. Loading 50 videos at a time reduces the first response size, review work, and cover memory use. Scrolling to a new page adds a network wait. A failed page has a retry control.

For more than 50 videos, set Sort type to Date. Manual is available when Filter type is Select shorts. A one-page grid can use the service's default sort. A grid that needs another page rejects an unset sort with selectionSortNull because the service can shuffle each request. An explicit Random sort can repeat or omit videos. Content changes between requests can also move page boundaries.

The SDK limit is 500 videos. The panel limits an entered Maximum quantity value to 100. Leave this setting empty when a placement needs more than 100 videos.

05

Cart handoff

The SDK validates the selected product and variant. Your host app changes the cart.

ModeHost action
.messageApply the typed request in app code or a host service.
.getMap the reviewed data to a host-approved GET endpoint and query.
.postMap the reviewed data to a host-approved POST endpoint and body.

LiveMarketCartRequest has generation, requestID, mode, contentID, optional viewID, productID, variantID, parameter, and quantity. Quantity is one in this version. Treat parameter as private data. Never open it as a URL.

Swift · host cart callback
player.onAddToCart = { request in
    guard !Task.isCancelled else {
        return .rejected(message: "Canceled.", retryAllowed: true)
    }
    do {
        // hostCart applies request.requestID at most once.
        try await hostCart.apply(request)
        return .accepted(message: "Item added to cart.")
    } catch {
        return .rejected(message: "Could not add item.", retryAllowed: true)
    }
}

Check cancellation again just before the cart mutation. Apply each requestID at most once. The SDK runs one request at a time and allows 15 seconds for a result. It cancels old work on replacement or destroy. An accepted cart result does not mean checkout or payment succeeded.

06

Analytics and consent

Analytics is off by default. The host app owns the consent decision.

  1. Configure. Set analytics: .enabled and supply a collector token that differs from the content token.
  2. Grant. Call grantAnalyticsConsent(userID:) only after the shopper agrees. Grant before load when possible.
  3. Update. Call denyAnalyticsConsent() on withdrawal. Use reset, new session, or user ID methods when host identity changes.
  4. Reload. Load the placement again after an identity change to start a new analytics view.

The SDK builds and sends its analytics events in native code. The WebView does not receive the collector token. Do not send a second copy of the SDK funnel from the host. The queue is memory only and bounded to 100 events. The host owns deletion requests for events already accepted by the collector.

LiveMarketAnalyticsIdentityManager(scope:) is available when the host needs one consent owner for the same tenant across players and windows. Use a stable tenant scope. Do not use a shopper ID as the scope. The player exposes matching consent methods for ordinary screen integration.

07

Public API reference

Call player and identity methods on the main actor. Set the cart callback before load.

Constructors and views

APIHow to use it
LiveMarketBusiness(clientID:contentToken:collectorToken:)Create one tenant's credential value. collectorToken is optional unless analytics is enabled.
LiveMarketSDKConfiguration(environment:business:cartMode:analytics:productImageOrigins:style:)Create the fixed player configuration. The last three inputs have defaults.
LiveMarketSelection(placementTag:contentLanguage:)Select a placement. Set contentLanguage only for multilingual service content.
LiveMarketPlayer(configuration:)Create on the main actor. Keep it for the screen lifetime.
LiveMarketPlayerView(player:)Attach the player to a SwiftUI view.
LiveMarketPlayerUIView(player:)Attach the player to a UIKit view.
LiveMarketColor(red:green:blue:)Set eight-bit RGB channels for native UI colors.
LiveMarketPlayerStyle(accent:text:surface:price:typeDesign:)Set native colors and .system, .rounded, or .serif type design.

Player methods

MethodWhen to call it
load(_ selection)Use the validated server surface. Replaces the current generation.
load(_:presentation:)Require .single, .carousel, .grid, or .feed.
load(_:presentation:startingAt:)Open a feed at a validated zero-based index.
play(), resume()Start or resume active media while the app is foregrounded. A user gesture can be required.
pause()Pause media. Keep the selection.
seek(to:)Seek in seconds after duration is known. Invalid values are ignored.
replay()Return to zero and play the current video.
setMuted(_:)Mute or unmute the current video. System volume does not change.
selectItem(at:)Open a reviewed video at a loaded index. Carousel and grid open fullscreen.
closeActiveItem()Close an open carousel or grid video and pause it.
addToCart(productID:variantID:)Submit a reviewed product and variant from a host-owned product control.
retry()Retry the last selection as a new generation.
grantAnalyticsConsent(userID:)Grant after host consent. The optional user ID stays in memory.
denyAnalyticsConsent()Revoke consent and clear this tenant's stored analytics identity.
resetAnalyticsIdentity()Rotate anonymous and session IDs while consent stays granted.
startNewAnalyticsSession()Rotate the memory-only session at a host session boundary.
setAnalyticsUserID(_:)Set or clear a consented, memory-only host user ID.
destroy()Cancel work, stop media, and release the player. It is terminal.

Player values and callback

ValueWhat it tells the host
onAddToCartAsync host callback. Return .accepted(message:) or .rejected(message:retryAllowed:).
state, progress, isMuted, commerceCurrent lifecycle, media time and frames, mute state, and cart eligibility.
presentation, contentID, generationCurrent surface, active content ID, and load generation.
itemCount, totalItemCount, activeItemIndex, isPlayerOpenLoaded and total item counts, selected index, and open video state.
height, isViewReadySuggested view height and whether a view surface exists. Ready does not prove that media can play.
cartMessage, analyticsConsentLast bounded cart result and current consent.
unapprovedProductImageOriginsExact selected-video image origins that need host review. Recreate the player after approval.
reportBounded diagnostic snapshot. report?.text gives JSON text. contentReviewFailure names a failed page and check without response data.

Identity manager methods

APIUse
LiveMarketAnalyticsIdentityManager(scope:)Get shared state for a stable tenant scope.
grantConsent(userID:), denyConsent()Grant or revoke consent outside a player screen.
resetIdentity(), startNewSession()Rotate anonymous identity or session.
setUserID(_:)Set or clear the memory-only user ID under consent.
consent, identityRead current consent and optional anonymous, session, and user IDs.

For failures, switch on LiveMarketPlaybackState.failed(error). Use error.code, error.message, and error.retryAllowed. The state also has .idle, .loading, .ready, .playing, .paused, .ended, and .destroyed. Use state.label for a short localized label.

08

Integration skill

The repository includes one host integration skill for an agent working in a customer iOS app.

  1. Copy. Copy the full live-market-ios-integration skill folder from the integration archive into the customer app's .agents/skills/ directory.
  2. Start in the host app. Run $live-market-ios-integration there. Read the host app's agent instructions first.
  3. Give release inputs. Use the pinned SDK binary, archive SHA-256, release record, tenant, placement tags, cart mode, and consent choice. Do not paste raw tokens into chat.
  4. Validate. Use the skill's feature map and validation matrix. Record pass, fail, or blocked for each applicable row.

The skill guides package setup, environment selection, every presentation, cart handoff, analytics consent, lifecycle, and release checks. It works in the host app. Its pinned release documentation and public Swift declarations control a customer integration.

09

Validation and limits

Check

Binary pin

Match the archive SHA-256 and version to the approved release record in every host build.

Check

iOS host

Run the host app on a simulator and required devices. Check each used surface, cart mode, consent path, and lifecycle.

Limit

Current release

Prerecorded clear video only. No live video, DRM, checkout, payment, stories, forms, or polls.

Test fullscreen entry while the video loads. Test next and previous videos, grid page loading, page retry, and each close action. Check that closing playback keeps the list position. Check playback and product gestures. Keep the player alive while the SDK fullscreen view is open.

Shell · package tests
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer \
  swift test --scratch-path /tmp/live-market-ios-sdk-tests

This command is for SDK maintainers with the source checkout. The macOS target does not exercise the iOS player. The media policy permits exact reviewed Mux hosts, including Google Cloud US East 1 hosts on edgemv.mux.com and fastly.mux.com. A customer app needs its own host tests and an approved release record. See the README for current behavior and release limits.

iOS SDK documentation · View source