Skip to content

Repository files navigation

Contentful Logo

Contentful Personalization & Analytics

Optimization iOS SDK

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.

Installation

Swift Package Manager

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>.

Quick start

SwiftUI

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.

UIKit / direct client

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

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.

Locale handling

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.

Runtime notes

  • Use client.track(event:properties:) for custom business events; identify(...), screen(...), and sticky trackView(...) return EventEmissionResult values with accepted and optional data. trackClick(...) remains available for entry-interaction flows.
  • For typed event calls, pass IdentifyPayload, PageEventPayload, ScreenEventPayload, or TrackEventPayload. Dictionary-based overloads remain available for dynamic JSON payloads.
  • Use client.getFlag(_:) for a one-off Custom Flag read and client.flagPublisher(_:) for an AnyPublisher<JSONValue?, Never> that updates as flag values change.
  • Use client.eventStream and client.blockedEventStream for analytics debugging, tests, and consent-gating diagnostics.
  • Use CTEntry.contentTypeId to select app-owned rendering for baseline and variant content types.
  • SwiftUI entry view and tap tracking default to enabled. Pass trackViews: false or trackTaps: false to OptimizationRoot or OptimizedEntry when 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.

License

MIT

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages