For the complete documentation index, see llms.txt. This page is also available as Markdown.

Player Deck (iOS)

Display Player Deck

Use PlayerDeckView

The PlayerDeckView provides a UIView wrapper for the PlayerDeckFeedViewController.

Integration

  1. Import FireworkVideo.

  2. Instantiate PlayerDeckView and embed it.

The following are the sample codes:

import UIKit
import FireworkVideo

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        self.addPlayerDeckView()
    }

    func addPlayerDeckView() {
        let channelID = "<Encoded Channel ID>"
        let playlistID = "<Encoded Playlist ID>"
        let playerDeckView = PlayerDeckView(source:
            .channelPlaylist(
                channelID: channelID,
                playlistID: playlistID
            )
        )
        playerDeckView.viewConfiguration = getPlayerDeckContentConfiguration()

        playerDeckView.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(playerDeckView)

        NSLayoutConstraint.activate([
            playerDeckView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
            playerDeckView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
            playerDeckView.heightAnchor.constraint(equalToConstant: 500),
            playerDeckView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor)
        ])
    }

    func getPlayerDeckContentConfiguration() -> PlayerDeckContentConfiguration {
        var viewConfiguration = PlayerDeckContentConfiguration()
        viewConfiguration.itemView.autoplay.isEnabled = true
        viewConfiguration.playerView.playbackButton.isHidden = false
        return viewConfiguration
    }
}

Use PlayerDeckSwiftUIView(SwiftUI)

The PlayerDeckSwiftUIView provides a SwiftUI View wrapper for the PlayerDeckFeedViewController.

Integration

  1. Import FireworkVideo.

  2. Instantiate PlayerDeckSwiftUIView and embed it.

The following are the sample codes:

Autosizing (grid layout)

By default the deck fills the frame you give it and scrolls its own content. Autosizing inverts that: with a grid layout (PlayerDeckGridLayout), the deck grows to the full height of its content, reports that height as its intrinsic content size, and lets your scroll view do the scrolling. That is what you want when the deck is one block inside a longer page.

Pass autosizingEnabled: true when you create the view.

In SwiftUI, place it in your ScrollView without a .frame(height:).

What autosizing changes

  • The deck stops scrolling internally and reports its content height as its intrinsic content size. Do not give it a fixed height constraint or .frame(height:).

  • At most 20 videos are rendered — one page. A grid grows taller with every page loaded, so it has to stay bounded. Set fetchConfiguration.maxVideos to show fewer; a value above 20 is clamped back to 20. This cap applies only to an autosized grid — without autosizing, or with a row layout, maxVideos is not limited.

Content Source

Please refer to Video Feed Content Source (iOS).

Custom Call-To-Action Button Handling

Custom Call-To-Action button handling is done via the FireworkVideoCTADelegate protocol. This provides control over what occurs when a call-to-action button is tapped.

  1. Set the delegate:

2. Conform to protocol:

Widget-Level Product Hydration

We support widget-level product hydration in the player deck through the onProductHydration closure. This process is triggered immediately after the widget data has finished loading. For more details, please refer to the code snippets below.

Why Is Widget-Level Product Hydration Required?

In the player deck, multiple videos may be displayed at the same time, and each video can have its own associated products.

The existing global product hydration mechanism is limited to handling product data for only one video at a time, which becomes a bottleneck in multi-video scenarios.

Widget-level product hydration removes this limitation by enabling the host app to hydrate product data for multiple videos concurrently, ensuring that products across different videos can be processed simultaneously.

Can We Implement Only Widget-Level Product Hydration?

No. In general, global product hydration should be implemented by default. Widget-level hydration is currently supported only in the player deck. If you need to hydrate products for other widgets—such as Video Feed, Circle Story, or Story Block—global product hydration is required.

Widget-level product hydration is designed specifically for multi-video product scenarios. It is triggered immediately after the widget data has finished loading and operates within a limited scope.

It is not intended to replace global product hydration. Instead, it addresses a specific use case within the player deck.

Therefore, widget-level hydration should be considered a complementary mechanism rather than a full replacement for global product hydration.

One-Tap Add to Cart

Player Deck product cards can show a one-tap Add to Cart button that adds the exact unit shown on the card to your cart without opening the product detail page. The button is hidden by default; it appears only when you assign FireworkVideoSDK.shopping.playerDeckAddToCartDelegate and set viewConfiguration.itemView.addToCartButton.isHidden = false, both before the player deck is created.

For the delegate contract, the 10-second reporting window and the full sample code, please refer to Player Deck one-tap Add to Cart.

Force Refresh

A PlayerDeckView or PlayerDeckSwiftUIView can be forced to refreshed by calling the refresh() method on the instance that should be refreshed. This functionality is useful if your feed is embedded along with other components that are also updated and you support features like pull to refresh.

Receive video feed events

  1. Set the delegate

  1. Conform to PlayerDeckFeedViewControllerDelegate protocol

Receive onVideosLoaded callback

The onVideosLoaded closure is called whenever videos are loaded into the player deck feed, including the initial page and every subsequent page loaded via pagination. The closure receives a PlayerDeckVideosLoadedInfo value whose videos property contains the [VideoDetails] that were loaded for that page.

Use PlayerDeckView

onVideosLoaded is exposed as a property on PlayerDeckView:

Use PlayerDeckSwiftUIView(SwiftUI)

onVideosLoaded is exposed as an initializer parameter on PlayerDeckSwiftUIView:

Autoplay

Autoplay lets the player deck automatically start playing eligible thumbnails without requiring user interaction. It is controlled per item by:

This is the prerequisite for everything below — it is true by default, so autoplay is on out of the box.

Player Deck's autoplay is viewport-based by default, which delivers a seamless experience when the component is embedded within a ScrollView, TableView, or CollectionView. The first item whose visibility within the viewport is greater than or equal to viewConfiguration.itemView.autoplay.triggerVisibilityPercentage starts playing automatically; when no item meets the threshold, playback pauses.

When the player deck is embedded in your own scroll container, the viewport is clipped to that container automatically — a deck scrolled out of it correctly pauses, with no extra configuration. The viewport itself is customizable via safeAreaEdges (see below).

Customize viewport

The default viewport is defined as the screen bounds minus the safe area insets—such as the status bar, top navigation bar, bottom tab bar, and bottom home indicator.

The viewport is then clipped to whatever your own layout hides. The SDK walks up from the player deck and intersects the bounds of every ancestor view that clips its content, so a player deck scrolled out of your scroll container — or hidden behind a header stacked above that container — is measured as not visible. This is automatic and needs no configuration.

If you want only some safe-area edges excluded, narrow them with safeAreaEdges.

Player Deck configurations

Please refer to Player Deck Configurations (iOS).

Player configurations

Please refer to Player configurations (iOS).

Last updated

Was this helpful?