This guide helps you migrate from Storyteller SDK version 10.x.x to 11.0.x. Version 11.0.x introduces several breaking changes that improve the SDK's architecture and consistency. Version 11 focuses on three major architectural improvements:
Shared Instance Pattern - Static methods replaced with Storyteller.shared
Consistent Naming - Public types now use Storyteller prefix
Modern Swift Concurrency - Callback-based APIs replaced with async/await
The Storyteller class has moved from using static methods to a shared instance pattern. All API calls must now use Storyteller.shared instead of calling static methods directly on the class.
See the shared instance pattern in the Showcase app where Storyteller.shared.modules, Storyteller.shared.theme, and Storyteller.shared.delegate are configured in AppDelegate.setupStoryteller.
eventTrackingOptions can now only be set during SDK initialization:
Before (10.x.x):
// Initialize SDKStoryteller.initialize(apiKey:"your-api-key",onComplete:{print("SDK initialized successfully")},onError:{errorinprint("Initialization failed: \(error)")})// Later in the code, modify tracking optionsStoryteller.eventTrackingOptions=StorytellerEventTrackingOptions(enablePersonalization:true,enableStorytellerTracking:true,enableUserActivityTracking:true,enableAdTracking:true,enableFullVideoAnalytics:true,enableRemoteViewingStore:true,disabledFunctionalFeatures:[])
After (11.x.x):
// Set tracking options during initializationlettrackingOptions=StorytellerEventTrackingOptions(enablePersonalization:true,enableStorytellerTracking:true,enableUserActivityTracking:true,enableAdTracking:true,enableFullVideoAnalytics:true,enableRemoteViewingStore:true,disabledFunctionalFeatures:[])letuserInput=StorytellerUserInput(externalId:"user-id")Task{tryawaitStoryteller.shared.initialize(apiKey:"your-api-key",userInput:userInput,eventTrackingOptions:trackingOptions)}
The isScrollable parameter no longer has a default value and must be explicitly provided:
Before (10.x.x):
// isScrollable defaulted to falseStorytellerStoriesGrid(model:storiesModel)StorytellerClipsGrid(model:clipsModel)
After (11.x.x):
// isScrollable must be explicitly providedletstoriesModel=StorytellerStoriesListModel(configuration:StorytellerStoriesListConfiguration(categories:["category-id"]))letclipsModel=StorytellerClipsListModel(configuration:StorytellerClipsListConfiguration(collectionId:"collection-id"))StorytellerStoriesGrid(isScrollable:false,model:storiesModel)StorytellerClipsGrid(isScrollable:false,model:clipsModel)
Check the Changelog for a detailed version history
Don't hesitate to reach out if you continue to face difficulties
{"slug": "migration-guide-v11", "page_title": "Migrate from Version 10 to 11", "page_url": "MigrationGuideV11/", "canonical_url": "/ios/MigrationGuideV11/", "markdown": "# Migrating to version 11\n\nThis guide helps you migrate from Storyteller SDK version 10.x.x to 11.0.x. Version 11.0.x introduces several breaking changes that improve the SDK's architecture and consistency. Version 11 focuses on three major architectural improvements:\n\n- **Shared Instance Pattern** - Static methods replaced with `Storyteller.shared`\n- **Consistent Naming** - Public types now use `Storyteller` prefix\n- **Modern Swift Concurrency** - Callback-based APIs replaced with async/await\n\n## Storyteller shared instance\n\nThe `Storyteller` class has moved from using static methods to a shared instance pattern. All API calls must now use `Storyteller.shared` instead of calling static methods directly on the class.\n\n### Usage example\n\n**Before (10.x.x):**\n\n<!-- storyteller-swift-example: id=migrationguidev11-01-before target=historical reason=\"SDK 10 static delegate API\" -->\n\n```swift\nStoryteller.delegate = myDelegate\n```\n\n**After (11.x.x):**\n\n<!-- storyteller-swift-example: id=migrationguidev11-01-after target=sdk-ios context=statements -->\n\n```swift\nfinal class DelegateObject: StorytellerDelegate {}\nlet myDelegate = DelegateObject()\nStoryteller.shared.delegate = myDelegate\n```\n\nSee the shared instance pattern in the Showcase app where `Storyteller.shared.modules`, `Storyteller.shared.theme`, and `Storyteller.shared.delegate` are configured in [`AppDelegate.setupStoryteller`](https://github.com/getstoryteller/storyteller-showcase-ios/blob/11.6.1/main/ShowcaseApp/ShowcaseApp.swift#L95).\n\n## Storyteller Prefix for Public Types\n\nAll public types now start with the `Storyteller` prefix for better namespace consistency and to avoid naming conflicts with your app code.\n\n### Type Renames\n\n| Old Name | New Name |\n|----------|----------|\n| `UserInput` | `StorytellerUserInput` |\n| `ClipCollectionConfiguration` | `StorytellerClipCollectionConfiguration` |\n| `Placement` | `StorytellerPlacement` |\n| `Category` | `StorytellerCategory` |\n| `CategoryDetail` | `StorytellerCategoryDetail` |\n| `CurrentCategoryData` | `StorytellerCurrentCategoryData` |\n| `UserActivity` | `StorytellerUserActivity` |\n| `UserActivityData` | `StorytellerUserActivityData` |\n| `CodableIgnored` | `StorytellerCodableIgnored` |\n| `Alignment` | `StorytellerAlignment` |\n| `FontProvider` | `StorytellerFontProvider` |\n| `TextCasing` | `StorytellerTextCasing` |\n| `PlayerIcons` | `StorytellerPlayerIcons` |\n| `InstructionIcons` | `StorytellerInstructionIcons` |\n\n## Async/Await functions\n\nAll callback-based APIs have been replaced with modern Swift async/await patterns. The following `Storyteller.shared` methods are now async functions:\n\n- `initialize(apiKey:userInput:eventTrackingOptions:)`\n- `dismissPlayer(animated:dismissReason:)`\n- `openDeepLink(url:)`\n- `openStory(id:openReason:)`\n- `openStory(externalId:openReason:)`\n- `openPage(id:openReason:)`\n- `openCategory(category:openReason:)`\n- `openCollection(configuration:openReason:)`\n- `openClipByExternalId(collectionId:externalId:openReason:)`\n- `openSheet(id:)`\n- `getStoriesCount(for:)`\n- `getClipsCount(for:)`\n- `openSearch()`\n\n### Migration Examples\n\n**Before (10.x.x):**\n\n<!-- storyteller-swift-example: id=migrationguidev11-02-before target=historical reason=\"SDK 10 callback initialization API\" -->\n\n```swift\nStoryteller.initialize(\n apiKey: \"your-api-key\",\n onComplete: {\n print(\"SDK initialized successfully\")\n },\n onError: { error in\n print(\"Initialization failed: \\(error)\")\n }\n)\n```\n\n**After (11.x.x):**\n\n<!-- storyteller-swift-example: id=migrationguidev11-02-after target=sdk-ios context=statements -->\n\n```swift\nTask {\n do {\n try await Storyteller.shared.initialize(apiKey: \"your-api-key\")\n print(\"SDK initialized successfully\")\n } catch {\n print(\"Initialization failed: \\(error)\")\n }\n}\n```\n\nSee the Showcase initialization flow using async/await in [`StorytellerService.setup`](https://github.com/getstoryteller/storyteller-showcase-ios/blob/11.6.1/main/ShowcaseApp/Storyteller/StorytellerService.swift#L36).\n\n## Additional Breaking Changes\n\n### Event Tracking Options\n\n`eventTrackingOptions` can now only be set during SDK initialization:\n\n**Before (10.x.x):**\n\n<!-- storyteller-swift-example: id=migrationguidev11-03 target=historical reason=\"SDK 10 mutable tracking options API\" -->\n\n```swift\n// Initialize SDK\nStoryteller.initialize(\n apiKey: \"your-api-key\",\n onComplete: {\n print(\"SDK initialized successfully\")\n },\n onError: { error in\n print(\"Initialization failed: \\(error)\")\n }\n)\n\n// Later in the code, modify tracking options\nStoryteller.eventTrackingOptions = StorytellerEventTrackingOptions(\n enablePersonalization: true,\n enableStorytellerTracking: true,\n enableUserActivityTracking: true,\n enableAdTracking: true,\n enableFullVideoAnalytics: true,\n enableRemoteViewingStore: true,\n disabledFunctionalFeatures: []\n)\n```\n\n**After (11.x.x):**\n\n<!-- storyteller-swift-example: id=migrationguidev11-04 target=sdk-ios context=statements -->\n\n```swift\n// Set tracking options during initialization\nlet trackingOptions = StorytellerEventTrackingOptions(\n enablePersonalization: true,\n enableStorytellerTracking: true,\n enableUserActivityTracking: true,\n enableAdTracking: true,\n enableFullVideoAnalytics: true,\n enableRemoteViewingStore: true,\n disabledFunctionalFeatures: []\n)\n\nlet userInput = StorytellerUserInput(externalId: \"user-id\")\n\nTask {\n try await Storyteller.shared.initialize(\n apiKey: \"your-api-key\",\n userInput: userInput,\n eventTrackingOptions: trackingOptions\n )\n}\n```\n\nSee how the Showcase app builds [`StorytellerEventTrackingOptions`](https://github.com/getstoryteller/storyteller-showcase-ios/blob/11.6.1/main/ShowcaseApp/Storyteller/StorytellerService.swift#L37) and passes them during initialization in [`StorytellerService.setup`](https://github.com/getstoryteller/storyteller-showcase-ios/blob/11.6.1/main/ShowcaseApp/Storyteller/StorytellerService.swift#L36).\n\nTo change tracking options after initialization, you must reinitialize the SDK. See [Privacy and Tracking](PrivacyAndTracking.md) for more information.\n\n### SwiftUI Grids\n\nThe `isScrollable` parameter no longer has a default value and must be explicitly provided:\n\n**Before (10.x.x):**\n\n<!-- storyteller-swift-example: id=migrationguidev11-05-before target=historical reason=\"SDK 10 SwiftUI grid initializer\" -->\n\n```swift\n// isScrollable defaulted to false\nStorytellerStoriesGrid(model: storiesModel)\nStorytellerClipsGrid(model: clipsModel)\n```\n\n**After (11.x.x):**\n\n<!-- storyteller-swift-example: id=migrationguidev11-05-after target=sdk-ios context=statements -->\n\n```swift\n// isScrollable must be explicitly provided\nlet storiesModel = StorytellerStoriesListModel(\n configuration: StorytellerStoriesListConfiguration(categories: [\"category-id\"])\n)\nlet clipsModel = StorytellerClipsListModel(\n configuration: StorytellerClipsListConfiguration(collectionId: \"collection-id\")\n)\nStorytellerStoriesGrid(isScrollable: false, model: storiesModel)\nStorytellerClipsGrid(isScrollable: false, model: clipsModel)\n```\n\nSee the Showcase SwiftUI grid usage in [`StoriesListView`](https://github.com/getstoryteller/storyteller-showcase-ios/blob/11.6.1/main/ShowcaseApp/Views/Home/Components/StorytellerLists.swift#L11).\n\n### StorytellerListViewDelegate\n\nThe `onTileTapped` method now provides richer context via the `StorytellerTileType` enum:\n\n**Before (10.x.x):**\n\n<!-- storyteller-swift-example: id=migrationguidev11-06-before target=historical reason=\"SDK 10 tile callback signature\" -->\n\n```swift\nextension MyViewController: StorytellerListViewDelegate {\n func onTileTapped(id: String) {\n print(\"Tapped tile with ID: \\(id)\")\n }\n}\n```\n\n**After (11.x.x):**\n\n<!-- storyteller-swift-example: id=migrationguidev11-06-after target=sdk-ios context=declarations -->\n\n```swift\nfinal class MyViewController: UIViewController, StorytellerListViewDelegate {\n nonisolated func onTileTapped(type: StorytellerTileType) {\n switch type {\n case .clip(let clipId, let collectionId, let categories):\n print(\"Tapped clip: \\(clipId) in collection: \\(collectionId), categories: \\(categories)\")\n case .story(let storyId, let categories):\n print(\"Tapped story: \\(storyId), categories: \\(categories)\")\n @unknown default:\n break\n }\n }\n}\n```\n\nSee the Showcase [`onTileTapped`](https://github.com/getstoryteller/storyteller-showcase-ios/blob/11.6.1/main/ShowcaseApp/Views/Home/Components/StorytellerItemView.swift#L65) flow (including categories) in [`StorytellerItemView.listAction`](https://github.com/getstoryteller/storyteller-showcase-ios/blob/11.6.1/main/ShowcaseApp/Views/Home/Components/StorytellerItemView.swift#L58).\n\n### Other breaking changes\n\nThe following theme properties have been removed and are now configured in the CMS:\n\n- `tiles.title.show` - configured in CMS\n- `engagement.poll.showVoteCount` - configured in CMS\n\n## Need Help\n\nIf you encounter any issues during the migration:\n\n1. Check the [Changelog](Changelog.md) for a detailed version history\n1. Don't hesitate to reach out if you continue to face difficulties\n", "copy_markdown_include_header": false, "base_path": "", "ai_dir": "ai", "missing_payload_behavior": "empty"}