Syncing TipKit with CloudKit

Starting in iOS 18 you can sync the state of TipKit tips across devices with CloudKit.

TipKit Tip State

Apple introduced TipKit in iOS 17 as a consistent way to show in-context tips to users. TipKit keeps track of how often it displays tips, when it has invalidated tips, and the events/rules that control when it should show tips.

Starting in iOS 18, you can opt-in to syncing the TipKit state across devices using CloudKit. That avoids showing the user the same tips on each of their devices.

Syncing With CloudKit

Enabling CloudKit sync for TipKit follows a similar process to enabling sync for Core Data.

  1. Select your App target in Xcode. In the Signing & Capabilities tab, use the + Capability button, double-click the iCloud capability and select CloudKit in the iCloud section. This also adds the Push Notifications capability:

    iCloud capability with CloudKit selected

  2. In the iCloud capability section, use the + button, below the list of containers, to add a container identifier for the TipKit datastore:

    Add a new container dialog showing com.useyourloaf.myapp.tips.

    Use a reverse domain name to create the identifier, ending with “.tips”. Xcode automatically includes the “iCloud” prefix. The new container can take a few seconds to show up in the iCloud console. Xcode shows the identifier in red until it’s ready:

    iCloud capability with CloudKit enabled and iCloud.com.useyourloaf.myapp.tips selected

  3. Repeat the process to add the Background Modes capability to your App target and enable the Remote notifcations option:

    Background modes capability with remote notifications selected

TipKit does not sync to CloudKit by default. You must enable the CloudKit container when configuring the Tips datastore:

try Tips.configure([
  .cloudKitContainer(.automatic)
])

Note:

  • The .automatic option uses the first container in your app’s entitlements that ends with “.tips”. You can override the automatic behaviour by passing an identifier:
try Tips.configure([
  .cloudKitContainer(.named("iCloud.com.apple.myapp.tips"))
])

Core Data Container Identifier

Be careful if you’re already syncing a Core Data/SwiftData database with CloudKit. By default, NSPersistentCloudKitContainer looks for the first iCloud Container identifier in the App’s entitlements file. If you’re not careful you may have listed your TipKit identifier first and your Core Data stack can end up trying to use it.

Apple recommends you use a separate container for syncing tips.

As a workaround, make sure to list your Core Data/SwiftData identifier first in the entitlements file:

Entitlements plist file with two iCloud container identifiers. The app identifier is before the .tips identifier.

Alternatively you can explicitly set the container identifier before loading the persistent store when creating your Core Data stack:

storeDescription.cloudKitContainerOptions = 
  NSPersistentCloudKitContainerOptions(
    containerIdentifier: "com.useyourloaf.myapp")

Learn More

One More Thing

If you’re working with UIKit and want to brush up your layout skills make sure to grab a copy of my book Modern Auto Layout. It’s 20% off in the WWDC25 sale!.