> For the complete documentation index, see [llms.txt](https://cmp.docs.sirdata.net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cmp.docs.sirdata.net/en/mobile-apps-native-sdk/mobile-sdk/setup-1.md).

# iOS — Setup

This page takes you from an empty Xcode project to an integration ready for the App Store, in order. Steps 1 to 6 are the integration itself; steps 7 to 10 cover US users, testing, the release and upgrades.

Every Swift snippet below compiles as written against the published 2.0.0 package, except those marked *fragment*, which go inside your own code.

## 1. Requirements

|                       | Requirement                                                                                                                     |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| iOS deployment target | 15.0 or later, whatever the channel                                                                                             |
| Xcode                 | Verified with Xcode 27.0; earlier versions were not tested. The package declares Swift tools 5.9, which needs Xcode 15 or later |
| Swift                 | 5.9 or later                                                                                                                    |
| Sirdata               | A **partner ID** and a **config ID**, from the [Sirdata Console](https://cmp.sirdata.io)                                        |

The 2.0.0 binary itself is built with Xcode 26, the version pinned in the SDK's build recipe. It is a static framework with an Objective-C interface; the consent UI ships as Swift sources that your Xcode compiles.

The partner ID and the config ID select the publisher configuration the SDK downloads at launch: texts, theme, purposes, vendors, scope and capping. Changing the configuration in the Sirdata Console takes effect without an app release.

**Licence.** The SDK is proprietary software, licensed and not sold, under the [Sirdata CMP Mobile SDK Proprietary Licence v1.1](https://sirdata.com/legal/sdk-licence-v1.1.txt), which is also the `LICENSE` file of the Swift Package Manager and CocoaPods packages. Shipping the SDK in an app made available to users requires a valid, current subscription to the Sirdata Consent Management Platform; one taken through the Sirdata Console is enough, and no signed agreement is required (section 25.1). Without a subscription, the licence is a 90-day evaluation grant: internal evaluation, development, testing and integration, with no distribution to third parties or to an app store (section 1.4). Subscriptions: [sirdata.com](https://sirdata.com); licence questions: <legal@sirdata.com>.

## 2. Add the SDK to your project

Use Swift Package Manager or CocoaPods: both deliver the core framework **and** the SwiftUI consent UI. The manual XCFramework has no UI.

### Swift Package Manager in Xcode (recommended)

1. **File → Add Package Dependencies…**, and enter `https://github.com/SirDataFR/sirdata-cmp-ios-spm`.
2. Set the dependency rule to **Up to Next Major Version**, from **2.0.0**.
3. Add the **SirDataCMP** product to your app target.

### Swift Package Manager in a `Package.swift`

Declare the package, then the product in each target that uses it. The `package:` label is the last component of the URL:

```swift
// swift-tools-version:5.9
import PackageDescription

let package = Package(
    name: "MyFeature",
    platforms: [.iOS(.v15)],
    dependencies: [
        .package(url: "https://github.com/SirDataFR/sirdata-cmp-ios-spm", from: "2.0.0")
    ],
    targets: [
        .target(
            name: "MyFeature",
            dependencies: [
                .product(name: "SirDataCMP", package: "sirdata-cmp-ios-spm")
            ]
        )
    ]
)
```

### CocoaPods

In your `Podfile`:

```ruby
platform :ios, '15.0'

target 'MyApp' do
  pod 'SirdataCMP', '~> 2.0'
end
```

Run `pod install`, then open the `.xcworkspace`, not the `.xcodeproj`. If CocoaPods cannot find version 2.0, run `pod install --repo-update`. The pod works with or without `use_frameworks!`.

The pod is named `SirdataCMP`, with a lowercase *d*. Keep the `~> 2.0` constraint: the 1.x versions of that pod are a different, discontinued Sirdata SDK from 2020, built from another code base.

### Manual (XCFramework)

Download `SirDataCMP-2.0.0.xcframework.zip` from the [releases page](https://github.com/SirDataFR/sirdata-cmp-ios-spm/releases), unzip it, drag `SirDataCMP.xcframework` into your project, and in your target's **General → Frameworks, Libraries, and Embedded Content** set it to **Do Not Embed**: it is a static framework, linked into your app binary.

That archive holds the core `SirDataCMP` module only, and none of the licence files of step 9. The SwiftUI consent UI (`SirDataCMPUI`, `ConsentView`, used in step 4) ships as Swift sources through Swift Package Manager and CocoaPods; use one of them if you want the built-in UI.

### Two modules

Whatever the channel, you import two modules:

```swift
import SirDataCMP    // core API: IosCMPApi, TCF / GPP / USP handlers
import SirDataCMPUI  // SwiftUI consent UI: ConsentView
```

They are separate because the binary framework owns the `SirDataCMP` module name.

If your app links Firebase Analytics through Swift Package Manager, read [Sharing consent with vendor SDKs](/en/mobile-apps-native-sdk/mobile-sdk/sharing-consent.md) before going further: the consent adapter needs Firebase's classes linked.

## 3. Initialize the SDK

Initialize as early as possible, **before any ad or analytics SDK**: a vendor SDK that reads storage before the CMP has identified itself behaves as though no CMP were present.

Three rules:

* **Exactly once.** In 2.0.0, a second `initialize` while the SDK is running terminates the app (the next release ignores it and logs it). To switch to another partner or config, call `shutdown()` first; `IosCMPApi.shared.isInitialized()` tells you whether it is running.
* **On the main thread.** `App.init()` and `application(_:didFinishLaunchingWithOptions:)` both run there. A call from another thread is logged, and terminates the app under `debugMode` (below).
* **Before any other SDK call.** In 2.0.0, these terminate the app when the SDK is not initialized: presenting `ConsentView`, `getConsentState()`, `getConsentData()`, `getConsentUpdates()`, `getGoogleConsentState()`, `getLastForwardedConsentState()`, `getRegisteredAdapters()`, `getLastTcStringError()`, `discardPendingChanges()`, `acceptAll()`, `rejectAll()`, `saveConsent()` and `submitConsent(userAction:)`.

In 2.0.0, on iOS, a misuse terminates the app rather than throwing: the SDK is written in Kotlin, and its exceptions do not cross into Swift. The next release (unreleased) removes this: before `initialize`, the getters return a neutral value (nothing selected, nothing granted, `nil`), `acceptAll()`, `rejectAll()`, `saveConsent()` and `submitConsent(userAction:)` throw a Swift error you can catch, a second `initialize` is ignored and logged, and `ConsentView` shows a message with a Close button. The three rules remain the correct integration.

The snippets use partner `1020` and config `"hmDnl"`, an example configuration. Replace them with your app's own IDs from the Sirdata Console.

### SwiftUI app

```swift
import SwiftUI
import SirDataCMP

@main
struct MyApp: App {
    init() {
        IosCMPApi.shared.initialize(partnerId: 1020, configId: "hmDnl")
    }

    var body: some Scene {
        WindowGroup {
            RootView()   // the view of step 4
        }
    }
}
```

### UIKit app

```swift
import UIKit
import SirDataCMP

@main
final class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        IosCMPApi.shared.initialize(partnerId: 1020, configId: "hmDnl")
        return true
    }
}
```

`partnerId` is an `Int32` in Swift: write `Int32(id)` if you hold it as an `Int`.

`IABTCF_CmpSdkID` is written to `UserDefaults.standard` **synchronously** during this call, before any network work, as the IAB specification requires. Everything else — publisher configuration, vendor lists, stored consent — loads asynchronously afterwards.

### Configuration options

```swift
import SirDataCMP

func startConsentManagement() {
    let config = IosCMPConfig.Builder(partnerId: 1020, configId: "hmDnl")
        .gdprDefaultApplies(gdprDefaultApplies: true)
        #if DEBUG
        .debugMode(debugMode: true)
        #endif
        .build()
    IosCMPApi.shared.initialize(config: config)
}
```

* `gdprDefaultApplies` (default `true`) is used only before the configuration has loaded, and only when the device's locale carries no region. Once the configuration is loaded, the Sirdata API decides whether GDPR applies.
* `debugMode` (default `false`) makes a call to `initialize`, `shutdown` or `setCcpaOptOut(optedOut:)` made off the main thread terminate the app instead of only being logged, so the fault shows in your own debug builds. It has no other effect. Keep it under `#if DEBUG`.
* `apiRoot`, `cacheApiRoot` and `consentApiRoot` default to the Sirdata hosts (`api.`, `choices.` and `mychoice.consentframework.com`). Leave them as they are.
* `language(language:)` is accepted but has **no effect** in 2.0.0. The UI language is the one set in your configuration; when it sets none, the device's preferred language if the Sirdata API serves it, then the configuration's default language, then English.

There is no theme option on iOS: colours, logo and banner position come from your configuration. When the device is in dark mode, the configuration's dark-mode colours are used if it defines them.

## 4. Present the consent UI

Let the SDK decide whether to present it. Do **not** test the TC string yourself: a partially answered consent must re-open the banner, an active capping window must not, and neither is visible from the string.

### SwiftUI

```swift
import SwiftUI
import SirDataCMP
import SirDataCMPUI

struct RootView: View {
    @State private var showConsent = false
    @State private var workflow: Workflow?

    var body: some View {
        Text("Your app")
            .sheet(isPresented: $showConsent) {
                ConsentView(onFinish: { showConsent = false }, workflow: workflow)
            }
            .task {
                guard let decision = try? await IosCMPApi.shared.awaitConsentDisplayDecision(),
                      decision.shouldDisplay else { return }
                workflow = decision.workflow
                IosCMPApi.shared.notifyBannerShown()  // fires `cmpuishown`
                showConsent = true
            }
    }
}
```

`awaitConsentDisplayDecision()` waits for the publisher configuration, then applies the same cascade as the web CMP: GDPR applicability, stored consent, cookie wall, the three capping windows, and whether the stored choice still covers every active purpose, partner and publisher purpose. It also returns *how* to present: a choice missing only at partner level opens the banner in "apply choices" mode, which asks only about what is left to decide. With the cookie wall enabled in your configuration, the banner comes back at every launch until the user grants purpose 1.

On a dead network the wait lasts until initialization gives up, which can take the sum of the HTTP timeouts. Behind a launch screen, bound it — past the deadline you get the decision as it stands, provisional if the configuration has not arrived (*fragment*):

```swift
let decision = try await IosCMPApi.shared.awaitConsentDisplayDecision(timeoutMillis: 3_000)
```

`ConsentView` renders the whole flow (banner → purposes → partners), themed from your configuration. Its initializer is `ConsentView(onFinish:initialScreen:workflow:)`: `onFinish` is called when the user is done, and `initialScreen: .purposes` opens straight on the preferences screen. The view fires `cmpuiclosed` itself when it closes. Call `notifyBannerShown()` each time you present it.

### UIKit

Present `ConsentView` in a `UIHostingController`, full screen over a clear background: the view draws its own dimmed backdrop and positions the banner itself.

```swift
import SwiftUI
import UIKit
import SirDataCMP
import SirDataCMPUI

final class HomeViewController: UIViewController {
    private var didCheckConsent = false

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        guard !didCheckConsent else { return }
        didCheckConsent = true
        Task { @MainActor in
            guard let decision = try? await IosCMPApi.shared.awaitConsentDisplayDecision(),
                  decision.shouldDisplay else { return }
            presentConsent(workflow: decision.workflow)
        }
    }

    func presentConsent(workflow: Workflow?) {
        weak var host: UIHostingController<ConsentView>?
        let controller = UIHostingController(
            rootView: ConsentView(onFinish: { host?.dismiss(animated: true) }, workflow: workflow)
        )
        host = controller
        controller.modalPresentationStyle = .overFullScreen
        controller.view.backgroundColor = .clear
        IosCMPApi.shared.notifyBannerShown()  // fires `cmpuishown`
        present(controller, animated: true)
    }
}
```

Before shipping this full-screen presentation, read the 2.0.0 known issue at the end of the next section: it has no way out when the configuration could not be loaded.

### Closing the sheet without answering

In a `.sheet`, the user can swipe the banner down. That closes it **without saving anything**: the SDK reports it to Sirdata as a close without a choice, fires `cmpuiclosed`, and the banner shows again at the next launch. To prevent it — with a cookie wall, for instance — disable the gesture on the view (*fragment*):

```swift
ConsentView(onFinish: { showConsent = false }, workflow: workflow)
    .interactiveDismissDisabled()
```

The full-screen UIKit presentation above has no such gesture.

**Known issue in 2.0.0: no way out while the configuration is missing.** If the configuration could not be loaded at this launch — the device is offline, for instance — the decision can still ask for the banner (reason `configNotLoaded`), but `ConsentView` then shows only a loading indicator, with no close control. In a plain `.sheet` the user can still swipe it down. With `.interactiveDismissDisabled()`, or in the full-screen UIKit presentation above, nothing closes it. If you use either, present the view only once the configuration has loaded. The next release (unreleased) fixes this: `ConsentView` shows a message and a Close button when the configuration could not be loaded, and a Close button under the loading indicator after five seconds. With UIKit, make this the first line of `presentConsent(workflow:)`, so that it also covers the re-opening of step 6 (*fragment*):

```swift
guard IosCMPApi.shared.tcfApi().isCmpLoaded() else { return }
```

## 5. Read consent in your own code

### Values

```swift
import SirDataCMP

func readConsent() {
    let cmp = IosCMPApi.shared
    let tcString    = cmp.getTcString()                    // "" until a choice is saved
    let gdprApplies = cmp.isGdprApplies()
    let analyticsOK = cmp.hasPurposeConsent(purposeId: 8)  // TCF purpose 8
    let googleOK    = cmp.hasVendorConsent(vendorId: 755)  // TCF vendor 755
    let gppString   = cmp.getGppString()
    let acString    = cmp.getAddtlConsent()                // Google Additional Consent
    print(tcString, gdprApplies, analyticsOK, googleOK, gppString, acString)
}
```

These read the stored values, the ones vendor SDKs read too: the IAB keys in `UserDefaults.standard` (`IABTCF_…`, `IABGPP_…`, and `IABUSPrivacy_String` once a US choice exists). [Sharing consent with vendor SDKs](/en/mobile-apps-native-sdk/mobile-sdk/sharing-consent.md) lists them. `isGdprApplies()` is the Sirdata API's answer once the configuration has loaded, and an estimate from the device's region before.

Some keys exist before any choice. `initialize` writes `IABTCF_CmpSdkID`, `IABTCF_CmpSdkVersion` and `IABTCF_PolicyVersion`. Once the configuration has loaded, the SDK writes `IABTCF_gdprApplies`, `IABTCF_PolicyVersion` again (from the loaded vendor list), `IABTCF_PublisherCC`, `IABTCF_PurposeOneTreatment`, `IABTCF_UseNonStandardTexts`, the publisher bit strings (`IABTCF_PublisherConsent`, `IABTCF_PublisherLegitimateInterests` and the two `IABTCF_PublisherCustomPurposes…` keys) and, for a US user, the GPP keys with the US section. `IABTCF_TCString` and the purpose and vendor consents (`IABTCF_PurposeConsents`, `IABTCF_VendorConsents`…) appear only once a choice is recorded.

### React to changes

A Kotlin flow cannot be collected from Swift: observe the SDK's update counter with an `UpdateCounterWatcher`. Create it after `initialize`, keep a reference to it, and close it when you are done.

```swift
import SirDataCMP

final class ConsentGate {
    private var watcher: UpdateCounterWatcher?

    func start() {
        apply()  // the watcher does not fire for the current value
        let watcher = UpdateCounterWatcher(flow: IosCMPApi.shared.getConsentUpdates())
        watcher.watch { [weak self] _ in self?.apply() }
        self.watcher = watcher
    }

    func stop() {
        watcher?.close()
        watcher = nil
    }

    private func apply() {
        let allowed = IosCMPApi.shared.hasPurposeConsent(purposeId: 1)
        print("purpose 1 granted:", allowed)  // enable or disable the dependent SDK here
    }
}
```

The callback runs on the main thread. It fires on every change of the selection, including toggles in the open consent UI that are not saved yet, so re-read the stored values each time rather than counting calls: they change only when the user saves. `UserDefaults.didChangeNotification` works too, but fires on every write to the app's defaults.

A US choice — saved on the US screen, or recorded with `setCcpaOptOut(optedOut:)` — does not change the counter: re-read `getUspString()` and `getGppString()` when the consent UI closes (in `onFinish`), and right after your own calls to `setCcpaOptOut`.

The in-app TCF API (`tcfApi()`) has an `addEventListener` command, but in 2.0.0 its callback does not say which event fired: read the stored values from it too.

### Google Consent Mode

`IosCMPApi.shared.getGoogleConsentState()` returns the Google signals the SDK derives from the stored TCF choice (`adStorageGranted`, `analyticsStorageGranted`, `adUserDataGranted`, `adPersonalizationGranted`). The SDK forwards consent to Firebase Analytics itself: see [Sharing consent with vendor SDKs](/en/mobile-apps-native-sdk/mobile-sdk/sharing-consent.md).

### Your own consent screen

Instead of `ConsentView`, a screen of your own can record a choice with `try await IosCMPApi.shared.acceptAll()` or `rejectAll()`. Each returns a `ConsentResult`: `ConsentResult.Success`, or `ConsentResult.Error` with a `message`. Call `notifyBannerShown()` when your screen appears and `notifyBannerClosed()` when it closes, so that the in-app TCF API fires `cmpuishown` and `cmpuiclosed`. `recordAskLater()` records an "ask me later": the banner stays hidden for one hour. Every method is in the [Reference](/en/mobile-apps-native-sdk/mobile-sdk/reference-1.md).

## 6. Re-open from a settings screen

Users must be able to change their choices at any time. Give them an entry point — a "Privacy choices" row in your settings — that presents the view in the manual workflow:

```swift
import SwiftUI
import SirDataCMP
import SirDataCMPUI

struct PrivacyChoicesRow: View {
    @State private var showConsent = false

    var body: some View {
        Button("Privacy choices") {
            IosCMPApi.shared.notifyBannerShown()
            showConsent = true
        }
        .sheet(isPresented: $showConsent) {
            ConsentView(onFinish: { showConsent = false }, workflow: .manualDisplay)
        }
    }
}
```

With UIKit, call `presentConsent(workflow: .manualDisplay)` from step 4.

In the manual workflow the banner has a close cross at the top and a "Reject all" button, whatever refusal type and style your configuration sets, and the purposes and partners screens show the saved choices. When it appears, the view restarts the capping window of your configuration and reports a re-visit (`load:revisit`): do not call `recordPrompt()` yourself.

## 7. US users

When GDPR does not apply, the SDK never asks for the banner to be shown: `awaitConsentDisplayDecision()` returns `shouldDisplay == false`, with reason `gdprNotApplies`. A US user therefore sees nothing unless your app opens the consent UI.

`isCcpaApplies()` tells you whether the US regime applies: the Sirdata API's answer once the configuration has loaded, the device's region before. When it is `true`, `ConsentView` shows the SDK's US screen instead of the TCF banner, whatever the workflow. Saving it records the user's opt-out choice: the SDK writes `IABUSPrivacy_String` and re-encodes the US sections of the GPP string. Until then, `IABUSPrivacy_String` is absent; the GPP keys, with the US section, are written as soon as the configuration has loaded, with default values until the user chooses. A US choice does not change the `getConsentUpdates()` counter (step 5).

So show the entry point of step 6 to US users too. If you build your own US screen instead, call `IosCMPApi.shared.setCcpaOptOut(optedOut:)` on the main thread, and only with the choice the user actually made — never on their behalf.

## 8. Test and verify your integration

To replay a first launch, delete the app, or call `IosCMPApi.shared.clearConsent()` and relaunch. Call it too whenever you switch to another partner or config: a stored choice belongs to the publisher that collected it.

Whether GDPR applies is decided by the Sirdata API, from the country of the device's IP address and from your configuration — not from the device's region settings. Where GDPR does not apply, the banner does not show (reason `gdprNotApplies`).

In a debug build, check each point in order:

1. Right after `initialize`, `UserDefaults.standard.integer(forKey: "IABTCF_CmpSdkID")` is `92`.
2. At the first launch, the decision has `shouldDisplay == true` and the banner appears with your configuration's texts, colours and logo. The purposes and partners screens open. Before any choice, once the configuration has loaded, `IABTCF_gdprApplies` is `1` and `IABTCF_TCString` is absent.
3. After **Accept all**, `IABTCF_TCString`, `IABTCF_PurposeConsents`, `IABTCF_VendorConsents` and `IABGPP_HDR_GppString` are set, and `IABUSPrivacy_String` is absent.
4. After a relaunch, the banner does not show again.
5. The re-opening of step 6 shows the close cross, the "Reject all" button and the saved choices; a new choice replaces the old one.
6. `ping` succeeds and reports `cmpStatus` `loaded`.
7. The Xcode console shows no line starting with `[CMP]`. One appears only when something needs fixing: a call off the main thread, a consent adapter that failed to forward a choice, a stored TC string that could not be read.
8. A Release build runs on a real device.

The keys of points 1 to 3, and point 6, can be checked from code (*fragment*). Read `IABTCF_CmpSdkID` right after `initialize`; run the rest once the configuration has loaded — from a debug button, for instance: until then `ping` answers with `cmpStatus` `stub`.

```swift
print("CmpSdkID:", UserDefaults.standard.integer(forKey: "IABTCF_CmpSdkID"))

let keys = UserDefaults.standard.dictionaryRepresentation().keys
    .filter { $0.hasPrefix("IABTCF_") || $0.hasPrefix("IABGPP_") || $0 == "IABUSPrivacy_String" }
    .sorted()
print("IAB keys:", keys)

IosCMPApi.shared.tcfApi().execute(command: "ping", version: 2, callback: { data, _, success in
    let ping = data as? [String: Any]
    print("ping:", success.boolValue, ping?["cmpStatus"] ?? "none")
}, parameter: nil)
```

If the banner never appears, the decision says why before any log does (*fragment*):

```swift
let decision = try await IosCMPApi.shared.awaitConsentDisplayDecision()
print("display:", decision.shouldDisplay, "workflow:", decision.workflow.name,
      "reason:", decision.reason.name)
```

An active capping window (`cappingActive`, `cappingAskLater`), a stored consent that still covers everything (`consentOk`) or GDPR not applying (`gdprNotApplies`) are normal reasons for the banner not to appear.

If the configuration does not load — `IosCMPApi.shared.tcfApi().isCmpLoaded()` stays `false` a few seconds after launch — `IosCMPApi.shared.getInitError()` returns the error message of the failed load; an unknown partner or config ID and a network failure both end up there. The SDK does not log it. Read it then, not as soon as `awaitConsentDisplayDecision()` returns: in 2.0.0, at that moment it can still be `nil` after a failure. The next release sets it before `awaitConsentDisplayDecision()` returns. See also [Logging](/en/mobile-apps-native-sdk/mobile-sdk/logging.md) and [Troubleshooting](/en/mobile-apps-native-sdk/mobile-sdk/troubleshooting.md).

## 9. Prepare the release

* **Your own IDs.** Replace the example partner and config IDs with your app's.
* **`debugMode` in debug builds only.** It terminates the app on a main-thread violation, and the SDK does not check the build type: keep it under `#if DEBUG`.
* **Licence.** Shipping the app requires a valid, current subscription to the Sirdata Consent Management Platform; one taken through the Sirdata Console is enough (step 1).
* **Third-party notices.** The SDK embeds open-source components under the Apache License 2.0 and the Boost Software License 1.0. When you distribute your app, reproduce the SDK's notice file and those licence texts and make them available to your users — in your app's acknowledgements screen, for instance. This is a condition of the Apache License, and of section 26.1(b) of the SDK's `LICENSE`. With Swift Package Manager they are in the package, as `NOTICE` and `THIRD-PARTY-LICENSES/`; with CocoaPods, in `Pods/SirdataCMP/` as `NOTICE-ios` and `THIRD-PARTY-LICENSES/`; with the manual XCFramework, take them from the [package repository](https://github.com/SirDataFR/sirdata-cmp-ios-spm) on GitHub.
* **Privacy manifest.** The SDK 2.0.0 ships no Apple privacy manifest (`PrivacyInfo.xcprivacy`). It reads and writes `UserDefaults.standard`, one of the API categories (`NSPrivacyAccessedAPICategoryUserDefaults`) that Apple's documentation on [required reason APIs](https://developer.apple.com/documentation/bundleresources/describing-use-of-required-reason-api) covers (checked on 2026-10-05). Take it into account for your App Store submission, and ask your Sirdata contact if you have questions.
* **App privacy details.** The [privacy details](https://developer.apple.com/app-store/app-privacy-details/) you give in App Store Connect include the practices of the third-party SDKs in your app (checked on 2026-10-05), this one included. It sends requests to `api.consentframework.com`, `choices.consentframework.com` and `mychoice.consentframework.com`.

## 10. Upgrading

**From Swift Package Manager 1.2.0.** "Up to Next Major Version" never crosses a major version, so a rule set from 1.2.0 stays on 1.x. Change it to start from 2.0.0: in Xcode, in your project's **Package Dependencies** tab; in a `Package.swift`, `from: "2.0.0"`. Then raise your deployment target to iOS 15.0 if it is lower. No public API was removed or renamed in 2.0.0, so your code needs no change; [Versions](/en/mobile-apps-native-sdk/mobile-sdk/versions-1.md) lists what changed in behaviour.

**From the 2020 `SirdataCMP` pod (1.x).** It is a different SDK, built from another code base. Remove it and the code that calls it, then integrate this SDK from step 2, with `pod 'SirdataCMP', '~> 2.0'`.

**Keep the two modules at the same version.** The SwiftUI layer and the binary framework are released together, and both package managers keep them aligned. If Xcode reports that a type has no member the SDK's code uses, resolve the package again, and do not mix a local copy with a released version.

## Next

* [Sharing consent with vendor SDKs](/en/mobile-apps-native-sdk/mobile-sdk/sharing-consent.md) — the part that makes ads work
* [Reference](/en/mobile-apps-native-sdk/mobile-sdk/reference-1.md) — every method and event
* [Logging](/en/mobile-apps-native-sdk/mobile-sdk/logging.md) — what the SDK writes to the console
* [Troubleshooting](/en/mobile-apps-native-sdk/mobile-sdk/troubleshooting.md) — the errors integrators actually hit
* [Versions](/en/mobile-apps-native-sdk/mobile-sdk/versions-1.md) — what changed in each release


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://cmp.docs.sirdata.net/en/mobile-apps-native-sdk/mobile-sdk/setup-1.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
