{"id":28186811,"url":"https://github.com/axeptio/sample-app-ios","last_synced_at":"2026-04-02T14:46:51.220Z","repository":{"id":230075803,"uuid":"766983030","full_name":"axeptio/sample-app-ios","owner":"axeptio","description":null,"archived":false,"fork":false,"pushed_at":"2026-03-17T17:00:25.000Z","size":24651,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":6,"default_branch":"develop","last_synced_at":"2026-03-18T06:44:04.417Z","etag":null,"topics":["cmp","ios","sample","sdk"],"latest_commit_sha":null,"homepage":"https://www.axept.io/","language":"Swift","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/axeptio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-03-04T13:50:07.000Z","updated_at":"2026-03-17T16:57:25.000Z","dependencies_parsed_at":"2025-10-17T19:36:05.679Z","dependency_job_id":null,"html_url":"https://github.com/axeptio/sample-app-ios","commit_stats":null,"previous_names":["axeptio/sample-app-ios"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/axeptio/sample-app-ios","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/axeptio%2Fsample-app-ios","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/axeptio%2Fsample-app-ios/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/axeptio%2Fsample-app-ios/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/axeptio%2Fsample-app-ios/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/axeptio","download_url":"https://codeload.github.com/axeptio/sample-app-ios/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/axeptio%2Fsample-app-ios/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31308403,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cmp","ios","sample","sdk"],"created_at":"2025-05-16T07:10:57.676Z","updated_at":"2026-04-02T14:46:51.183Z","avatar_url":"https://github.com/axeptio.png","language":"Swift","readme":"\u003cimg src=\"https://github.com/user-attachments/assets/5799ac86-5d77-4a9e-9bdf-36d40881a449\" width=\"600\" height=\"300\"/\u003e\n\n# Axeptio iOS SDK Documentation\n\nWelcome to the Axeptio iOS SDK Samples project. This repository provides a comprehensive guide on how to integrate the Axeptio iOS SDK into your mobile applications. It showcases two distinct modules: one for Swift using Swift Package Manager and one for Objective-C using CocoaPods. Below you'll find detailed instructions and code examples to help you integrate and configure the SDK within your iOS app.\n\n## Table of Contents\n1. [GitHub Access Token Documentation](#github-access-token-documentation)\n2. [Requirements](#requirements)\n3. [SDK Version](#sdk-version)\n4. [Clone the repository](#clone-the-repository)\n5. [Adding the SDK](#adding-the-sdk)\n   - [Using CocoaPods](#using-cocoapods)\n   - [Using Swift Package Manager](#using-swift-package-manager)\n6. [Initializing the SDK](#initializing-the-sdk)\n   - [Swift](#swift)\n   - [Objective-C](#objective-c)\n7. [Widget Environment Configuration (SDK 2.1.0+)](#widget-environment-configuration-sdk-210)\n8. [Cookie Duration Management (SDK 2.1.0+)](#cookie-duration-management-sdk-210)\n9. [Set up the SDK UI](#set-up-the-sdk-ui)\n   - [Swift](#swift)\n   - [Objective-C](#objective-c)\n     - [Issues with the Consent Popup (Objective-C)](#issues-with-the-consent-popup-objective-c)\n   - [SwiftUI Integration](#swiftui-integration)\n10. [Additional Configuration: Show Popup When Returning from Background](#additional-configuration-show-popup-when-returning-from-background)\n11. [Axeptio SDK and App Tracking Transparency (ATT) Integration](#axeptio-sdk-and-app-tracking-transparency-att-integration)\n   - [Swift Integration](#swift-integration)\n   - [Objective-C Integration](#objective-c-integration)\n   - [Handling Changes in ATT Settings](#handling-changes-in-att-settings)\n12. [Responsibilities Mobile App vs SDK](#responsibilities-mobile-app-vs-sdk)\n13. [Retrieving Stored Consents](#retrieving-stored-consents)\n14. [Show Consent Popup on Demand](#show-consent-popup-on-demand)\n15. [Clearing Consent from `UserDefaults`](#clearing-consent-from-userdefaults)\n16. [Sharing Consent with Webviews](#sharing-consent-with-webviews)\n    - [Manual Token Addition](#manual-token-addition)\n    - [Automatic Token Addition](#automatic-token-addition)\n17. [TCF Vendor Management APIs](#tcf-vendor-management-apis)\n    - [Available TCF Vendor APIs](#available-tcf-vendor-apis)\n    - [Real-Time Vendor Consent Monitoring](#real-time-vendor-consent-monitoring)\n    - [Debug and Troubleshooting](#debug-and-troubleshooting)\n    - [Integration with IAB TCF Framework](#integration-with-iab-tcf-framework)\n18. [Events Overview](#events-overview)\n19. [Event Descriptions](#event-descriptions)\n20. [Event source for KPI tracking](#event-source-for-kpi-tracking)\n21. [Google Consent Mode v2 Integration with Axeptio SDK](#google-consent-mode-v2-integration-with-axeptio-sdk)\n22. [Google AdMob Integration with Axeptio SDK](#google-admob-integration-with-axeptio-sdk)\n\n\u003cbr\u003e\u003cbr\u003e\n\n## GitHub Access Token Documentation\nWhen setting up your project or accessing certain GitHub services, you may be prompted to create a GitHub Access Token. However, it's important to note that generating a GitHub access token requires a valid GitHub account and the enabling of two-factor authentication (2FA).\n\nAs a developer, you may not be immediately aware of these requirements, which could lead to confusion or authentication issues. To streamline the process, we recommend reviewing the official [GitHub Access Token Documentation](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) for detailed instructions on how to create a token. This guide will also clarify prerequisites such as the need for a validated GitHub account and the necessity of enabling 2FA.\n\nBy following these instructions, you'll be able to generate a GitHub Access Token smoothly, reducing any onboarding friction and avoiding potential authentication problems down the line.\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n\n## Requirements\nThe Axeptio iOS SDK is distributed as a pre-compiled binary package, delivered as an `XCFramework`. It supports iOS versions \u003e= 15.\n\n\u003e **Note:** The SDK supports iOS 15+. The sample apps in this repository target iOS 18, so the Podfile and Xcode examples below use 18.0 as a sample-app setting — not an SDK requirement. If your app targets iOS 15 or later, keep your own deployment target instead of copying the sample target verbatim.\n\nBefore starting, make sure you have:\n\n- iOS \u003e= 15 (SDK minimum requirement; this sample app targets iOS 18)\n- Xcode \u003e= 16 (required for iOS 18 development)\n- CocoaPods or Swift Package Manager for dependency management.\n\n**Note:** Please be aware that it is not possible to test a custom banner without an active and valid Axeptio plan. A valid Axeptio plan is required to configure and preview custom consent banners during development.\n\nEnsure the **following keys** are added to your `Info.plist` file to comply with app tracking and security policies:\n```xml\n\u003ckey\u003eNSUserTrackingUsageDescription\u003c/key\u003e\n\u003cstring\u003eYour data will be used to deliver personalized ads to you.\u003c/string\u003e\n\u003ckey\u003eNSAppTransportSecurity\u003c/key\u003e\n\u003cdict\u003e\n    \u003ckey\u003eNSAllowsArbitraryLoads\u003c/key\u003e\n    \u003ctrue/\u003e\n\u003c/dict\u003e\n```\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n\n## SDK Version\n\nThis sample app demonstrates the **Axeptio iOS SDK**. Current version: **2.1.2**\n\nFor release notes and changelog, see:\n- [SDK Releases](https://github.com/axeptio/axeptio-ios-sdk/releases)\n- [Release Notes v2.1.2](https://github.com/axeptio/axeptio-ios-sdk/releases/tag/2.1.2)\n\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n## Clone the Repository\nTo get started, clone the repository to your local machine:\n\n```bash\ngit clone https://github.com/axeptio/sample-app-ios\n```\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n## Adding the SDK\nThe package can be added to your project using either **CocoaPods** or **Swift Package Manager**. Both dependency managers for iOS and are supported by the Axeptio SDK.\n\n### Using CocoaPods\nIf your project uses CocoaPods, you can easily add the Axeptio SDK by following these steps:\n##### Prerequisites\n- Xcode version 16 or later\n- CocoaPods version compatible with XCFrameworks (latest version recommended), if you haven' already, install the latest version of [CocoaPods](https://guides.cocoapods.org/using/getting-started.html)\n##### Steps\n- Open your `Podfile` in the root directory of your project\n```ruby\nsource 'https://github.com/CocoaPods/Specs.git'\nplatform :ios, '18.0'\nuse_frameworks!\n\ntarget 'MyApp' do\n  pod 'AxeptioIOSSDK'\nend\n```\n- run the following command to install the dependency:\n```bash\npod install\n```\n\n### Using Swift Package Manager\nTo integrate the Axeptio iOS SDK into your Xcode project using Swift Package Manager, follow these steps:\n##### Steps\n- Open your Xcode project.\n- In the **Project Navigator**, select your project\n- Under the **PROJECT** section, navigate to the Package Dependencies tab\n- Click the **+** button to add a new package dependency\n- In the search bar, paste the following package URL: `https://github.com/axeptio/axeptio-ios-sdk`\n- Select the **AxeptioIOSSDK** package from the list of available packages\n- Click Add Package.\n- In the **Choose Package Products screen**, confirm the selection and click **Add Package** to complete the integration\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n## Initializing the SDK\nTo initialize the Axeptio SDK in your iOS project, import the `AxeptioSDK` module into your `AppDelegate` and initialize the SDK with the appropriate configuration.\n\n### `widgetType` parameter\n\n\u003e **Note (v2.1.0+):** `initialize()` requires a `widgetType` parameter. Use `.production` for all production apps.\n\n| Value | Description |\n|---|---|\n| `.production` | Loads the production Axeptio widget. **Use this in all production apps.** |\n| `.staging` | Loads the staging widget (appends `?axeptio_next` to the URL). For pre-release testing only. |\n| `.pullRequest` | Loads a PR-specific widget build. Use with the `widgetPR` parameter (PR number). |\n\n### Swift\n\n**In AppDelegate:**\n```swift\nimport UIKit\nimport AxeptioSDK\n\n@main\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -\u003e Bool {\n\n        // Basic initialization\n        Axeptio.shared.initialize(\n            targetService: .publisherTcf,  // or .brands\n            clientId: \"your-client-id\",\n            cookiesVersion: \"your-cookies-version\",\n            token: \"your-token\"  // optional\n        )\n\n        return true\n    }\n}\n```\n\n**With widget environment and cookie duration (SDK 2.1.0+):**\n```swift\nAxeptio.shared.initialize(\n    targetService: .publisherTcf,\n    clientId: \"your-client-id\",\n    cookiesVersion: \"your-cookies-version\",\n    token: \"your-token\",\n    widgetType: .production,               // .production, .staging, or .pr\n    widgetPR: nil,                         // PR hash when using .pr\n    cookiesDurationDays: 190,              // Default: 190 days\n    shouldUpdateCookiesDuration: false     // Default: false\n)\n```\n\n**Then in your ViewController:**\n```swift\nimport UIKit\nimport AxeptioSDK\n\nclass ViewController: UIViewController, UITableViewDataSource {\n\n    @IBOutlet weak var tableView: UITableView!\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n        // Register the cell identifier for UserDefaultsCell\n        tableView.register(UITableViewCell.self, forCellReuseIdentifier: \"UserDefaultsCell\")\n\n        // Call setupUI to show the consent popup when appropriate\n        Axeptio.shared.setupUI()\n    }\n\n    // UITableViewDataSource methods\n    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -\u003e Int {\n        return 1\n    }\n\n    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -\u003e UITableViewCell {\n        let cell = tableView.dequeueReusableCell(withIdentifier: \"UserDefaultsCell\", for: indexPath)\n        cell.textLabel?.text = \"UserDefaults Button\"\n        return cell\n    }\n}\n```\n\nIn your `AppDelegate`, initialize the SDK with `widgetType`:\n\n```swift\nimport AxeptioSDK\n\n// Production app (most common case)\nAxeptio.shared.initialize(\n    targetService: .brands,\n    clientId: \"\u003cYour Client ID\u003e\",\n    cookiesVersion: \"\u003cYour Cookies Version\u003e\",\n    widgetType: .production\n)\n\n// Pre-release / staging testing\nAxeptio.shared.initialize(\n    targetService: .brands,\n    clientId: \"\u003cYour Client ID\u003e\",\n    cookiesVersion: \"\u003cYour Cookies Version\u003e\",\n    widgetType: .staging\n)\n\n// PR-specific widget build\nAxeptio.shared.initialize(\n    targetService: .brands,\n    clientId: \"\u003cYour Client ID\u003e\",\n    cookiesVersion: \"\u003cYour Cookies Version\u003e\",\n    widgetType: .pullRequest,\n    widgetPR: \"123\"\n)\n```\n\n### Objective-C\n```objc\n#import \"AppDelegate.h\"\n\n@import AxeptioSDK;\n\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n\n    AxeptioService targetService = AxeptioServiceBrands; // or AxeptioServicePublisherTcf\n    // Production app (most common case)\n    [Axeptio.shared initializeWithTargetService:targetService\n                                       clientId:@\"\u003cYour Client ID\u003e\"\n                                 cookiesVersion:@\"\u003cYour Cookies Version\u003e\"\n                                     widgetType:WidgetTypeProduction];\n\n    // or with a token set from another device\n    [Axeptio.shared initializeWithTargetService:targetService\n                                       clientId:@\"\u003cYour Client ID\u003e\"\n                                 cookiesVersion:@\"\u003cYour Cookies Version\u003e\"\n                                     widgetType:WidgetTypeProduction\n                                          token:@\"\u003cToken\u003e\"];\n\n    return YES;\n}\n```\n\n**Note:** SDK 2.1.0+ parameters (widgetType, widgetPR, cookiesDurationDays, shouldUpdateCookiesDuration) are available in the Swift API. For Objective-C projects, refer to the SDK's Objective-C bridging headers for the complete API.\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n\n## Widget Environment Configuration (SDK 2.1.0+)\n\nThe SDK supports three widget environments for development and testing:\n\n### Environment Types\n\n- **Production** (`.production`) - Default production widget\n- **Staging** (`.staging`) - Staging environment for testing\n- **PR** (`.pr`) - Test specific PR deployments\n\n### Usage Examples\n\n**Production Environment (default):**\n```swift\nAxeptio.shared.initialize(\n    targetService: .publisherTcf,\n    clientId: \"your-client-id\",\n    cookiesVersion: \"your-version\",\n    widgetType: .production\n)\n```\n\n**Staging Environment:**\n```swift\nAxeptio.shared.initialize(\n    targetService: .publisherTcf,\n    clientId: \"your-client-id\",\n    cookiesVersion: \"your-version\",\n    widgetType: .staging\n)\n```\n\n**PR Environment (for testing specific changes):**\n```swift\nAxeptio.shared.initialize(\n    targetService: .publisherTcf,\n    clientId: \"your-client-id\",\n    cookiesVersion: \"your-version\",\n    widgetType: .pr,\n    widgetPR: \"59026e8d-b110-5452-afbe-6cb99c4e202a\"  // PR hash/version\n)\n```\n\n### When to Use Each Environment\n\n- **Production**: Live apps in production\n- **Staging**: Pre-release testing and QA\n- **PR**: Testing specific widget changes before they're merged to production\n\n## Cookie Duration Management (SDK 2.1.0+)\n\nControl how long user consent choices persist.\n\n### Configuration Options\n\n**cookiesDurationDays** (default: 190 days)\n- Sets the validity period for stored consent\n- User will be prompted again when consent expires\n\n**shouldUpdateCookiesDuration** (default: false)\n- When `true`: Duration end date is updated each time consent is saved\n- When `false`: Duration end date is set only once at first consent\n\n### Usage Examples\n\n**Default behavior (190 days, no updates):**\n```swift\nAxeptio.shared.initialize(\n    targetService: .publisherTcf,\n    clientId: \"your-client-id\",\n    cookiesVersion: \"your-version\"\n    // cookiesDurationDays: 190 (default)\n    // shouldUpdateCookiesDuration: false (default)\n)\n```\n\n**Custom duration (365 days):**\n```swift\nAxeptio.shared.initialize(\n    targetService: .publisherTcf,\n    clientId: \"your-client-id\",\n    cookiesVersion: \"your-version\",\n    cookiesDurationDays: 365\n)\n```\n\n**Update duration on each consent save:**\n```swift\nAxeptio.shared.initialize(\n    targetService: .publisherTcf,\n    clientId: \"your-client-id\",\n    cookiesVersion: \"your-version\",\n    cookiesDurationDays: 190,\n    shouldUpdateCookiesDuration: true  // Extends expiration on each consent save\n)\n```\n\n### Checking Remaining Consent Days\n\n```swift\nif let remainingDays = Axeptio.shared.getRemainingDaysForConsent() {\n    print(\"Consent expires in \\(remainingDays) days\")\n} else {\n    print(\"No consent stored or consent has expired\")\n}\n```\n\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n## Set up the SDK UI\n\u003e **[!IMPORTANT]** The `setupUI` method should be invoked **only** from your main/entry `UIViewController`, typically once during the application launch. By calling this method, the consent notice and preference views will be displayed **only if necessary** and **once the SDK is fully initialized**.\n\nIn order to display the consent and preference views and interact with the user, ensure that the `setupUI` method is called from your main `UIViewController`. The consent popup and preferences management will be shown based on the SDK initialization and the user's consent requirements.\n\n### Swift\n```swift\nimport UIKit\n\nimport AxeptioSDK\n​\nclass ViewController: UIViewController {\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        Axeptio.shared.setupUI()\n    }\n```\n}\n\n### Objective-C\n```objc\n#import \"ViewController.h\"\n@import AxeptioSDK;\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    // Initialize the UI elements required for consent display\n    [Axeptio.shared setupUI];  // Ensure that this is called from your main view controller\n}\n\n@end\n```\n#### Issues with the Consent Popup (Objective-C)\nIf the consent popup is not appearing as expected, follow these steps to troubleshoot and resolve the issue:\n\n###### Ensure Correct SDK Initialization in AppDelegate:\nVerify that the SDK is properly initialized in the `AppDelegate.m` file with the correct `clientId` and `cookiesVersion`\n```objc\n#import \"AppDelegate.h\"\n@import AxeptioSDK;\n\n@implementation AppDelegate\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n    AxeptioService targetService = AxeptioServiceBrands; // Or use AxeptioServicePublisherTcf if required\n\n    // Initialize with the provided Client ID and Cookies Version\n    [Axeptio.shared initializeWithTargetService:targetService\n                                    clientId:@\"\u003cYour Client ID\u003e\"\n                                cookiesVersion:@\"\u003cYour Cookies Version\u003e\"];\n\n    // Optional: Initialize with a Token from another device\n    [Axeptio.shared initializeWithTargetService:targetService\n                                    clientId:@\"\u003cYour Client ID\u003e\"\n                                cookiesVersion:@\"\u003cYour Cookies Version\u003e\"\n                                          token:@\"\u003cToken\u003e\"];\n\n    return YES;\n}\n\n@end\n```\n##### Correctly Calling `setupUI` from Main `UIViewController`:\nEnsure that the `setupUI` method is called from your main view controller (usually in `viewDidLoad` or a similar lifecycle method) to properly trigger the consent popup display.\n```objc\n#import \"ViewController.h\"\n@import AxeptioSDK;\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    // Call setupUI to show the consent popup when appropriate\n    [Axeptio.shared setupUI];  \n}\n\n@end\n```\n\n##### Check for Potential UI Blockers\nIf the consent popup is not showing, check if other views or modals are blocking it. Temporarily disable any other views that might interfere with the consent view to ensure it is not being hidden.\n\n##### Verify Event Logging for Popup Request:\nAdd a logging statement to confirm that the SDK is triggering the popup:\n```objc\n[Axeptio.shared setupUI];\nNSLog(@\"Consent popup triggered successfully\");\n```\n##### Ensure Proper Event Listeners are Set Up\nIf you are using event listeners to capture actions like the consent popup being closed, ensure that they are properly implemented and assigned.\n```objc\nAxeptioEventListener *axeptioEventListener = [[AxeptioEventListener alloc] init];\n[axeptioEventListener setOnPopupClosedEvent:^{\n    NSLog(@\"Consent popup closed by the user\");\n}];\n[Axeptio.shared setEventListener:axeptioEventListener];\n```\n##### SDK Version\nEnsure that you are using the latest version of the Axeptio SDK. Outdated versions might contain bugs that affect the popup behavior.\n\n### SwiftUI Integration\n\n##### Create a UIViewController subclass to call `setupUI()`\nTo integrate the Axeptio SDK into a SwiftUI app, first, create a subclass of `UIViewController` to invoke the SDK's `setupUI()` method. This view controller will later be integrated into SwiftUI using `UIViewControllerRepresentable`.\n```swift\nimport SwiftUI\nimport AxeptioSDK\n\n// Custom UIViewController to handle the SDK UI\nclass AxeptioViewController: UIViewController {\n\n    override func viewDidAppear(_ animated: Bool) {\n        super.viewDidAppear(animated)\n\n        // Call the setupUI method of the SDK to show the consent popup\n        Axeptio.shared.setupUI()\n    }\n}\n```\n\n##### Create a `UIViewControllerRepresentable` struct\nNext, create a struct that conforms to the `UIViewControllerRepresentable` protocol to integrate the custom `UIViewController` into the SwiftUI view hierarchy. This struct will allow you to display the `AxeptioViewController` as a SwiftUI view.\n```swift\n// Struct to integrate AxeptioViewController into SwiftUI\nstruct AxeptioView: UIViewControllerRepresentable {\n\n    // Create the custom UIViewController\n    func makeUIViewController(context: Context) -\u003e some UIViewController {\n        return AxeptioViewController()\n    }\n\n    // Required method, but not used in this case\n    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {}\n}\n```\n##### Connect with the AppDelegate using `UIApplicationDelegateAdaptor`\nIn SwiftUI, to properly set up the application and initialize the SDK, you'll need an entry point that implements the initialization logic in the `AppDelegate`. Use `UIApplicationDelegateAdaptor` to connect your `AppDelegate` to the SwiftUI app structure.\n```swift\nimport SwiftUI\nimport AxeptioSDK\n\n// AppDelegate that initializes the SDK\nclass AppDelegate: NSObject, UIApplicationDelegate {\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -\u003e Bool {\n        \n        // Initialize the Axeptio SDK with the Client ID, cookies version, and widget type\n        Axeptio.shared.initialize(\n            targetService: .brands,\n            clientId: \"\u003cYour Client ID\u003e\",\n            cookiesVersion: \"\u003cYour Cookies Version\u003e\",\n            widgetType: .production\n        )\n\n        return true\n    }\n}\n\n// Main SwiftUI app structure\n@main\nstruct YourSwiftUIApp: App {\n    // Bind the AppDelegate to the SwiftUI app structure\n    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate\n\n    var body: some Scene {\n        WindowGroup {\n            // Display the AxeptioView which contains the custom UIViewController\n            AxeptioView()\n        }\n    }\n}\n```\nBy following these steps, the Axeptio SDK will be correctly integrated into a SwiftUI app, and the logic for displaying the consent popup will be handled inside `viewDidAppear()` within the custom `UIViewController`\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n\n## Additional Configuration Show Popup When Returning from Background\nThe `setDisplayPopUpOnEnterForeground` property was added to control whether the consent popup should automatically appear when the app returns from the background.\nYou can set this property after the SDK has been initialized.\n\n#### Example Usage:\n```swift\n// Initialize the SDK as usual\nAxeptioSDK.initialize(...)\n\n// Configure the popup behavior when returning from background\nAxeptioSDK.setDisplayPopUpOnEnterForeground(true)\n```\n#### Behavior:\n- The user is in the main app that includes the SDK.\n- The user switches to another app → the main app goes to the background.\n- The user returns to the main app → the app comes back to the foreground.\n- If `setDisplayPopUpOnEnterForeground = true`, the popup is displayed.\n- If `setDisplayPopUpOnEnterForeground = false`, the popup is not displayed automatically.\n\n\n\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n## Axeptio SDK and App Tracking Transparency (ATT) Integration\n\nStarting with iOS 14.5, Apple introduced the App Tracking Transparency (ATT) framework, which requires apps to request user consent before tracking their data across other apps and websites. The Axeptio SDK does **not** automatically handle ATT permission requests, and it is your responsibility to ask for user consent for tracking and manage how the Axeptio Consent Management Platform (CMP) interacts with the ATT permission.\n\nThis steps will show you how to:\n\n- Request ATT permission.\n- Display the Axeptio consent notice after the user has accepted the ATT permission.\n- Handle cases where ATT permission is not requested or denied, and show the Axeptio CMP accordingly.\n\n#### Overview\n\nThe Axeptio SDK does not ask for the user’s tracking permission using the ATT framework. It is your responsibility to request this permission, and the way in which the ATT framework and Axeptio CMP interact depends on your app's logic.\n\nIn this sample app (targeting iOS 18.0 and above), you must use the `ATTrackingManager.requestTrackingAuthorization` function to ask for tracking consent. Based on the user's response, you can choose to show the Axeptio consent notice.\n\n#### Expected Flow:\n\n1. **ATT Permission**: Show the ATT permission dialog if the iOS version is 14 or later.\n2. **Axeptio Consent Notice**: Show the Axeptio consent notice if:\n   - iOS version is \u003e= 15.\n   - The user accepts the ATT permission.\n3. **Fallback**: If the ATT permission cannot be displayed (e.g., restricted, iOS \u003c 14, or user denied permission), you can still show the Axeptio CMP.\n\n## Swift Integration\n\nBelow is the complete Swift code to handle the ATT permission and initialize the Axeptio CMP.\n\n#### Request ATT Permission and Show Axeptio CMP\n\n```swift\nimport UIKit\nimport AppTrackingTransparency\nimport AxeptioSDK\n\nclass ViewController: UIViewController {\n\n    override func viewDidAppear(_ animated: Bool) {\n        super.viewDidAppear(animated)\n        Task {\n            await handleATTAndInitializeAxeptioCMP()\n        }\n    }\n\n    private func handleATTAndInitializeAxeptioCMP() async {\n        // ATT is always available since this sample app targets iOS 18+\n        let status = await ATTrackingManager.requestTrackingAuthorization()\n        let isAuthorized = (status == .authorized)\n        initializeAxeptioCMPUI(granted: isAuthorized)\n    }\n\n    private func initializeAxeptioCMPUI(granted: Bool) {\n        if granted {\n            // Initialize Axeptio CMP UI if ATT permission is granted\n            Axeptio.shared.setupUI()\n        } else {\n            // Handle case where user denies permission or ATT is restricted\n            Axeptio.shared.setUserDeniedTracking(denied: true)\n        }\n    }\n}\n```\n#### Key Points:\n- `ATTrackingManager.requestTrackingAuthorization`: Requests permission for tracking and returns the status.\n- `Axeptio.shared.setupUI()`: Initializes and shows the consent notice once ATT permission is granted.\n- **Fallback Handling**: If ATT permission is denied or unavailable, the Axeptio CMP can still be initialized depending on your requirements (e.g., on iOS versions before 14).\n\n#### This Sample App (iOS 18+):\n- Since this sample app targets iOS 18+, ATT is always available.\n- The app will request the ATT permission as it's always available.\n- the user grants permission, you can show the Axeptio consent notice using `Axeptio.shared.setupUI()`.\n\n## Objective-C Integration\nFor Objective-C, the implementation is quite similar. You’ll request ATT permission and initialize the Axeptio CMP based on the user's response.\n#### Request ATT Permission and Show Axeptio CMP\n\n```objc\n#import \u003cAppTrackingTransparency/AppTrackingTransparency.h\u003e\n@import AxeptioSDK;\n\n@implementation ViewController\n\n- (void)viewDidAppear:(BOOL)animated {\n    [super viewDidAppear:animated];\n    \n    // ATT is always available since we require iOS 18+\n    [self requestTrackingAuthorization];\n}\n\n- (void)requestTrackingAuthorization {\n    [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {\n        BOOL isAuthorized = (status == ATTrackingManagerAuthorizationStatusAuthorized);\n        [self initializeAxeptioCMPUI:isAuthorized];\n    }];\n}\n\n- (void)initializeAxeptioCMPUI:(BOOL)granted {\n    if (granted) {\n        // Initialize Axeptio CMP UI if ATT permission is granted\n        [Axeptio.shared setupUI];\n    } else {\n        // Handle case where user denies permission or ATT is restricted\n        [Axeptio.shared setUserDeniedTracking:false];\n    }\n}\n\n@end\n```\n#### Key Points:\n- `ATTrackingManager.requestTrackingAuthorizationWithCompletionHandler`: This method requests ATT permission and provides a callback with the status of the request.\n- `Axeptio.shared.setupUI()`: This method initializes and shows the consent notice after the user has granted ATT permission.\n- **Fallback Handling**: Similar to the Swift implementation, you can still show the Axeptio CMP even if the ATT permission is not granted or not available.\n\n#### Importante Notes:\n- **ATT Request Flow**: The ATT request must be shown at an appropriate time in your app flow, typically when the user first opens the app or at a point where they can make an informed decision.\n- **This sample app (iOS 18+)**: Since the sample app targets iOS 18+, the ATT framework is always available, so the app always requests ATT permission.\n- **Data Collection Disclosure**: Apple's App Store guidelines require you to disclose what data your app collects and how it uses it. Ensure your app’s privacy policy is up to date, and provide clear information on what data is being collected for tracking purposes.\n\n#### Useful Links\n- [Apple’s App Tracking Transparency Documentation](https://developer.apple.com/documentation/apptrackingtransparency)\n- [Apple's App Store Review Guidelines](https://developer.apple.com/app-store/review/guidelines/)\n\n## Handling Changes in ATT Settings\n\nThe SDK introduces improved handling of the App Tracking Transparency (ATT) flow. This enhancement addresses an issue where, after modifying ATT permissions via iOS Settings, the “Reopen Cookie Banner” feature continued redirecting users to Settings instead of re-displaying the consent banner.\n\nThe SDK offers a new setup option to control whether the consent banner should be displayed even if ATT is denied on the device.\n\n### New Configuration Flag\n\n```swift\nallowPopupDisplayWithRejectedDeviceTrackingPermissions: Bool\n```\n- Default: `false`\n- If set to `true`, the SDK bypasses the ATT check and allows the consent popup to be displayed even if ATT tracking is denied at the OS level.\nThis flag must be set during the Axeptio SDK setup phase.\n\n### Logic to Display the Consent Popup\n\nTo display the popup, the following conditions are now evaluated:\n\n| **Condition**                                | **Mandatory** | **Configurable** |\n|----------------------------------------------|---------------|------------------|\n| Network connectivity                         | Yes        | No            |\n| Device ATT status is \"Authorized\"            | No         | Yes (via `allowPopupDisplayWithRejectedDeviceTrackingPermissions`) |\n\n## Behavior of the `_ax_app_att_denied` flag\n- Set to `true` when ATT is denied on the device.\n- Automatically removed from local storage when ATT is later enabled, ensuring the consent banner can be displayed again.\n\nIf the user initially denies ATT and later re-enables it in iOS Settings, the app will now detect the change. Based on the ` allowPopupDisplayWithRejectedDeviceTrackingPermissions`  flag, it can choose to show the consent popup again — instead of redirecting the user to Settings.\n\n\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n## Responsibilities Mobile App vs SDK\n\nThe integration of the Axeptio SDK into your mobile application involves clear delineation of responsibilities between the mobile app and the SDK itself. Below are the distinct roles for each in handling user consent and tracking.\n\n#### **Mobile Application Responsibilities:**\n\n1. **Managing App Tracking Transparency (ATT) Flow:**\n   - The mobile app is responsible for initiating and managing the ATT authorization process on iOS 14.5 and later. This includes presenting the ATT request prompt at an appropriate time in the app's lifecycle.\n\n2. **Controlling the Display Sequence of ATT and CMP:**\n   - The app must determine the appropriate sequence for displaying the ATT prompt and the Axeptio consent management platform (CMP). Specifically, the app should request ATT consent before invoking the Axeptio CMP.\n\n3. **Compliance with App Store Privacy Labels:**\n   - The app must ensure accurate and up-to-date declarations of data collection practices according to Apple’s privacy label requirements, ensuring full transparency to users about data usage.\n\n4. **Event Handling and User Consent Updates:**\n   - The app is responsible for handling SDK events such as user consent actions. Based on these events, the app must adjust its behavior accordingly, ensuring that user consent is respected across sessions.\n\n#### **Axeptio SDK Responsibilities:**\n\n1. **Displaying the Consent Management Interface:**\n   - The Axeptio SDK is responsible for rendering the user interface for the consent management platform (CMP) once triggered. It provides a customizable interface for users to give or revoke consent.\n\n2. **Storing and Managing User Consent Choices:**\n   - The SDK securely stores and manages user consent choices, maintaining a persistent record that can be referenced throughout the app's lifecycle.\n\n3. **Sending Consent Status via APIs:**\n   - The SDK facilitates communication of the user's consent status through APIs, allowing the app to be updated with the user’s preferences.\n\n4. **No Implicit Handling of ATT Permissions:**\n   - The Axeptio SDK does **not** manage the App Tracking Transparency (ATT) permission flow. It is the host app's responsibility to request and handle ATT permissions explicitly before displaying the consent management interface. The SDK functions only once the ATT permission is granted (or bypassed due to platform restrictions).\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n## Retrieving Stored Consents\n\nTo retrieve user consent preferences stored by the Axeptio SDK, you can access the data stored in the `UserDefaults`. The SDK automatically stores consent information in `UserDefaults`, making it accessible for the app to retrieve whenever necessary.\n\n#### **Retrieving Consents in Swift:**\n\nIn Swift, you can access the stored consents by using the `UserDefaults` API. This allows you to query specific consent keys, such as the one you previously stored when the user made their choices.\n\n```swift\nlet consent = UserDefaults.standard.object(forKey: \"Key\")\n```\nThis will return the consent data associated with the provided key. Ensure that you know the specific key associated with the consent data you're trying to access.\n\n#### **Retrieving Consents in Objective-C:**\nIn Objective-C, you can access the stored consents using the `NSUserDefaults` class. The following code demonstrates how to retrieve the consent data stored in `NSUserDefaults`:\n```objc\nid consent = [[NSUserDefaults standardUserDefaults] objectForKey:@\"Key\"];\n```\nThis will return the consent information associated with the specified key.\n\nFor a more detailed breakdown of how the Axeptio SDK handles stored consent values, including cookie management and other privacy-related data, please refer to the [Axeptio SDK Documentation](https://support.axeptio.eu/hc/en-gb/articles/8558526367249-Does-Axeptio-deposit-cookies).\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n## Show Consent Popup on Demand\n\nYou can request the consent popup to be displayed programmatically at any point in your app’s lifecycle. This can be useful when you need to show the consent screen after a specific user action or event, rather than automatically when the app starts.\n- This method will display the consent management platform (CMP) UI based on the user's current consent status.\n- Make sure to trigger the consent popup at the appropriate moment to avoid interrupting the user experience.\n- The consent popup can be triggered even after the app has been launched and after the consent has already been obtained, allowing you to ask for consent again if necessary.\n\n#### Swift Implementation:\nTo trigger the consent popup on demand in Swift, you can call the `showConsentScreen()` method on the `Axeptio.shared` instance:\n\n```swift\nAxeptio.shared.showConsentScreen()\n```\n#### Objective-C Implementation\n\nSimilarly, in Objective-C, the same method can be invoked to show the consent screen on demand:\n```objc\n[Axeptio.shared showConsentScreen];\n```\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n## Clearing Consent from `UserDefaults`\n\nA method is provided to clear the stored consent information from `UserDefaults`. This allows you to reset the user's consent status and remove any previously stored preferences.\n- This method will remove the stored consent data, which may include preferences or other consent-related information stored in UserDefaults.\n- It's useful for scenarios where the user needs to update their consent choices or when you want to reset consent state for any other reason.\n- Once consent is cleared, the app may re-prompt the user for consent based on the current configuration or flow.\n\n#### Swift Implementation:\nTo clear the consent from `UserDefaults` in Swift, simply invoke the `clearConsent()` method on the shared `Axeptio` instance:\n\n```swift\nAxeptio.shared.clearConsent()\n```\n#### Objective-C Implementation:\nSimilarly, in Objective-C, you can call the clearConsent method on the shared Axeptio instance to remove the stored consent:\n```objc\n[Axeptio.shared clearConsent];\n```\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n## Sharing Consent with Webviews\n\nThis functionality is available only for the **Publishers Service**. It allows you to pass the consent token to webviews or external URLs to maintain consistency across platforms. You can append the `axeptioToken` to any URL to share the user’s consent status.\n##### Key Points:\n- **Manual Approach:** Developers can append the `axeptioToken` and query item manually to any URL using the standard `URLComponents` method.\n- **Automatic Approach:** Use the `appendAxeptioTokenToURL` function to automatically append the token to any URL.\n- **Publisher's Service:** This feature is available only for the Publishers service in Axeptio.\n  \n### Manual Token Addition\nYou can manually append the `axeptioToken` to any URL using the `axeptioToken` and `keyAxeptioTokenQueryItem` properties.\n\n#### Swift Implementation:\n```swift\n// Access the token and query item name\nlet axeptioToken = Axeptio.shared.axeptioToken\nlet keyAxeptioTokenQueryItem = Axeptio.shared.keyAxeptioTokenQueryItem\n\n// Append the token to the URL\nvar urlComponents = URLComponents(string: \"\u003cYour URL\u003e\")\nurlComponents?.queryItems = [\n    URLQueryItem(name: keyAxeptioTokenQueryItem, value: axeptioToken)\n]\n\n// Construct the updated URL with the appended token\nlet updatedURL = urlComponents?.url\n```\n\n#### Objective-C Implementation:\n```objc\n// Access the token and query item name\nNSString *axeptioToken = [Axeptio.shared axeptioToken];\nNSString *keyAxeptioTokenQueryItem = [Axeptio.shared keyAxeptioTokenQueryItem];\n\n// Append the token to the URL\nNSURLComponents *urlComponents = [[NSURLComponents alloc] initWithString:@\"\u003cYour URL\u003e\"];\nurlComponents.queryItems = @[\n    [NSURLQueryItem queryItemWithName:keyAxeptioTokenQueryItem value:axeptioToken]\n];\n\n// Construct the updated URL with the appended token\nNSURL *updatedURL = urlComponents.URL;\n```\n### Automatic Token Addition\nAlternatively, you can use the `appendAxeptioTokenToURL` method to automatically append the token to the URL.\n\n#### Swift Implementation:\n```swift\n// Automatically append the consent token to the URL\nlet updatedURL = Axeptio.shared.appendAxeptioTokenToURL(\"\u003cYour URL\u003e\", token: Axeptio.shared.axeptioToken)\n```\n#### Objective-C Implementation:\n```objc\n// Automatically append the consent token to the URL\nNSURL *updatedURL = [Axeptio.shared appendAxeptioTokenToURL:@\"\u003cYour URL\u003e\" token:[Axeptio.shared axeptioToken]];\n```\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n## TCF Vendor Management APIs\n\nThe Axeptio SDK provides comprehensive APIs for managing vendor consent in TCF (Transparency and Consent Framework) mode. These APIs allow you to query individual vendor consent states, implement vendor-specific functionality, and maintain compliance with IAB TCF requirements.\n\n#### When to Use TCF Vendor APIs\n\nUse these APIs when your app needs to:\n- Query consent status for specific advertising vendors\n- Implement vendor-specific features or ad serving logic\n- Build custom vendor management UI components\n- Debug consent collection issues in TCF mode\n- Ensure compliance with specific vendor requirements\n\n### Available TCF Vendor APIs\n\n#### 1. Get All Vendor Consents\n\nRetrieve a complete dictionary of all vendor consent states.\n\n##### Swift Implementation:\n```swift\n// Get all vendor consent states as a dictionary\nlet allVendorConsents = Axeptio.shared.getVendorConsents()\n\n// Dictionary format: [vendorID: consentStatus]\n// vendorID (Int): The IAB vendor ID\n// consentStatus (Bool): true = consented, false = refused\n\nfor (vendorId, hasConsent) in allVendorConsents {\n    print(\"Vendor \\(vendorId): \\(hasConsent ? \"Consented\" : \"Refused\")\")\n}\n\n// Example usage for ad serving logic\nif let googleVendorConsent = allVendorConsents[755] { // Google's vendor ID\n    if googleVendorConsent {\n        // Enable Google ads\n        enableGoogleAds()\n    } else {\n        // Disable Google ads or show alternative content\n        disableGoogleAds()\n    }\n}\n```\n\n##### Objective-C Implementation:\n```objc\n// Get all vendor consent states\nNSDictionary\u003cNSNumber *, NSNumber *\u003e *allVendorConsents = [Axeptio.shared getVendorConsents];\n\n// Iterate through all vendor consents\nfor (NSNumber *vendorId in allVendorConsents) {\n    BOOL hasConsent = [allVendorConsents[vendorId] boolValue];\n    NSLog(@\"Vendor %@: %@\", vendorId, hasConsent ? @\"Consented\" : @\"Refused\");\n}\n\n// Example usage for specific vendor\nNSNumber *googleVendorId = @755; // Google's vendor ID\nif (allVendorConsents[googleVendorId]) {\n    BOOL googleConsent = [allVendorConsents[googleVendorId] boolValue];\n    if (googleConsent) {\n        // Enable Google services\n        [self enableGoogleAds];\n    } else {\n        // Disable Google services\n        [self disableGoogleAds];\n    }\n}\n```\n\n#### 2. Get Consented Vendors Only\n\nRetrieve a list of vendor IDs that have been granted consent.\n\n##### Swift Implementation:\n```swift\n// Get array of vendor IDs with consent granted\nlet consentedVendors = Axeptio.shared.getConsentedVendors()\n\nprint(\"Number of consented vendors: \\(consentedVendors.count)\")\nprint(\"Consented vendor IDs: \\(consentedVendors)\")\n\n// Check if specific vendors are consented\nlet criticalVendors = [755, 32, 76] // Example vendor IDs\nlet consentedCriticalVendors = criticalVendors.filter { consentedVendors.contains($0) }\n\nif consentedCriticalVendors.count == criticalVendors.count {\n    print(\"All critical vendors have consent\")\n    enablePremiumFeatures()\n} else {\n    print(\"Missing consent from some critical vendors\")\n    enableBasicFeatures()\n}\n```\n\n##### Objective-C Implementation:\n```objc\n// Get array of consented vendor IDs\nNSArray\u003cNSNumber *\u003e *consentedVendors = [Axeptio.shared getConsentedVendors];\n\nNSLog(@\"Number of consented vendors: %lu\", (unsigned long)consentedVendors.count);\nNSLog(@\"Consented vendor IDs: %@\", consentedVendors);\n\n// Check for specific vendors\nNSArray\u003cNSNumber *\u003e *criticalVendors = @[@755, @32, @76]; // Example vendor IDs\nNSMutableArray\u003cNSNumber *\u003e *consentedCriticalVendors = [[NSMutableArray alloc] init];\n\nfor (NSNumber *vendorId in criticalVendors) {\n    if ([consentedVendors containsObject:vendorId]) {\n        [consentedCriticalVendors addObject:vendorId];\n    }\n}\n\nif (consentedCriticalVendors.count == criticalVendors.count) {\n    NSLog(@\"All critical vendors have consent\");\n    [self enablePremiumFeatures];\n} else {\n    NSLog(@\"Missing consent from some critical vendors\");\n    [self enableBasicFeatures];\n}\n```\n\n#### 3. Get Refused Vendors Only\n\nRetrieve a list of vendor IDs that have been refused consent.\n\n##### Swift Implementation:\n```swift\n// Get array of vendor IDs with consent refused\nlet refusedVendors = Axeptio.shared.getRefusedVendors()\n\nprint(\"Number of refused vendors: \\(refusedVendors.count)\")\nprint(\"Refused vendor IDs: \\(refusedVendors)\")\n\n// Disable services for refused vendors\nfor vendorId in refusedVendors {\n    disableVendorServices(vendorId: vendorId)\n}\n\n// Check if any essential vendors were refused\nlet essentialVendors = [755, 32] // Example essential vendor IDs\nlet refusedEssentialVendors = essentialVendors.filter { refusedVendors.contains($0) }\n\nif !refusedEssentialVendors.isEmpty {\n    print(\"Essential vendors were refused: \\(refusedEssentialVendors)\")\n    showAlternativeContent()\n}\n```\n\n##### Objective-C Implementation:\n```objc\n// Get array of refused vendor IDs\nNSArray\u003cNSNumber *\u003e *refusedVendors = [Axeptio.shared getRefusedVendors];\n\nNSLog(@\"Number of refused vendors: %lu\", (unsigned long)refusedVendors.count);\nNSLog(@\"Refused vendor IDs: %@\", refusedVendors);\n\n// Disable services for refused vendors\nfor (NSNumber *vendorId in refusedVendors) {\n    [self disableVendorServicesWithVendorId:[vendorId integerValue]];\n}\n\n// Check for essential vendors\nNSArray\u003cNSNumber *\u003e *essentialVendors = @[@755, @32]; // Example essential vendor IDs\nNSMutableArray\u003cNSNumber *\u003e *refusedEssentialVendors = [[NSMutableArray alloc] init];\n\nfor (NSNumber *vendorId in essentialVendors) {\n    if ([refusedVendors containsObject:vendorId]) {\n        [refusedEssentialVendors addObject:vendorId];\n    }\n}\n\nif (refusedEssentialVendors.count \u003e 0) {\n    NSLog(@\"Essential vendors were refused: %@\", refusedEssentialVendors);\n    [self showAlternativeContent];\n}\n```\n\n#### 4. Check Individual Vendor Consent\n\nCheck consent status for a specific vendor ID.\n\n##### Swift Implementation:\n```swift\n// Check consent for specific vendor\nlet vendorId = 755 // Example: Google's vendor ID\nlet isConsented = Axeptio.shared.isVendorConsented(vendorId)\n\nif isConsented {\n    print(\"Vendor \\(vendorId) has consent\")\n    enableVendorServices(vendorId: vendorId)\n} else {\n    print(\"Vendor \\(vendorId) was refused or not found\")\n    disableVendorServices(vendorId: vendorId)\n}\n\n// Example usage in ad loading logic\nfunc loadAdsForVendor(_ vendorId: Int) {\n    guard Axeptio.shared.isVendorConsented(vendorId) else {\n        print(\"Cannot load ads - vendor \\(vendorId) consent denied\")\n        return\n    }\n    \n    // Proceed with ad loading\n    loadVendorAds(vendorId: vendorId)\n}\n\n// Check multiple vendors efficiently\nlet vendorsToCheck = [755, 32, 76, 81] // Multiple vendor IDs\nfor vendorId in vendorsToCheck {\n    let hasConsent = Axeptio.shared.isVendorConsented(vendorId)\n    print(\"Vendor \\(vendorId): \\(hasConsent ? \"Consented\" : \"Refused\")\")\n}\n```\n\n##### Objective-C Implementation:\n```objc\n// Check consent for specific vendor\nNSInteger vendorId = 755; // Example: Google's vendor ID\nBOOL isConsented = [Axeptio.shared isVendorConsented:vendorId];\n\nif (isConsented) {\n    NSLog(@\"Vendor %ld has consent\", (long)vendorId);\n    [self enableVendorServicesWithVendorId:vendorId];\n} else {\n    NSLog(@\"Vendor %ld was refused or not found\", (long)vendorId);\n    [self disableVendorServicesWithVendorId:vendorId];\n}\n\n// Example usage in ad loading logic\n- (void)loadAdsForVendor:(NSInteger)vendorId {\n    if (![Axeptio.shared isVendorConsented:vendorId]) {\n        NSLog(@\"Cannot load ads - vendor %ld consent denied\", (long)vendorId);\n        return;\n    }\n    \n    // Proceed with ad loading\n    [self loadVendorAdsWithVendorId:vendorId];\n}\n\n// Check multiple vendors\nNSArray\u003cNSNumber *\u003e *vendorsToCheck = @[@755, @32, @76, @81]; // Multiple vendor IDs\nfor (NSNumber *vendorNumber in vendorsToCheck) {\n    NSInteger vendorId = [vendorNumber integerValue];\n    BOOL hasConsent = [Axeptio.shared isVendorConsented:vendorId];\n    NSLog(@\"Vendor %ld: %@\", (long)vendorId, hasConsent ? @\"Consented\" : @\"Refused\");\n}\n```\n\n### Real-Time Vendor Consent Monitoring\n\nMonitor vendor consent changes by combining the TCF APIs with event listeners:\n\n#### Swift Implementation:\n```swift\n// Set up event listener for consent changes\nlet eventListener = AxeptioEventListener()\n\neventListener.onConsentChanged = { [weak self] in\n    // Refresh vendor consent states when user changes preferences\n    self?.updateVendorBasedFeatures()\n}\n\neventListener.onPopupClosedEvent = { [weak self] in\n    // Update UI or services after popup is closed\n    self?.refreshVendorStates()\n}\n\nAxeptio.shared.setEventListener(eventListener)\n\nfunc updateVendorBasedFeatures() {\n    let consentedVendors = Axeptio.shared.getConsentedVendors()\n    \n    // Update ad serving\n    updateAdConfiguration(consentedVendors: consentedVendors)\n    \n    // Update analytics\n    updateAnalyticsVendors(consentedVendors: consentedVendors)\n    \n    // Update UI elements\n    updateVendorBasedUI(consentedVendors: consentedVendors)\n}\n```\n\n#### Objective-C Implementation:\n```objc\n// Set up event listener for consent changes\nAxeptioEventListener *eventListener = [[AxeptioEventListener alloc] init];\n\n[eventListener setOnConsentChanged:^{\n    // Refresh vendor consent states when user changes preferences\n    [self updateVendorBasedFeatures];\n}];\n\n[eventListener setOnPopupClosedEvent:^{\n    // Update UI or services after popup is closed\n    [self refreshVendorStates];\n}];\n\n[Axeptio.shared setEventListener:eventListener];\n\n- (void)updateVendorBasedFeatures {\n    NSArray\u003cNSNumber *\u003e *consentedVendors = [Axeptio.shared getConsentedVendors];\n    \n    // Update ad serving\n    [self updateAdConfigurationWithConsentedVendors:consentedVendors];\n    \n    // Update analytics\n    [self updateAnalyticsVendorsWithConsentedVendors:consentedVendors];\n    \n    // Update UI elements\n    [self updateVendorBasedUIWithConsentedVendors:consentedVendors];\n}\n```\n\n### Debug and Troubleshooting\n\n#### Using Debug Information API\n\n```swift\n// Get detailed consent debug information\nlet debugInfo = Axeptio.shared.getConsentDebugInfo(preferenceKey: nil)\nprint(\"Consent Debug Info: \\(debugInfo)\")\n\n// Get debug info for specific preference\nlet specificDebugInfo = Axeptio.shared.getConsentDebugInfo(preferenceKey: \"IABTCF_VendorConsents\")\nprint(\"Vendor Consents Debug: \\(specificDebugInfo)\")\n```\n\n#### Common Issues and Solutions\n\n1. **Vendor Count Mismatch**: If the number of consented + refused vendors doesn't match the total, check for:\n   - Timing issues during consent processing\n   - Vendors that haven't been explicitly consented or refused\n   - Edge cases in vendor ID ranges\n\n2. **Missing Vendor Consent**: If a vendor appears in `getVendorConsents()` but not in `getConsentedVendors()` or `getRefusedVendors()`:\n   - Verify the vendor is part of your TCF configuration\n   - Check if consent was collected properly\n   - Review the TCF string data in UserDefaults\n\n3. **Performance Considerations**:\n   - Cache vendor consent states when possible\n   - Use `isVendorConsented()` for single vendor checks\n   - Monitor consent changes with event listeners rather than polling\n\n### Integration with IAB TCF Framework\n\nThe vendor APIs work with standard IAB TCF data stored in UserDefaults:\n\n```swift\n// Access raw TCF data for advanced use cases\nlet tcfString = UserDefaults.standard.string(forKey: \"IABTCF_TCString\")\nlet vendorConsents = UserDefaults.standard.string(forKey: \"IABTCF_VendorConsents\")\nlet vendorLegitimateInterests = UserDefaults.standard.string(forKey: \"IABTCF_VendorLegitimateInterests\")\n\n// The Axeptio APIs provide a higher-level interface to this data\n// But you can access the raw data when needed for compliance reporting\n```\n\nFor a complete implementation example with UI, debugging, and real-time monitoring, refer to the `VendorConsentViewController.swift` in the sample application.\n\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n### SDK Events - Handling User Consent and Tracking\n\nThe Axeptio SDK provides various events to notify your application when the user interacts with the consent management platform (CMP). By subscribing to these events, you can track consent status changes, consent popup visibility, and updates to Google Consent Mode. This section explains how to subscribe to and handle these events.\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n## Events Overview\n\n#### Available Events\n1. **onPopupClosedEvent**  \n   This event is triggered when the consent popup is closed. You can use this event to perform actions after the consent popup is dismissed, such as storing consent status or updating app behavior based on user preferences.\n\n2. **onConsentChanged**  \n   This event is triggered when the user gives or updates their consent. It allows you to handle the changes in user consent status, enabling you to take appropriate actions in your app.\n\n3. **onGoogleConsentModeUpdate**  \n   This event is triggered when the Google Consent V2 status is updated. It allows you to react to changes in Google’s consent mode, which can affect tracking behaviors and user data processing preferences.\n\n### Using AxeptioEventListener to Subscribe to Events\n\n#### Swift Integration\n\nTo handle events in Swift, you need to create an `AxeptioEventListener` instance and set event handlers for the desired events.\n\n```swift\nlet axeptioEventListener = AxeptioEventListener()\n\n// Handle popup closed event\naxeptioEventListener.onPopupClosedEvent = {\n    // Actions to take when the consent popup is closed\n    // Retrieve consents from UserDefaults\n    // Check user preferences\n    // Run external processes or services based on user consents\n}\n\n// Handle consent changed event\naxeptioEventListener.onConsentChanged = {\n    // Actions to take when the user consent status changes\n    // For example, trigger analytics, update UI, or change app behavior\n}\n\n// Handle Google Consent Mode update event\naxeptioEventListener.onGoogleConsentModeUpdate = { consents in\n    // Actions to take when the Google Consent V2 status is updated\n    // Example: Update tracking configuration based on new consent mode status\n}\n\nAxeptio.shared.setEventListener(axeptioEventListener)\n```\n\n#### Objective-C Integration\nFor Objective-C, you can set up the `AxeptioEventListener` and subscribe to the events similarly.\n```objc\nAxeptioEventListener *axeptioEventListener = [[AxeptioEventListener alloc] init];\n\n// Handle popup closed event\n[axeptioEventListener setOnPopupClosedEvent:^{\n    // Actions to take when the consent popup is closed\n    // For example, store consent data or update app behavior\n}];\n\n// Handle consent changed event\n[axeptioEventListener setOnConsentChanged:^{\n    // Actions to take when the user changes their consent\n    // Example: Update app functionality based on new consent status\n}];\n\n// Handle Google Consent Mode update event\n[axeptioEventListener setOnGoogleConsentModeUpdate:^(GoogleConsentV2 *consents) {\n    // Actions to take when the Google Consent V2 status is updated\n    // Example: Adjust app tracking based on Google's updated consent mode\n}];\n\n[Axeptio.shared setEventListener:axeptioEventListener];\n```\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n## Event Descriptions\n\n#### `onPopupClosedEvent`\n- **Description**: This event is triggered when the consent popup is closed, either by the user granting or denying consent.\n- **Use Case**: You can use this event to perform any actions after the user has seen or interacted with the consent popup, such as storing consent preferences, updating the UI, or triggering other processes based on user consent.\n\n#### `onConsentChanged`\n- **Description**: This event is triggered when a user’s consent changes. This could happen when a user grants or revokes consent, or updates their consent preferences.\n- **Use Case**: You can use this event to track changes in user consent status, update app behavior based on new consent, or trigger specific services according to user preferences.\n\n#### `onGoogleConsentModeUpdate`\n- **Description**: This event is triggered when the Google Consent Mode is updated. It provides information on how Google’s consent management framework has changed, such as when a user grants or withdraws consent for Google’s tracking technologies.\n- **Use Case**: If your app integrates with Google services (e.g., Google Analytics or AdSense), you can use this event to update your tracking configuration or handle user data processing preferences according to Google’s consent mode.\n\n### Event Handling Best Practices\n\n#### Popup Visibility\nEnsure that the consent popup is shown at an appropriate time to avoid interrupting the user experience. Use `onPopupClosedEvent` to determine when the user has seen or interacted with the consent popup, and avoid displaying it again unnecessarily.\n\n#### User Consent Flow\nConsider how the `onConsentChanged` event integrates into your app’s data processing workflow. Ensure that your app adapts its behavior according to the user’s preferences, such as enabling/disabling tracking or collecting personal data.\n\n#### Google Consent Mode\nUse the `onGoogleConsentModeUpdate` event to monitor and respond to changes in Google’s consent status. This ensures that your app aligns with Google’s tracking and data collection policies based on the user’s consent.\n\nBy using `AxeptioEventListener` to listen for consent-related events, you can effectively manage user consent in your app, ensure compliance with privacy regulations, and improve the user experience. The SDK triggers these events based on user actions, so you can tailor your app’s functionality to respect the user’s consent preferences.\n\n### Event Handling with the Axeptio SDK\n\nIntegrating Axeptio into your iOS app includes managing user consent and cookie configuration events. To facilitate this, the Axeptio SDK triggers events that can be received by the host app. In this section, we'll explore how to receive and manage these events, including options for handling them via callbacks, publishers (using Combine), and delegates.\n\n#### Event Types\n\nSome of the events Axeptio can send include:\n\n- **app:cookies:ready**: Indicates that the SDK is ready to manage consent for cookies, with a payload describing the current state (e.g., whether the CMP is visible or not).\n\n  Example payload:\n```json\n  {\n    \"name\": \"app:cookies:ready\",\n    \"payload\": \"{\\\"showCmp\\\":false,\\\"reason\\\":\\\"The subscription does not allow the use of the SDK app mode\\\"}\"\n  }\n ```\nThese events are sent by the system to notify the host app that the user has interacted with the consent system or that an action related to consent has been completed.\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n\u003c!--  \n## How to Receive Events\n\nTo listen for events sent by the SDK, you can use one of the following approaches:\n\n#### Callback (Closure)\nThe simplest way to receive events is by using a closure callback. You can define a property of type closure to handle the event and its associated payload.\n**Implementation Example:**\n```swift\npublic class Axeptio {\n    public var onEventReceived: ((Result\u003cPayload, Error\u003e) -\u003e Void)?\n    \n    func someMethod() {\n        // Send success event\n        onEventReceived?(.success(payloadObject))\n        \n        // Send failure event\n        onEventReceived?(.failure(error))\n    }\n}\n\n// *** Usage in host app:\nAxeptio.shared.onEventReceived = { [weak self] result in\n    switch result {\n    case .success(let payload):\n        // Handle the received payload\n    case .failure(let error):\n        // Handle the error\n    }\n}\n```\nIn this example, the host app can listen to the event and respond accordingly, either by handling the payload or managing errors.\n#### Publisher (Combine Framework)\nIf your app uses the Combine framework, you can take advantage of a PassthroughSubject to send and receive events. This approach is helpful if your app is already designed to use Combine.\n**Implementation Example**\n```swift\nimport Combine\n\npublic class Axeptio {\n    public static let shared = Axeptio()\n    public var onConsentEvent = PassthroughSubject\u003cPayload, Never\u003e()\n    \n    func someMethod() {\n        // Send the event via publisher\n        onConsentEvent.send(payloadObject)\n    }\n}\n\n// *** Usage in host app:\nAxeptio.shared.onConsentEvent\n    .sink { [weak self] event in\n        // Handle the received event\n    }\n```\nIn this case, the host app uses the `sink` method to receive the payload and handle the event.\n#### Delegate (Protocol)\nAnother possible approach is to use a **delegate protocol** to receive events. This method is particularly useful if you want to centralize event management in a delegate object.\n\n**Implementation Example:**\n```swift\npublic protocol AxeptioEventDelegate: AnyObject {\n    func didReceiveEvent(_ event: Payload)\n    func didFailWithError(_ error: Error)\n}\n\npublic class Axeptio {\n    public static let shared = Axeptio()\n    public weak var delegate: AxeptioEventDelegate?\n    \n    func someMethod() {\n        // Notify the delegate of the event\n        delegate?.didReceiveEvent(payloadObject)\n        \n        // Notify the delegate of an error\n        delegate?.didFailWithError(error)\n    }\n}\n\n// *** Usage in host app:\nclass ViewController: UIViewController {\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        // Set the delegate\n        Axeptio.shared.delegate = self\n    }\n}\n\n// MARK: - AxeptioEventDelegate methods\nextension ViewController: AxeptioEventDelegate {\n    func didReceiveEvent(_ event: Payload) {\n        // Handle the received event\n    }\n    \n    func didFailWithError(_ error: Error) {\n        // Handle the error\n    }\n}\n```\nIn this example, the host app implements the AxeptioEventDelegate protocol and receives events through the delegate.\n\n\n\n\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e --\u003e\n\n## Event source for KPI tracking\nTo ensure proper KPI attribution in the back office, the App SDK now adds a specific `event_source` value when emitting TCF events from the WebView.\n\n- `sdk-app-tcf` → Used when TCF is loaded in a mobile app (via WebView)\n- `sdk-web-tcf` → Used when TCF is loaded on a website\n- `sdk-app-brands` → Used when the brands widget is loaded in an app\n- `sdk-web` → Used for regular brands on the web\n\nThis change ensures that events triggered from the App SDK are not incorrectly counted under Web KPIs.\n\nNo additional configuration is needed on your side if you are using the official SDK integration.\n\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e --\u003e\n## Google Consent Mode v2 Integration with Axeptio SDK\n\nThis steps explains how to integrate Google Consent Mode v2 with the Axeptio SDK for managing user consent within your iOS application. It covers Firebase Analytics integration and provides code examples in both Swift and Objective-C.\n\n#### Prerequisites\n\nBefore starting the integration, ensure that:\n\n- Firebase Analytics is already added to your iOS project.\n  - [Firebase Analytics SDK Documentation](https://firebase.google.com/docs/analytics)\n  \n- You have integrated the [Axeptio SDK](https://www.axeptio.eu/en/).\n  - [Axeptio SDK Documentation](https://support.axeptio.eu/hc/en-gb)\n\n#### Overview\n\nWhen user consent is collected through your Consent Management Platform (CMP), the Axeptio SDK triggers the necessary events and updates Firebase Analytics' consent states accordingly. This ensures that your app remains compliant with privacy regulations, especially when using services like Google Analytics or AdSense.\n\nThe integration allows the app to send consent preferences to both Google and Firebase systems. The Google Consent Mode is updated whenever the user modifies their consent preferences via the CMP, and this information is sent to Firebase for analytics tracking.\n\n#### Key Steps to Integrate Google Consent Mode v2 with Axeptio SDK\n\n##### 1. **Register for Google Consent Updates**\n   \nYou need to listen for consent updates that come from the user interaction with the Axeptio SDK. These events will notify your application when a user's consent preferences change, especially regarding Google-related services like Google Analytics, Ad Storage, and others.\n\n- The Axeptio SDK will automatically set the `IABTCF_EnableAdvertiserConsentMode` key in `UserDefaults` to `true` once the user has consented to advertising data collection.\n\n###### 2. **Map Consent Types and Status**\n   \nThe Google Consent Mode v2 categorizes consent statuses into different types like `analyticsStorage`, `adStorage`, and `adPersonalization`. You must map these consent statuses to the corresponding Firebase Analytics consent models. This ensures that Firebase respects the user’s privacy choices.\n\n##### 3. **Update Firebase Analytics Consent Statuses**\n\nOnce the Google Consent update is received from the Axeptio SDK, you must update the consent statuses in Firebase Analytics. Use the `setConsent()` method provided by Firebase to sync the user’s preferences.\n\n##### 4. **Set Up the Event Listener for Google Consent Updates**\n\nThe Axeptio SDK triggers events, allowing you to listen for changes in Google’s consent status. You can then map the updates and forward the consent status to Firebase Analytics.\n\n#### Code Examples\n\n##### Swift\n\n```swift\n// Set up the listener for Google Consent Mode updates\naxeptioEventListener.onGoogleConsentModeUpdate = { consents in\n    // Mapping Axeptio consent statuses to Firebase Analytics consent types\n    Analytics.setConsent([\n        .analyticsStorage: consents.analyticsStorage == GoogleConsentStatus.granted ? ConsentStatus.granted : ConsentStatus.denied,\n        .adStorage: consents.adStorage == GoogleConsentStatus.denied ? ConsentStatus.granted : ConsentStatus.denied,\n        .adUserData: consents.adUserData == GoogleConsentStatus.denied ? ConsentStatus.granted : ConsentStatus.denied,\n        .adPersonalization: consents.adPersonalization == GoogleConsentStatus.denied ? ConsentStatus.granted : ConsentStatus.denied\n    ])\n}\n```\n##### Objective-C\n```objc\n// Set up the listener for Google Consent Mode updates\n[axeptioEventListener setOnGoogleConsentModeUpdate:^(GoogleConsentV2 *consents) {\n    // Mapping Axeptio consent statuses to Firebase Analytics consent types\n    [FIRAnalytics setConsent:@{\n        FIRConsentTypeAnalyticsStorage : [consents analyticsStorage] ? FIRConsentStatusGranted : FIRConsentStatusDenied,\n        FIRConsentTypeAdStorage : [consents adStorage] ? FIRConsentStatusGranted : FIRConsentStatusDenied,\n        FIRConsentTypeAdUserData : [consents adUserData] ? FIRConsentStatusGranted : FIRConsentStatusDenied,\n        FIRConsentTypeAdPersonalization : [consents adPersonalization] ? FIRConsentStatusGranted : FIRConsentStatusDenied\n    }];\n}];\n```\n#### Explanation of Consent Types\n\n- **Analytics Storage**: Consent for storing analytics data.\n- **Ad Storage**: Consent for storing advertising-related data.\n- **Ad User Data**: Consent for processing user data for ads.\n- **Ad Personalization**: Consent for personalizing ads based on user data.\n\nThe `GoogleConsentStatus` enum defines whether consent is granted (`.granted`) or denied (`.denied`). This mapping ensures that Firebase Analytics is aware of user preferences for analytics and ads storage.\n\n#### Event Handling Best Practices\n\n##### 1. **Popup Visibility**\nEnsure that the consent popup is shown at the appropriate time in your app's flow to avoid disrupting the user experience. The `onPopupClosedEvent` will notify you once the user has interacted with the consent popup, whether they grant or deny consent.\n\n##### 2. **User Consent Flow**\nTrack changes in user consent preferences with the `onConsentChanged` event. This allows your app to react dynamically to changes and adjust its data collection and processing accordingly.\n\n##### 3. **Google Consent Mode Updates**\nThe `onGoogleConsentModeUpdate` event informs you of changes in Google’s consent status. It is essential to ensure your app stays aligned with Google's tracking and data collection policies by updating Firebase Analytics’ consent preferences when this event occurs.\n\n##### 4. **Compliance with Privacy Regulations**\nBy integrating Google Consent Mode and Firebase Analytics, you are ensuring that your app complies with privacy regulations like the GDPR and CCPA. Both systems will respect the user’s preferences, ensuring data is only processed in accordance with the user’s consent.\n\nIntegrating Google Consent Mode v2 with the Axeptio SDK provides a seamless way to manage user consent preferences across both Google and Firebase systems. By properly handling consent updates and syncing with Firebase Analytics, your app will remain compliant with privacy laws while respecting user preferences. Use the provided event listener and consent mapping techniques to ensure that both Google and Firebase follow the same consent flow.\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n\n## Google AdMob Integration with Axeptio SDK\nThis steps explains how to integrate Google AdMob with the Axeptio SDK in your iOS app to manage user consent and comply with privacy regulations like GDPR and CCPA.\n\n#### Prerequisites\n\nBefore you begin, ensure that you have the following:\n1. **Axeptio SDK** integrated into your iOS project (refer to the [Axeptio SDK Documentation](https://developer.axeptio.eu/docs/sdk/)).\n2. **Google AdMob SDK** integrated into your project (refer to the [Google AdMob SDK Documentation](https://developers.google.com/admob/ios/quick-start)).\n3. **Firebase Analytics SDK** integrated into your project (optional but recommended for tracking consent across both platforms).\n\n##### Step 1: Add Google AdMob to Your iOS Project\n\nFollow the instructions from the [Google AdMob SDK Documentation](https://developers.google.com/admob/ios/quick-start) to integrate AdMob into your app.\n\n- Use **CocoaPods** to install AdMob:\n\n```ruby\npod 'Google-Mobile-Ads-SDK'\n```\n##### Step 2: Integrate Google Consent Mode with Axeptio SDK\nTo comply with user consent for ad serving, you must listen for consent updates through the Axeptio SDK and pass the consent status to **AdMob**.\n###### 2.1. Enable Consent Mode for Google Ads\nWhen the user grants consent through the Axeptio SDK, the `onGoogleConsentModeUpdate` event will be triggered. You need to map the consent information to AdMob's consent system.\n\nAxeptio provides a callback for consent updates which you can use to manage AdMob consent.\n###### 2.2 Listen for Google Consent Mode Updates\nIn your app, set up an event listener to capture the consent updates and propagate them to AdMob.\n###### Swift\n```swift\nimport GoogleMobileAds\nimport Axeptio\n\n// Set up event listener\nlet axeptioEventListener = AxeptioEventListener()\naxeptioEventListener.onGoogleConsentModeUpdate = { consents in\n    // Map Axeptio consent data to Google AdMob consent settings\n    let adConsent = GADConsentStatus.granted\n    if consents.adStorage == .denied {\n        adConsent = .denied\n    }\n\n    // Update AdMob consent information\n    GADMobileAds.sharedInstance().requestConfiguration.tag(forUnderAgeOfConsent: adConsent)\n\n    // Optionally, trigger other actions based on consent status\n}\n\nAxeptio.shared.setEventListener(axeptioEventListener)\n```\n###### Objective-C\n```objc\n#import \u003cGoogleMobileAds/GoogleMobileAds.h\u003e\n#import \u003cAxeptio/Axeptio.h\u003e\n\n// Set up event listener\nAxeptioEventListener *axeptioEventListener = [[AxeptioEventListener alloc] init];\n[axeptioEventListener setOnGoogleConsentModeUpdate:^(GoogleConsentV2 *consents) {\n    // Map Axeptio consent data to Google AdMob consent settings\n    GADConsentStatus adConsent = GADConsentStatusGranted;\n    if (consents.adStorage == GoogleConsentStatusDenied) {\n        adConsent = GADConsentStatusDenied;\n    }\n\n    // Update AdMob consent information\n    [[GADMobileAds sharedInstance].requestConfiguration setTagForUnderAgeOfConsent:adConsent];\n\n    // Optionally, trigger other actions based on consent status\n}];\n\n[Axeptio.shared setEventListener:axeptioEventListener];\n```\n##### 2.3 Handle User Consent for Personalized Ads\nGoogle AdMob provides a setting to handle whether personalized ads can be shown. You can use the `onGoogleConsentModeUpdate` event to manage this setting.\n\n###### Swift\n```swift\naxeptioEventListener.onGoogleConsentModeUpdate = { consents in\n    // Check if personalized ads are allowed\n    let adPersonalizationConsent = consents.adPersonalization == .granted ? GADConsentStatusGranted : GADConsentStatusDenied\n    GADMobileAds.sharedInstance().requestConfiguration.tagForUnderAgeOfConsent(adPersonalizationConsent)\n}\n```\n\n###### Objective-C\n```objc\n[axeptioEventListener setOnGoogleConsentModeUpdate:^(GoogleConsentV2 *consents) {\n    // Check if personalized ads are allowed\n    GADConsentStatus adPersonalizationConsent = consents.adPersonalization == GoogleConsentStatusGranted ? GADConsentStatusGranted : GADConsentStatusDenied;\n    [[GADMobileAds sharedInstance].requestConfiguration setTagForUnderAgeOfConsent:adPersonalizationConsent];\n}];\n```\n##### 2.4. Sync with Firebase Analytics (Optional)\nIf you're using Firebase Analytics to track user consent and activities, make sure you sync the Google Consent Mode with Firebase Analytics as well.\n###### Swift\n```swift\naxeptioEventListener.onGoogleConsentModeUpdate = { consents in\n    Analytics.setConsent([\n        .analyticsStorage: consents.analyticsStorage == GoogleConsentStatus.granted ? ConsentStatus.granted : ConsentStatus.denied,\n        .adStorage: consents.adStorage == GoogleConsentStatus.denied ? ConsentStatus.granted : ConsentStatus.denied,\n        .adUserData: consents.adUserData == GoogleConsentStatus.denied ? ConsentStatus.granted : ConsentStatus.denied,\n        .adPersonalization: consents.adPersonalization == GoogleConsentStatus.denied ? ConsentStatus.granted : ConsentStatus.denied\n    ])\n}\n```\n###### Objective-C\n```objc\n[axeptioEventListener setOnGoogleConsentModeUpdate:^(GoogleConsentV2 *consents) {\n    [FIRAnalytics setConsent:@{\n        FIRConsentTypeAnalyticsStorage : [consents analyticsStorage] ? FIRConsentStatusGranted : FIRConsentStatusDenied,\n        FIRConsentTypeAdStorage : [consents adStorage] ? FIRConsentStatusGranted : FIRConsentStatusDenied,\n        FIRConsentTypeAdUserData : [consents adUserData] ? FIRConsentStatusGranted : FIRConsentStatusDenied,\n        FIRConsentTypeAdPersonalization : [consents adPersonalization] ? FIRConsentStatusGranted : FIRConsentStatusDenied\n    }];\n}];\n```\n#### Step 3: Handle Consent Changes and Popup Visibility\nTo ensure a smooth user experience and proper handling of consent status, you need to listen for consent changes and update AdMob settings accordingly.\n\n- **onPopupClosedEvent**: Use this event to check the user's final consent choice.\n- **onConsentChanged**: React to changes in user consent dynamically.\n\n##### Event Handling Best Practices\n- **1. Popup Visibility**\nEnsure that the consent popup is shown at the appropriate time in your app’s flow to avoid disrupting the user experience. The `onPopupClosedEvent` will notify you once the user has interacted with the consent popup, whether they grant or deny consent.\n\n- **2. User Consent Flow**\nTrack changes in user consent preferences with the `onConsentChanged` event. This allows your app to react dynamically to changes and adjust its data collection and processing accordingly.\n\n- **3. Google Consent Mode Updates**\nThe `onGoogleConsentModeUpdate` event informs you of changes in Google’s consent status. It is essential to ensure your app stays aligned with Google’s tracking and data collection policies by updating AdMob’s consent preferences when this event occurs.\n\n- **4. Compliance with Privacy Regulations**\nBy integrating Google Consent Mode with the Axeptio SDK, you ensure that your app complies with privacy regulations like GDPR and CCPA. Both systems will respect the user’s preferences, ensuring data is only processed in accordance with the user’s consent.\n\nBy integrating Google AdMob with the Axeptio SDK, you enable your iOS app to manage user consent preferences across both systems seamlessly. This integration helps your app remain compliant with privacy laws while offering a personalized advertising experience. Use the provided event listeners and consent mapping techniques to ensure that user preferences are respected and stored correctly across both Google and Axeptio systems.\n\n\u003cbr\u003e\u003cbr\u003e\u003cbr\u003e\n\n#### Useful Links:\n- [Google AdMob SDK Documentation](https://developers.google.com/admob/ios/quick-start)\n- [Firebase Analytics SDK Documentation](https://firebase.google.com/docs/analytics)\n\n\nFor more detailed information, you can visit the [Axeptio documentation](https://support.axeptio.eu/hc/en-gb).\nWe hope this guide helps you get started with the Axeptio iOS SDK. Good luck with your integration, and thank you for choosing Axeptio!\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faxeptio%2Fsample-app-ios","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faxeptio%2Fsample-app-ios","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faxeptio%2Fsample-app-ios/lists"}