Note
Source lives at https://github.com/contentful/optimization. This repository is generated by a release workflow; do not file PRs here.
ContentfulOptimization is the native Swift Package for the
Contentful Optimization SDK Suite. It runs shared
optimization behavior through a local JavaScriptCore bridge while Swift code owns native app
concerns such as persistence, networking, lifecycle handling, SwiftUI views, and preview-panel UI.
Requires iOS 15 or later.
In Package.swift:
dependencies: [
.package(url: "https://github.com/contentful/optimization.swift.git", from: "<version>"),
],
targets: [
.target(
name: "MyApp",
dependencies: [
.product(name: "ContentfulOptimization", package: "optimization.swift"),
]
),
],Or in Xcode: File > Add Package Dependencies… and paste
https://github.com/contentful/optimization.swift.
Choose the latest released tag from
contentful/optimization.swift and use
that value for <version>.
Wrap your app in OptimizationRoot to initialize the client and provide it to the view tree:
import ContentfulOptimization
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
OptimizationRoot(
config: OptimizationConfig(
clientId: "<your-client-id>",
environment: "main"
)
) {
ContentView()
.trackScreen(name: "Home")
}
}
}
}Render optimized Contentful entries with OptimizedEntry, and track screens with the
.trackScreen(name:) modifier.
import ContentfulOptimization
let client = OptimizationClient()
try client.initialize(
config: OptimizationConfig(clientId: "<your-client-id>", environment: "main")
)
let screenResult = try await client.screen(name: "Home")
let optimizationData = screenResult.accepted ? screenResult.data : nil
try await client.track(event: "Purchase Completed", properties: ["sku": "sku-1"])Consent policy remains application-owned. Boolean consent controls both event emission and durable profile-continuity persistence by default:
let config = OptimizationConfig(
clientId: "<your-client-id>",
defaults: StorageDefaults(consent: true)
)Use that default when application policy permits Optimization by default and no end-user consent UI is rendered. When application policy depends on user choice, call consent from the app's controls:
client.consent(true)
client.consent(false)Use split consent when events are allowed but profile continuity should stay session-only:
client.consent(events: true, persistence: false)For cross-SDK consent policy guidance, see Consent management in the Optimization SDK Suite.
For a single-locale app, choose the application Contentful locale and pass the same value to SDK
locale when Experience API responses and events should use that language:
let appLocale = "en-US"
let config = OptimizationConfig(
clientId: "<your-client-id>",
environment: "main",
locale: appLocale
)For localized apps, derive appLocale from your navigation, i18n, or app configuration layer:
let appLocale = getAppLocale()
let config = OptimizationConfig(
clientId: "<your-client-id>",
environment: "main",
locale: appLocale
)Use the same appLocale when your app-owned Contentful Delivery API client queries an entry by
content type and slug. Pass that fetched single-locale entry to OptimizedEntry or
client.resolveOptimizedEntry(...). The native iOS SDK does not provide managed entry fetching, so
the lookup values and CDA request remain in your app.
- Use
client.track(event:properties:)for custom business events;identify(...),screen(...), and stickytrackView(...)returnEventEmissionResultvalues withacceptedand optionaldata.trackClick(...)remains available for entry-interaction flows. - For typed event calls, pass
IdentifyPayload,PageEventPayload,ScreenEventPayload, orTrackEventPayload. Dictionary-based overloads remain available for dynamic JSON payloads. - Use
client.getFlag(_:)for a one-off Custom Flag read andclient.flagPublisher(_:)for anAnyPublisher<JSONValue?, Never>that updates as flag values change. - Use
client.eventStreamandclient.blockedEventStreamfor analytics debugging, tests, and consent-gating diagnostics. - Use
CTEntry.contentTypeIdto select app-owned rendering for baseline and variant content types. - SwiftUI entry view and tap tracking default to enabled. Pass
trackViews: falseortrackTaps: falsetoOptimizationRootorOptimizedEntrywhen a screen or entry must opt out. - Analytics events queue while the device is offline and flush when connectivity returns or the app moves toward the background.
For the full locale model, see Locale handling in the Optimization SDK Suite. For the single-locale CDA entry contract, see Entry optimization and variant resolution.
See the SwiftUI integration guide, UIKit integration guide, and iOS runtime and interaction mechanics for setup walkthroughs, SwiftUI helpers, runtime behavior, and preview-panel guidance.