iOS Consent Library APIs

Usage Notes:

  • Note: Minimum airgap.js version required is 8.37.2. You can upgrade your airgap version in the Admin Dashboard. Don't forget to publish the change!
  • While most of the usage remains consistent with the previous version, the new version introduces enhancements to the initialization of the API and UI instances.
  • This version also includes notable changes such as:
    • Storing Consent Preferences in the Preference Store.
    • Enables Transcend-stored telemetry data.
    • Minor bug fixes and performance improvements.
  • The remaining documentation is organized into three sections:
    • Introduction of Transcend Core Config to streamline the configuration process.
    • Initialization of the API Instance.
    • Initialization of the UI Instance.
  • Introduced TranscendCoreConfig to streamline the configuration process for both API and UI instances.

    TranscendCoreConfig Properties

    • transcendConsentUrl: The URL of the airgap.js bundle used for consent management. This is a required field.
    • destroyOnClose: A boolean indicating whether the UI view should be destroyed when closed. By default, it is set to true.
    • defaultAttributes: A dictionary containing default attributes to initialize the airgap bundle. This may be useful for overriding parameters such as data-partition. The mobile SDK includes the following defaults:
      • data-cfasync: false
      • data-report-only: on -> note airgap.js is not performing regulation in the mobile app, hence why the script is loaded in report only mode
      • data-partition: <airgap-bundle-id>
      • data-sync: on
      • data-local-sync: off
      • data-backend-sync: on
      • data-telemetry: off
    • token: The user token used to sync consent data in the Preference Store. Refer to the Preference Store for token creation.
    • syncDomains: An array of domain URLs that may be rendered as webViews and require consent synchronization.
    • autoShowUI: A boolean indicating whether to automatically display the UI. By default, it is set to false. When set to true, the UI will be displayed automatically if the user has not provided consent.
    • mobileAppId: The Mobile Application ID is utilized to enable Transcend-stored telemetry data. Native Applications can be created within the Admin Dashboard where the Name field should be used as the mobileAppId. Telemetry Information can be accessed on the Admin Dashboard.
    public init(
        transcendConsentUrl: String,
        destroyOnClose: Bool = true,
        defaultAttributes: [String: String] = [:],
        token: String = "",
        syncDomains: [String] = [],
        autoShowUI: Bool = false,
        mobileAppId: String = ""
    )
    
  • To create an API instance, use TranscendWebViewUI(transcendCoreConfig: TranscendCoreConfig(), didFinishNavigation: didFinishNavigation). For UI instance initialization, refer to Initialization of UI Instance.

    import SwiftUI
    import Transcend
    
    // Usage
    // completionHandler
    let didFinishNavigation: ((Result<Void, Error>) -> Void) = { result in
      switch result {
        case .success():
          // Your logic goes here
        case .failure(let error):
          print("Error during web view navigation: \(error.localizedDescription)")
      }
    }
    // Create TranscendCoreConfig
    let simpleCoreConfig: TranscendCoreConfig = TranscendCoreConfig(
      transcendConsentUrl: "https://transcend-cdn.com/cm/{Bundle_Id}/airgap.js")
    
    TranscendWebViewUI(transcendCoreConfig: simpleCoreConfig, didFinishNavigation: didFinishNavigation)
    
  • To create a UI view (that is actually visible on UI) use TranscendWebViewUI(transcendCoreConfig: TranscendCoreConfig(), onCloseListener: onCloseListener)

  • The onCloseListener now yields Result<TrackingConsentDetails, Error> instead of Result<Void, Error>. This adjustment enables developers to promptly access consent data immediately after the UI closure, eliminating the need to fetch it using getConsent().

  • It should be invoked subsequent to the initialization of the API instance and when didFinishNavigation returns .success.

    import SwiftUI
    import Transcend
    
    // Usage
    // completionHandler
    let onCloseListener: ((Result<TrackingConsentDetails, Error>) -> Void) = { result in
      self.showingPopover = false
      switch result {
        case .success(let consentData):
          // Your logic goes here
          print("Onclose:: \(consentData.purposes)")
        case .failure(let error):
          print("Error during web view navigation: \(error.localizedDescription)")
      }
    }
    // Create TranscendCoreConfig
    let transcendCoreConfigWithSyncDomain: TranscendCoreConfig = TranscendCoreConfig(
      transcendConsentUrl: "https://transcend-cdn.com/cm/{Bundle_Id}/airgap.js",
      syncDomains: ["https://another-domain.example.com"])
    
    // Can be used in popover, sheet or any other view
    TranscendWebViewUI(transcendCoreConfig: transcendCoreConfigWithSyncDomain, onCloseListener: onCloseListener)
    

Usage Notes:

  • Note: Minimum airgap.js version required is 8.32.0. You can upgrade your airgap version in the Admin Dashboard. Don't forget to publish the change!
  • To leverage APIs like getRegimes() and getConsent(), it's crucial to call TranscendWebViewUI(..., isInit: true, didFinishNavigation: didFinishNavigation) or TranscendWebViewUI(..., isInit: true,syncDomains: [String], didFinishNavigation: didFinishNavigation) either within the struct implementing the App protocol or in the view appearing on application load.
  • Note: Using isInit: true creates a singleton instance of TranscendWebView running in the background throughout the application context. TransncendWebViewUI is available for iOS versions ≥ 13.
  • Note: To create a UI view (that is actually visible on UI) use TranscendWebViewUI(isInit: false, onCloseListener: onCloseListener)
  • If your app supports iOS versions earlier than 13, we recommend using TranscendWebView similarly to a WKWebView instance.
  • The didFinishNavigation: ((Result<Void, Error>) -> Void)?) parameter is essentially a callback function you provide to determine if the background-running webView has loaded and is ready to handle API calls such as getRegimes() and getConsent().
  • The onCloseListener:((Result<Void, Error>) -> Void)?) parameter is essentially a callback function that will be called when a UI view is closed. Specifically useful if the transcendWebViewUI is added to a parentView such as a popUp.
  • The remaining documentation is organized into three sections:
    • Initialization of the API Instance.
    • Definitions and usage of the API.
    • Initialization of the UI Instance.
  • To start a webView in background that is only responsible for API’s calls such as getRegimes() and getConsent(). To show a UI view, refer Initialization of UI Instance.

    import UIKit
    import WebKit
    
    // Usage
    // completionHandler
    let didFinishNavigation: ((Result<Void, Error>) -> Void) = { result in
      switch result {
        case .success():
          // Your logic goes here
        case .failure(let error):
          print("Error during web view navigation: \(error.localizedDescription)")
      }
    }
    
    TranscendWebViewUI(
      transcendConsentUrl: "https://transcend-cdn.com/cm/{Bundle_id}airgap.js",
      isInit: true, didFinishNavigation: didFinishNavigation)
    
  • This functionality primarily serves customers employing webView instances seeking to synchronize consent states between their Native application and webViews. The function signature incorporates a parameter named syncDomains, enabling the inclusion of a list of domains for consent state synchronization. It's important to highlight that this function automatically generates webViews in the background to synchronize consent states, offering enhanced convenience for customers managing webViews across multiple domains.

    import UIKit
    import WebKit
    
    // Usage
    // completionHandler
    let didFinishNavigation: ((Result<Void, Error>) -> Void) = { result in
      switch result {
        case .success():
          // Your logic goes here
        case .failure(let error):
          print("Error during web view navigation: \(error.localizedDescription)")
      }
    }
    
    TranscendWebViewUI(
      transcendConsentUrl: "https://transcend-cdn.com/cm/{Bundle_id}airgap.js",
      isInit: true, ["https://another-domain.example.com"], didFinishNavigation: didFinishNavigation)
    
  • If you opt to manually inject consent data into your webView for improved performance prior to loading, you can refer to this code snippet and utilize the initialization described above here.

    let configuration = WKWebViewConfiguration()
    let contentController = WKUserContentController()
    // Get Data from UserDefaults
    let consent = UserDefaults.standard.string(forKey: TranscendConstants.TRANSCEND_CONSENT_DATA)
    let tcString = UserDefaults.standard.string(forKey: IABConstants.IAB_TCF_TC_STRING)
    
    // Generate Script
    let script = ""
    if let consent = consent {
      script += "localStorage.setItem('tcmConsent', '\(consent)');"
    }
    if let tcString = tcString {
      script += "localStorage.setItem('tcmTcf', '\(tcString)');"
    }
    
    // Inject UserScript
    let userScript = WKUserScript(
      source: script, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: false)
    contentController.addUserScript(userScript)
    configuration.userContentController = contentController
    
    // Create WebView and load
    let webview = WKWebView(configuration: configuration)
    webview.load(URLRequest(url: URL(string: "your URL")))
    

The following APIs can be used after the didFinishNavigation callback returns .success.

  • Returns a set of all privacy legal regimes that are detected as applicable to the user. The set will be empty if no regimes are detected.

    getRegimes definition

    /// Fetches the available regimes and invokes the completion handler with the result.
    ///
    /// - Parameter completionHandler: A closure to be called once the regimes are fetched.
    ///   The closure takes two parameters: a set of strings representing the available regimes,
    ///   and an optional error if the operation fails.
    public func getRegimes(completionHandler: @escaping (Set<String>?, Error?) -> Void)
    

    getRegimes usage

    // Usage
    // Note: can be used only after didFinishNavigation returns .success
    TranscendWebView.transcendAPI.webAppInterface.getRegimes(completionHandler: { result, error in
      if let error = error {
        // Your logic goes here
        print("UI Error : \(error)")
      } else {
        // Your logic goes here
        if result?.contains("us") == true {
          self.showTranscendWebView = true
        }
      }
    })
    
  • getConsent() returns TrackingConsentDetails. This descriptor has a purposes field which returns an object keyed by all consentable tracking purpose types. The descriptor also has an ISO 8601 timestamp accessible via the timestamp field.

    getConsent definition

    /// Retrieves the user's tracking consent details and invokes the completion handler with the result.
    ///
    /// - Parameter completionHandler: A closure to be called once the tracking consent details are retrieved.
    ///   The closure takes two parameters: a `TrackingConsentDetails` object representing the user's consent details,
    ///   and an optional error if the operation fails.
    public func getConsent(completionHandler: @escaping (TrackingConsentDetails?, Error?) -> Void)
    

    getConsent usage

    // Usage
    // Note: can be used only after didFinishNavigation returns .success
    TranscendWebView.transcendAPI.webAppInterface.getConsent(completionHandler: { result, error in
      if let error = error {
        // Your logic goes here
        print("Error : \(error)")
      } else {
        // Your logic goes here
        let response: TrackingConsentDetails = (result) ?? TrackingConsentDetails()
        for key in response.purposes.keys {
          if let purpose = response.purposes[key] {
            switch purpose {
            case .bool(let value):
              print("\(key) Bool Value: \(value)")
            case .string(let value):
              print("\(key) String Value: \(value)")
            default:
              print("No Value found for \(key)")
            }
          }
        }
      }
    })
    
  • Determines whether a given SDK is allowed to load based on serviceId. The serviceId is the unique slug associated with each SDK. The completion handler will return the consent status for the given SDK or an error if the operation fails.

    getSDKConsentStatus definition

    /// Determines whether a given SDK is allowed to load based on:
    /// - The SDK's associated tracking
    /// - The user's own consent
    /// - The user's matching regional experience
    public func getSDKConsentStatus(
      serviceId: String, completionHandler: @escaping (ConsentStatus?, Error?) -> Void)
    
    /// The possible consent statuses for a given SDK
    public enum ConsentStatus {
      case TCF_ALLOW
      case BLOCK
      case ALLOW
      case NO_SDK_FOUND
      case INTERNAL_ERROR
    }
    

    getSDKConsentStatus usage

    // Usage
    // Note: can be used only after didFinishNavigation returns .success
    TranscendWebView.transcendAPI.webAppInterface.getSDKConsentStatus(
      serviceId: "datadog-ios",
      completionHandler: { result, error in
        if let error = error {
          print("UI Error : \(error)")
        } else {
          if let status = result {
            print(status)
          }
        }
      })
    
  • To create a UI view (that is actually visible on UI) use TranscendWebViewUI(isInit: false, onCloseListener: onCloseListener). To be called after API instance is initialized and didFinishNavigation returns .success.

    import SwiftUI
    import Transcend
    
    // Usage
    // completionHandler
    let onCloseListener: ((Result<Void, Error>) -> Void) = { result in
      switch result {
        case .success:
          // Your logic goes here
          // e.g. dismiss a popover
          self.showingPopover = false
        case .failure(let error):
          // Your logic goes here
          print("Error during UI onClose: \(error.localizedDescription)")
      }
    }
    // Can be used in popover, sheet or any other view
    TranscendWebViewUI(transcendConsentUrl: "https://transcend-cdn.com/cm/{Bundle_id}airgap.js",
    isInit: false, onCloseListener: onCloseListener)