Apple TV App and Universal Search Video Integration Guide

The Apple TV app lets you browse content from a variety of video services without switching from one app to the next. It provides movies, shows, and handpicked recommendations. The app is on iOS and tvOS devices— so you can watch wherever you go.

  • Your app should be available on both tvOS (for Apple TV) and iOS (for iPhones and iPads).
  • Your app should offer long-form content (such as movies or series)
  • For sports content and event-based streams in the United States and Canada, we support linear channels.
  • You need to provide detailed information (metadata) about all the long-form, stand-alone, and episodic content available in your app.
  • You must also provide artwork for your content that meets Apple specifications. This is required especially if the content is not available from any other provider in a particular country.
  • Finally, you should be ready to submit your app builds to Apple's testing teams through TestFlight for testing purposes.

3. Integration Process for your Data Feed

3.1 Brand Registration

A search brand is like a collection of video services that belong to one company. Each video service is a catalog of on-demand content that customers can watch if they have access to the service. If some content is only available in specific countries, multiple video services are used.

  • Brand Name: [You need to provide a brand name for your collection of video services.]
  • Application Apple ID: [You need to provide the Apple ID for the application.]
  • Participating Territories: [You need to list the countries or territories where your video services are available.]
  • Top 25 TV Shows and Movies in the App: [You should prepare a list of the 25 most popular TV shows and movies available in your app.]

After you register your brand with Apple, you'll need to integrate the data about your media content and make sure the feed is accurate. This data will be used by Siri for Universal Search, making it easier for users to find your content.

3.2 Data Integration

  • Adopt the UMC Catalog Data Interface Specification ("Catalog Feed") and the UMC Availability Data Interface Specification ("Availability Feed"). The Catalog Feed provides factual information about your app's content, like Title, Description, Release Date, and Cover Artwork. The Availability Feed describes how and when users can access the content through deep links and window definitions.
  • Validate your XML feed using the provided XSD and macOS Media Feed Validator. Ensure there are no XSD errors and no "Errors" or "Warnings" from the Media Feed Validator. Also, make sure your Catalog Feed follows the UMC Standards and Style Guide for Apple's quality standards.
  • Provide Apple with URLs where they can access your Availability and Catalog feeds for each service.
  • Apple will review the XML structure, content, and metadata quality of your feeds. They'll categorize any issues found as Must Fix or Should Fix.
  • After resolving all Must Fix issues, Apple will ingest your feed into the Universal Media Catalog in "Isolation Mode". This allows them to simulate mapping your metadata and validate its quality. They'll provide a report with any issues categorized as Must Fix or Should Fix.
  • Next, Apple will ingest your feed into the Universal Media Catalog in "Mapping Mode". This prepares Siri for Natural Language Processing of your catalog items. This process usually takes around 3 to 6 weeks.
  • Implement the UMC Partner Manifest Data Interface to configure catalogs and availability services in the UMC platform. The partner manifest is a collection of configurations for your content provider's catalogs and availability services. This data is delivered to Apple's video content platform through the UMC Data Ingest Service.

3.3 Client App Integration

Complete the following client integrations on both tvOS and iOS as described in Apple TV App and Universal Search:

3.3.1 Request Extended Entitlements

Before proceeding, talk to your technical contact at Apple and ensure that your developer account has been registered as a Universal Search partner. If it has not, send your Developer account Team ID to your Apple contact. Apple will grant your Apple Developer Team ID an extended entitlement, allowing your apps to utilize the Subscription Registration API. This entitlement becomes accessible when you create Provisioning Profiles from the Developer Portal. However, it's important to note that you'll need to handle profile management manually for your app.

3.3.2 Adding to Info.plist for the Apple TV App

To indicate that your app is compatible with the Apple TV app, you must add this new key to your application Info.plist file. Once you have implemented the Apple TV app into your application, your app will be rejected by App Review if this key is missing.

3.3.3 Subscription Registration

Informs the Apple TV app and Universal Search that a user is entitled to watch content within your app. The subscription registration API is provided via the VSSubscriptionRegistrationCenter class in the VideoSubscriberAccount framework. Upon user sign in to your service, your app must register a subscription whose expiration date is Date.distantFuture. In addition, the subscription information should be refreshed on every app launch.

Note - If your app consists of both free and paid content, the subscription registration API should only be implemented for paid users.

let subscription = VSSubscription()
subscription.expirationDate = Date.distantFuture
let registrationCenter = VSSubscriptionRegistrationCenter.default()
registrationCenter.setCurrentSubscription(subscription)

When the user signs out, your app must remove the subscription:

let registrationCenter = VSSubscriptionRegistrationCenter.default()
registrationCenter.setCurrentSubscription(nil)

3.3.4 Supporting the UMC Availability 3.0 Spec

The UMC Availability 3.0 spec uses the type, availabilityType, to support tiered subscription models. It is your responsibility to update the subscription any time the user entitlements change, such as when the user purchases a new add-on, removes an add-on, cancels a subscription or signs out of the app.

When registering a subscription with tiers, set the access level, tiers, and billing identifier if applicable.

The billingIdentifier is only used for regional content restrictions, most often in the context of live sports, where some live sporting events are only available to customers in specific regions of the same country. It is generally a hashed zip code.

Note: The tiers and access level values must match the values provided in your availability feed, including casing.

subscription.accessLevel = .paid
subscription.tierIdentifiers = ["Tier1", "Tier2"]
subscription.billingIdentifier = hashedBillingIdentifier

For more information, see the VSSubscription.h header file.

3.3.5 Now Playing API

Informs Apple TV app what content a user is watching in your app and the user’s current playback progress. Enables Siri functionality that allows the user to ask questions about content during video playback. For debugging Now Playing, the Now Playing Logger is a drop-in class that can be used to log changes to the Now Playing Info.

This is done in two different ways, depending on whether or not you are using AVKit:

  • For AVKit (AVPlayerViewController) on tvOS, populate the metadata array of an AVPlayerItem using instances of AVMetadataItem. AVKit on iOS still requires manual reporting (see 2).
  • For iOS and non-AVKit tvOS, use the MPNowPlayingInfoCenter to manually report playback activity

3.3.5.1 Expected Metadata

The metadata expected is different depending on the type of playback. Below is a matrix that identifies which properties should be provided for each type of supported playback. Depending on your app’s platform and AVKit usage, either all or a subset of these properties will need to be provided by you.

Note: Properties that are marked as No must not be included for the given content type.

Property Type Description VOD EBS** Live
Duration Integer The duration (net time) of the asset in seconds Yes No No
Elapsed Time Integer The current playback progress offset in seconds, excluding interstitial content Yes No No
Playback Rate Float The rate of playback0 for paused, 1 for playing Yes Yes Yes
Current Playback Date Date The date of the current playback location. Must be set to the value of the AVPlayerItem’s currentDate property. Note that the content being played must have been authored such that its HLS playlist includes the EXT-X-PROGRAM-DATE-TIME tag. No Yes Yes
Content Identifier* String The unique identifier for the playing asset Yes Yes No
Service Identifier* String The unique service identifier for live streams No No Yes
Is Live Stream Integer Indicates if the currently playing asset is live.0 for false, 1 for true No Yes Yes
Playback Progress Float Used to indicate the playback progress of the currently playing asset. 0.0 for no progress, 1.0 for completed to credits start.Note: if the credit start time is not known, this metadata item must not be provided at all. Optional No No

* The Content Identifier and Service Identifier must match the identifiers provided in the Universal Search availability feed.
** EBS: Event Based Stream

3.3.5.2 AVKit tvOS Integrations

Implementing Now Playing Info when you are using AVKit (AVPlayerViewController) is easy — AVKit has done the bulk of the heavy lifting for you, providing the majority of the metadata properties.

Note: For your AVPlayerViewController, the showsPlaybackControls property must always be true.

You are still responsible for providing the Content Identifier or Service Identifier and Playback Progress (if applicable).

Property Constant
Service Identifier AVKitMetadataIdentifierServiceIdentifier
Content Identifier AVKitMetadataIdentifierExternalContentIdentifier
Playback Progress AVKitMetadataIdentifierPlaybackProgress

If you intend to provide additional metadata (for example, to populate the HUD), see the `AVPlayerItem.h`` header file for common metadata properties.

Below is an example of adding metadata properties for the VOD content type:

let videoURL = NSURL(string: "https://example.com/video_manifest.m3u8")
let playerItem = AVPlayerItem(url: videoURL)

// title
let metaTitle = AVMutableMetadataItem()
metaTitle.identifier = AVMetadataCommonIdentifierTitle
metaTitle.extendedLanguageTag = "en"
metaTitle.value = "Example Title"

// content id
let metaContentId = AVMutableMetadataItem()
metaContentId.extendedLanguageTag = "en"
metaContentId.value = "example_content_id"
metaContentId.identifier = AVKitMetadataIdentifierExternalContentIdentifier

// playback progress
let metaPlaybackProgress = AVMutableMetadataItem()
metaPlaybackProgress.extendedLanguageTag = "en"
metaPlaybackProgress.value = 0
metaPlaybackProgress.identifier = AVKitMetadataIdentifierPlaybackProgress

// set metadata
playerItem.externalMetadata = [metaTitle, metaContentId, metaPlaybackProgress]

Once the metadata properties have been added to your AVPlayerItem externalMetadata property, AVKit handles updating the Now Playing Info for you.

3.3.5.3 iOS and non-AVKit tvOS Integration

Implementing Now Playing Info on iOS and on tvOS when you are not using AVKit requires four pieces:

3.3.5.3.1 Registering for Remote Commands

As noted above, registering for remote commands is required in order for iOS and tvOS to recognize Now Playing Info updates. You must register for at least one remote command, but we recommend registering for as many of the available remote commands as your player, and the respective content type, supports. It is also the mechanism to receive commands such as pause, resume, and seek from the lock screen, Control Center, and external accessories.

let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.pauseCommand.isEnabled = true
commandCenter.pauseCommand.addTarget { (event) -> MPRemoteCommandHandlerStatus in
     // pause your player
     return .success
}
commandCenter.seekForwardCommand.isEnabled = true
commandCenter.seekForwardCommand.addTarget { (event) -> MPRemoteCommandHandlerStatus in
     // seek forward
     return .success
}
commandCenter.seekBackwardCommand.isEnabled = true
commandCenter.seekBackwardCommand.addTarget { (event) -> MPRemoteCommandHandlerStatus in
     // seek backward
     return .success
}

3.3.5.3.2 Disable AVKit Now Playing Updates

AVKit on iOS does not allow you to provide the extended metadata properties required by the Apple TV App. Therefore, you must disable AVKit from sending Now Playing Info updates to prevent it from interfering with your manual updates.

self.playerViewController.updatesNowPlayingInfoCenter = false

3.3.5.3.3 Send Now Playing Info Updates

Once playback has been initiated, you must update the Now Playing Info with the required metadata properties for the content type.

Note: To aid in development, we strongly recommend using the NowPlayingLogger class during debugging, which allows you to see the same Now Playing Info changes that Apple will see during validation.

Event Property Updates
Video Start MPNowPlayingInfoPropertyExternalContentIdentifier set to the content identifier that matches the identifier provided in the availability feed
Video Start MPMediaItemPropertyPlaybackDuration set to the net duration of the content in seconds
Video Start MPNowPlayingInfoPropertyPlaybackRate set to 1.0
Video Start MPNowPlayingInfoPropertyElapsedPlaybackTime set to the playback offset in seconds
Play MPNowPlayingInfoPropertyPlaybackRate updated to 1.0
Pause MPNowPlayingInfoPropertyPlaybackRate updated to 0
Pause MPNowPlayingInfoPropertyElapsedPlaybackTime updated to the playback offset in seconds
Seek MPNowPlayingInfoPropertyElapsedPlaybackTime updated to the playback offset in seconds
Video completion or player dismissal nowPlayingInfo dictionary set to nil

Now Playing Info updates should only be sent on the events listed above, and not at an arbitrary interval.

For example, when playback begins for a VOD asset, you might send an initial Now Playing Info update with the content ID:

let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
var nowPlayingInfo = [String: Any]()
nowPlayingInfo[MPMediaItemPropertyTitle] = "WWDC 2016"
nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = durationInSeconds
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = elapsedTimeInSeconds
nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = 1.0
if #available(iOS 10.0, *, tvOS 10.0, *) {
     nowPlayingInfo[MPNowPlayingInfoPropertyExternalContentIdentifier] = contentId
     nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackProgress] = 0.0
}
nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo

When the user pauses the player, you would send another update using the existing dictionary, and updating the values for elapsed time and playback rate:

let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
var nowPlayingInfo = nowPlayingInfoCenter.nowPlayingInfo
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = elapsedTimeInSeconds
nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = 0.0
nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo

3.3.5.3.4 Unregister for Remote Commands

Once the player is dismissed, you must unregister for the remote commands that were registering before playback started.

commandCenter.pauseCommand.isEnabled = false
commandCenter.pauseCommand.removeTarget(nil)
commandCenter.seekBackwardCommand.isEnabled = false
commandCenter.seekBackwardCommand.removeTarget(nil)
commandCenter.seekForwardCommand.isEnabled = false
commandCenter.seekForwardCommand.removeTarget(nil)

3.3.6 NSUserActivity

Enables Siri functionality that allows a user to ask Siri to Add this to my Up Next from within your app. This allows users to easily add content to their Up Next queue in the Apple TV App. If your app does not have a details view for an asset, then NSUserActivity should not be implemented.

An NSUserActivity object must remain in memory for the duration of its lifetime, so it's important to retain a strong reference to the object. Generally, apps set the NSUserActivity object as a property of the details view controller. In your details view controller's viewWillAppear delegate:

self.userActivity = NSUserActivity(activityType: "com.developer.app.details")
self.userActivity.externalMediaContentIdentifier = "content_id"
self.userActivity.becomeCurrent()

In your details view controller's viewWillDisappear delegate:

self.userActivity.invalidate()

For TV shows, the externalMediaContentIdentifier can be set to the content ID for the series, season, or episode.

3.3.7 Deep Linking

Allows the Apple TV app and Universal Search to launch your app for content playback and viewing product pages. Your deep links for playback should accept an optional resumeTime parameter in seconds and start the user at the appropriate time in the video. If you would like to track deep links that originate from the Apple TV app and Universal Search, be sure to include a unique campaign parameter to the deep links you provide in the feed and parse that value in your URL handler code for tracking. There are two methods of implementing deep links on iOS and tvOS:

  • Universal Links (recommended): Universal links allow your app to handle standard HTTP URLs that would traditionally be handled by a browser. This allows you to use the same URLs for your app as you currently do on the web.

  • Custom URL scheme: Custom URL schemes allow you to register a URL scheme to enable your app to handle URLs.

Resume Time
When a piece of content was already partially watched, the Apple TV app may invoke your deep link with the resumeTime parameter appended to indicate the time offset at which playback should begin. If the resumeTime (Integer Type) query parameter is present, playback must be resumed at this time.

4. Testing

For testing, please read Apple TV App and Universal Search Video Testing Guide.


Discussion

Read Community Guidelines
You've successfully subscribed to Developer Insider
Great! Next, complete checkout for full access to Developer Insider
Welcome back! You've successfully signed in
Success! Your account is fully activated, you now have access to all content.