Introduction
The Cookie Information Mobile Consents SDK is a library that helps you to collect and manage consents for personal data processing from your users. It is available for iOS and Android.
On iOS it's compatible with Swift and Objective-C, can be installed using Swift Package Manager, CocoaPods, or manually. On Android it’s compatible with Kotlin and Java on Android, it can be installed from the Maven central repository or manually from Github.
Key Features:
Installation Options: It's easy to integrate into your app using common package managers. Manual installation is possible but not recommended due to the need for manual updates.
Easy Initialisation: You can start using the SDK by importing it and initialising it with a few key parameters like client ID, secret, and solution ID obtainable from the Cookie Information Consent Management Platform.
Built-In User Interface: The SDKs come with pre-built screens to manage user consents. They automatically use the app's current language for translations, defaulting to English if the app's language isn't available.
Privacy Pop-Up Customisation: Developers can customise the appearance and behaviour of the privacy pop-up. This includes setting the accent colour, fonts, and handling user interactions like accepting or rejecting consents.
Custom UI Option: For more flexibility, you can create a custom UI to manage consents while still utilising the SDK's data handling capabilities.
Error Handling: The SDK includes methods to handle errors that might occur during the consent process.
Local and Server Consent Management: Developers can easily send consent data to the server or retrieve locally saved consent data.
Logging and Debugging: The SDK can log network events to help with debugging.
Device Identifier Display: Each user's consents are linked to a unique device identifier, which is visible in the privacy policy section of the app.
This SDK simplifies the process of managing user consents in iOS apps, ensuring compliance with data privacy regulations while offering a degree of customisation to fit the app’s design.
How it works
The SDK provides a simple UI that you can use to collect consents from your users. It also provides an API that you can use to manage consents programmatically. The SDK stores the consents in a local database on the user's device and also transmits them to the Cookie Information Consent Engine for archival and auditing purposes. The local database is encrypted and can only be accessed by your app.
The SDK also provides a UI that allows your users to view and manage their consents.
Requirements
Our SDKs work natively with iOS and Android operating systems, and they are compatible with the most popular cross-platform application development frameworks*.
Android
iOS
The Cookie Information Mobile Consents SDK for iOS supports iOS projects based on Swift or Objective-C.
As of SDK version 1.5.0 the following requirements need to be met:
- iOS 11.0 or later
- Swift or Objective-C
- or cross-platform or hybrid technologies see the compatibility table below* s of version 1 the iOS SDK supports iOS versio
* unless the cross-platform frameworks is specifically mentioned to be supported it may require additional code - a so called wrapper - to be used in said framework.
Setup
Obtaining the API credentials
In order to use the Cookie Information Mobile Consents SDKs you need to have the following credentials:
- Client ID
- Client Secret
- Solution ID
You can read in detail about setting up your account and obtaining the credentials here
Android SDK
Installation
MobileConsentsSDK is available through Gradle, by adding te dependency to your project.. Kotlin DSL
implementation("com.cookieinformation:mobileconsents:<latest_release>")
Groovy
implementation 'com.cookieinformation:mobileconsents:<latest_release>'
Initializing
Create an instance of the sdk, and initialize prior to accessing the sdk at any point. You can initialize with or without theming and styling (for theming and styling its required to have compose dependencies.) The SDK credentials can be fetched from the platform here: https://go.cookieinformation.com/login This SDK requires you to ensure the language used for the sdk, is fully set on the platform, and all data exists. So if you choose to use the sdk in German, please ensure all fields are set on the platform.
The recommended implementation would be having the sdk invoking (most likely) the showPrivacyPopUpIfNeeded, when needed, so just initialize prior to calling the method
The minimum required data for initializing the SDK would be the following:
ConsentsUISDK.init(
clientID = "<CLIENT_ID>",
clientSecret = "<CLIENT_SECRET>",
solutionId = "<SOLUTION ID>",
)
Here is an example of all the arguments and data that support the SKD.
ConsentsUISDK.init(
clientID = "<CLIENT_ID>",
clientSecret = "<CLIENT_SECRET>",
solutionId = "<SOLUTION ID>",
languageCode = "FR",//Can be null, in this case it will take the devices configured language.
typography = defaultTypography.copy(bodyMedium = TextStyle.Default),
customDarkColorScheme = darkColorScheme(
primary = Color.Yellow,
secondary = Color.Green,
tertiary = Color.Black
),
customLightColorScheme = lightColorScheme(
primary = Color.Red,
secondary = Color.Yellow,
tertiary = Pink40
),
)
UI language
The language set for the sdk, will be the language used for all components, and will ignore the systems language. In case no language has been set, (in the init function), the sdk will use the devices configured language. Its important to note, it is the developers responsibility to ensure that any potential languages to be used are set on CookieInformation's platform.
Using built-in mobile consents UI
SDK contains built-in screens for managing consents. Please ensure you set the correct language code you expect the consents to use, and that has been fully set on the platform.
Consents Screen
Standard flows
Presenting the privacy pop-up
To show the Privacy Pop Up screen, whatever the state is use showPrivacyPopUp
(typically used in settings to
allow for modification of the consent)
or to show the Privacy Pop Up screen in case the user has not consented to the latest version use showPrivacyPopUpIfNeeded
(typically used at startup to
present the privacy screen conditionally. See more below) method:
ConsentsUISDK.showPrivacyPopup(callingActivity).collect {
it.fold(
onSuccess = {
it.forEachIndexed { index, consentItem ->
Log.d("####", "onCreate: ${consentItem.title} ${consentItem.accepted}")
}
},
onFailure = { Log.d("####", it.message ?: "no message") }
)
}
The above function takes an optional completion block argument that should be used to react to the users consent and start or block various third-party SDKs.
Presenting the privacy pop-up conditionally
The showPrivacyPopUpIfNeeded
method is typically used to present the popup after app start (or at
a point the developer deems appropriate).
The method checks if a valid consent is already saved locally on the device and also checks if there
are any updates on the Cookie Information server. In case there is no consent saved or the consent
version is different from the one available on the server, the popup will be presented, otherwise
only the completion closure is called. Using the ignoreVersionChanges
parameter allows the
developer to turn off the version checking mechanism and ignore consent version changes coming from
the server.
ConsentsUISDK.showPrivacyPopupIfNeeded(callingActivity).collect {
it.fold(
onSuccess = {
it.forEachIndexed { index, consentItem ->
Log.d("####", "onCreate: ${consentItem.title} ${consentItem.accepted}")
}
},
onFailure = {
Log.d("####", it.message ?: "no message")
}
)
}
Tracking the changes of the accepted consents
ConsentsUISDK.getSavedItemsAsFlow().collect {
//collects emitted Result<List<ConsentItem>> objects, so can track the changes
}
Managing multiple users
This SDK supports multiple users, if you would like to identify you users, and ask each user to consents, just pass the userId into the methods, showPrivacyPopUp
etc.
The argument userId is by default null which represents an anonymous user.
Please note, user management is applicable per device, and not across multiple devices, so each user will need to interact on each device used.
Example for displaying for an anonymous user:
ConsentsUISDK.showPrivacyPopUpIfNeeded(callingActivity, null).collect { consents ->
//returns the result for an anonymous user
}
Example for displaying for a user identified as "user_email":
ConsentsUISDK.showPrivacyPopUpIfNeeded(callingActivity, "user_email").collect { consents ->
//returns the result for a user identified as user_email.
}
Handling errors
Both the showPrivacyPopUp
and showPrivacyPopUpIfNeeded
, return Flow<Result<List
ConsentsUISDK.showPrivacyPopUpIfNeeded(callingActivity, userId).collect { consents ->
if (consent.isSuccessful()) {
consents.forEach { consent ->
// handle user defined consent items such as age consent
print("Consent given for: ${consentItem.title} ${consentItem.accepted}")
}
} else { //failure.
//handle error
}
}
optional settings
Theming & Styling
The UI theme and font can be customized in the SDKs initializer, make sure you have Jetpack Compose dependencies in you project:
ConsentsUISDK.init(
clientID = "<CLIENT_ID>",
clientSecret = "<CLIENT_SECRET>",
solutionId = "<SOLUTION ID>",
languageCode = "FR",
typography = defaultTypography.copy(bodyMedium = TextStyle.Default),
customDarkColorScheme = darkColorScheme(
primary = Color.Yellow,
secondary = Color.Green,
tertiary = Color.Black
),
customLightColorScheme = lightColorScheme(
primary = Color.Red,
secondary = Color.Yellow,
tertiary = Pink40
),
)
Consent solution description and consent item texts can leverage HTML tags for basic text styling. Supported tags include:
<b>
for bolding text<i>
and<em>
for emphasizing text<br>
for line breaking<ul>
and<li>
for creating lists<a href>
for embedding links
Displaying the device identifier
All consents sent to the Cookie Information servers are identified by a unique device identifier that is generated randomly after opening the privacy popup for the first time. This ID is necessary for Cookie Information to retrieve consents saved by the end user.
During normal operation the identifier is not required, however in case the end user wants to access their saved consents, it is only possible if they provide the above mentioned identifier. When using the default user interface, the device identifier can be located at the bottom of the privacy policy page (after tapping "read more"). It can be copied to the clipboard by tapping the text.
iOS examples
Installation in Xcode
Swift Package Manager
MobileConsentsSDK is available through the Swift Package Manager (SPM) and CocoaPods. For the best experience we recommend using SPM by adding a new Package Dependency to your XCode project with the following repository URL:
https://github.com/cookie-information/ios-release
Cocoapods
Add the following line to your Podfile and run pod install
from your terminal.
pod 'MobileConsentsSDK', :git => 'https://github.com/cookie-information/ios-release.git'
Manual installation
In you're unable to use SPM or CocoaPods in your project, you can add the source code to your project either as a Git submodule or manually copy it into your Xcode Workspace. Using the manual method is discouraged as it requires you to manually update the SDK when security or feature updates are released.
Initializing
Swift
import MobileConsentsSDK
let mobileConsentsSDK = MobileConsents(clientID: "<CLIENT_ID>",
clientSecret: "<CLIENT_SECRET>",
solutionId: "<SOLUTION ID>"
)
Objective-C
@import MobileConsentsSDK;
MobileConsents *mobileConsents = [[MobileConsents alloc] initWithUiLanguageCode:@"EN"
clientID:@"<CLIENT_ID>"
clientSecret:@"<CLIENT_SECRET>"
solutionId:@"<SOLUTION ID>"
accentColor: UIColor.systemBlueColor
fontSet: FontSet.standard
enableNetworkLogger: YES];
Using built-in mobile consents UI
SDK contains built-in screens for managing consents. By default, built-in UI tries to use application's current langauge for consent translations. If application's language is not available in translations, English will be used.
Privacy Pop-Up
To show the Privacy Pop Up screen, use either showPrivacyPopUp
(typically used in settings to allow for modification of the consent) or showPrivacyPopUpIfNeeded
(typically used at startup to present the privacy screen conditionally. See more below) method:
mobileConsentsSDK.showPrivacyPopUp() { settings in
settings.forEach { consent in
switch consent.purpose {
case .statistical: break
case .functional: break
case .marketing: break
case .necessary: break
case .custom:
if consent.purposeDescription.lowercased() == "age consent" {
// handle user defined consent items such as age consent
}
if consent.consentItem.id == "<UUID of consent item comes here>" {
// handle user defined consent items such as age consent based on UUID
}
@unknown default:
break
}
print("Consent given for:\(consent.purpose): \(consent.isSelected)")
}
}
The above function takes an optional completion block argument that should be used to react to the users consent and start or block various third-party SDKs.
By default, the pop up is presented by top view controller of key window of the application. To change that, you can pass presenting view controller as an optional parameter.
Presenting the privacy pop-up conditionally
The showPrivacyPopUpIfNeeded
method is typically used to present the popup after app start (or at a point the developer deems appropriate). The method checks if a valid consent is already saved on the device and also checks if there are any updates on the Cookie Information server. In case there is no consent saved or the consent version is different from the one available on the server, the popup will be presented, otherwise only the completion closure is called. Using the ignoreVersionChanges
parameter allows the developer to turn off the version checking mechanism and ignore consent version changes coming from the server.
mobileConsentsSDK.showPrivacyPopUpIfNeeded(ignoreVersionChanges: true) { settings in
// handle results here
}
Objective-C
Just like in Swift, the same methods are used to display the privacy pop-up, only with a slight variation to reflect Objective-C naming conventions.
[self.mobileConsents showPrivacyPopUpIfNeededOnViewController:self
animated:YES
ignoreVersionChanges:NO
completion:^(NSArray<UserConsent *> * _Nonnull) {
// Handle consents here
}];
Handling errors
Both the showPrivacyPopUp
and showPrivacyPopUpIfNeeded
can be passed a errorHandler
closure that is called when an error occurs. After the errorHandler
is called, the popup is dismissed by the router, the selection made by the user is persisted locally and an attempt is made the next time showPrivacyPopUpIfNeeded
is called or if synchronizeIfNeeded
method is called manually.
mobileConsentsSDK.showPrivacyPopUpIfNeeded(ignoreVersionChanges: true) { settings in
// handle results here
} errorHandler: { err in
// handle the error here
}
Styling
The UI accent color and the fonts can be customized in the SDKs initializer:
MobileConsents( clientID: "<CLIENT_ID>",
clientSecret: "<CLIENT_SECRET>",
solutionId: "<SOLUTION ID>"
accentColor: .systemGreen,
fontSet: FontSet(largeTitle: .boldSystemFont(ofSize: 34),
body: .monospacedSystemFont(ofSize: 14, weight: .regular),
bold: .monospacedSystemFont(ofSize: 14, weight: .bold))
)
Consent solution description and consent item texts can leverage HTML tags for basic text styling. Supported tags include:
<b>
for bolding text<i>
and<em>
for emphasizing text<br>
for line breaking<ul>
and<li>
for creating lists<a href>
for embeding links
Basic inline css are also supported, e.g. <span style=\"color:red\">Text with custom color</span>
UI language
By default, Privacy Pop-up and Privacy Center use application's current langauge for consent translations. If application's language is not available in consent translations, English is used.
You can override langauge used by the screens by initializing SDK with custom langauge code. See the example app for more details.
Building your custom UI
In case the built-in popup screen is too limiting for you, you can choose to build your own custom screen, while still using the data and communication built into the SDK.
To start you need to create a new class inheriting from UIViewController
and conforming to PrivacyPopupProtocol
. This protocol requires that you implement an initializer that takes a viewModel
argument. This viewModel is passed in by the SDK and contains the data and methods necessary to display and save consents.
After setting up your UI components and constraints you should set up the viewModel callback functions:
onDataLoaded: ((PrivacyPopUpData) -> Void)?
- which allows you to receive the data and configure the UI components. It is useful to keep a reference to the viewModel, because it contains functions to modify the state of the consent (consent given, or revoked), to save the consent, reject optional, or accept selection.onError: ((ErrorAlertModel) -> Void)?
- to receive notifications about errorsonLoadingChange: ((Bool) -> Void)?
- to receive notifications about changes in the loading state (useful if you're using a spinner or similar progress indicator)
private func setupViewModel() {
viewModel.onDataLoaded = { [weak self] data in
guard let self = self else { return }
self.titleLabel.text = data.title
self.data = data
self.table.reloadData()
}
viewModel.viewDidLoad()
}
To allow for the user to interact with the consent screen you'll need buttons that accept or reject the data collection/processing categories. In order to do so you'll need to create the buttons and make them call viewModel.acceptAll
, viewModel.acceptSelected
or viewModel.rejectAll
.
Once you're ready with the view controller, you should use the showPrivacyPopUp
or showPrivacyPopUpIfNeeded
methods with the customViewType argument:
mobileConsentsSDK.showPrivacyPopUp(customViewType: CustomController.self) { settings in
settings.forEach { consent in
switch consent.purpose {
case .statistical: break
case .functional: break
case .marketing: break
case .necessary: break
case .custom:
if consent.purposeDescription.lowercased() == "age consent" {
// handle user defined consent items such as age consent based on the name
}
if consent.consentItem.id == "<UUID of consent item comes here>" {
// handle user defined consent items such as age consent based on UUID
}
}
}
}
To see a more complete implementation, please refer to the Example app and look for CustomPopup.swift
Sending Consent to server manually
If you want to send consent to the server, first you have to create Consent
object which structure looks like this:
var consent = Consent(consentSolutionId: "consentSolution.id", consentSolutionVersionId: "consentSolution.versionId")
/* if you want your consent to have a custom data you can add it as a last parametr */
let customData = ["email": "test@test.com", "device_id": "test_device_id"]
var consent = Consent(consentSolutionId: "consentSolution.id", consentSolutionVersionId: "consentSolution.versionId" customData: customData)
Then you have to add processing purposes which contains a given consents
/* given consents are included in main consent object as ProcessingPurpose objects which you can add to Consent object using `addProcessingPurpose` function */
let purpose = ProcessingPurpose(consentItemId: "consentItem.id", consentGiven: {true / false}, language: "en")
consent.addProcessingPurpose(purpose)
After setting up the Consent object you are ready to send it to the server
mobileConsentsSDK.postConsent(consent) { error in
/* if error is nil it means that post succeeded */
}
Getting locally saved consents data
let savedData:[SavedConsent] = mobileConsentsSDK.getSavedConsents()
SavedConsent object structure
struct SavedConsent {
let consentItemId: String
let consentGiven: Bool
}
Canceling last post to server request
mobileConsentsSDK.cancel()
Logging
The SDK can be configured to print the network events in the console. These events include all network requests, responses and errors. By default this option is disabled to keep the unnecessary clutter out of the console, however in case of unexpected behaviour or to verify that everything works as expected it can be switched on in the SDK initializer.
import MobileConsentsSDK
let mobileConsentsSDK = MobileConsents(clientID: "<CLIENT_ID>",
clientSecret: "<CLIENT_SECRET>",
solutionId: "<SOLUTION ID>",
enableNetworkLogger: true
)
Displaying the device identifier
All consents sent to the Cookie Information servers are identified by a unique device identifier that is generated randomly after opening the privacy popup for the first time. This ID is necessary for Cookie Information to retrieve consents saved by the end user.
During normal operation the identifier is not required, however in case the end user wants to access their saved consents, it is only possible if they provide the above mentioned identifier. When using the default user interface, the device identifier can be located at the bottom of the privacy policy page (after tapping "read more"). It can be copied to the clipboard by tapping the text and selecting the appropriate button from the action sheet.
Google Consent Mode
Introduction
Google Consent Mode is a way to set the behaviour of the Firebase Analytics SDK by specifying the consent decisions of the user. This can be achieved
by calling the setConsent
method of the Firebase SDK with one of the consent types. Cookie Information's Mobile Consent Management platform allows you to
effortlessly manage your users' consents ant update Firebase using Consent Mode to ensure compliance with regulations.
Consent Mode 2.0 supports the following consent types:
ad_user_data
ad_storage
ad_personalization
analytics_storage
Prerequisites
By default, no consent mode values are set. In order to comply with privacy regulations explicit consent is required before data collection is started. To prevent Firebase from collecting such information, you need to specify default values for the above mentioned consent types.
Android
To disable data collection and storage by default add the following XML AndroidManifest.xml
<meta-data android:name="google_analytics_default_allow_ad_user_data"
android:value="false" />
<meta-data android:name="google_analytics_default_allow_ad_storage"
android:value="false" />
<meta-data android:name="google_analytics_default_allow_ad_personalization_signals"
android:value="false" />
<meta-data android:name="google_analytics_default_allow_analytics_storage"
android:value="false" />
iOS
To disable data collection and storage by default add the following key-value pairs to the Info.plist
of your application.
<key>GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_USER_DATA</key>
<false/>
<key>GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_STORAGE</key>
<false/>
<key>GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS</key>
<false/>
<key>GOOGLE_ANALYTICS_DEFAULT_ALLOW_ANALYTICS_STORAGE</key>
<false/>
Update consent
It is cruitial to inform the Firebase SDK when the user changes their consent. To update consent values after an app has launched, call the setConsent
method.
The value set by the setConsent method overrides the default setting and persists across app executions. The value remains in that state until
setConsent
is called again, even if a user closes and reopens the app. setConsent
only updates the parameters you specify.
Android
The setConsent
method is used to update the consents in the Firebase SDK:
Firebase.analytics.setConsent {
analyticsStorage(<consent status>)
adStorage(<consent status>)
adUserData(<consent status>)
adPersonalization(<consent status>)
}
Using the Cookie Information Android SDK you can retrieve the latest user consents. The consent decisions are stored as Boolean, so they need to be mapped to ConsentStatus.GRANTED
and ConsentStatus.DENIED
to be used with Firebase.
lifecycleScope.launch {
(applicationContext as App).sdk.getSavedConsentsWithType(object : CallListener<Map<UUID, ConsentWithType>> {
override fun onSuccess(result: Map<UUID, ConsentWithType>) {
val mapped = result.values.associate { it.type to it.consented }
Firebase.analytics.setConsent {
analyticsStorage(if(mapped[ConsentItem.Type.TypeStatistical] == true) ConsentStatus.GRANTED else ConsentStatus.DENIED )
adStorage(if(mapped[ConsentItem.Type.TypeMarketing] == true) ConsentStatus.GRANTED else ConsentStatus.DENIED )
adUserData(if(mapped[ConsentItem.Type.TypeMarketing] == true) ConsentStatus.GRANTED else ConsentStatus.DENIED )
adPersonalization(if(mapped[ConsentItem.Type.TypeFunctional] == true) ConsentStatus.GRANTED else ConsentStatus.DENIED )
}
}
override fun onFailure(error: IOException) {}
})
}
See the previous chapters about more details on the SDK setup and implementation.
iOS
Similarly to Android, the consents are updated using the setConsent
method. The following snippet demonstrates an optional extention that maps
the Cookie Information consent status to the Firebase Analytics ConsentStatus
type.
extention UserConsent {
var consentStatus: ConsentStatus {
return isSelected ? ConsentStatus.GRANTED : ConsentStatus.DENIED
}
}
mobileConsentsSDK.showPrivacyPopUp() { settings in
settings.forEach { consent in
switch consent.purpose {
case .statistical:
Analytics.setConsent(.analyticsStorage: consent.consentStatus
case .functional: break
case .marketing: break
Analytics.setConsent([
.adStorage: consent.consentStatus,
.adUserData: consent.consentStatus,
.adPersonalization: consent.consentStatus,
])
case .necessary: break
@unknown default:
break
}
print("Consent given for:\(consent.purpose): \(consent.isSelected)")
}
Analytics.setConsent([
.analyticsStorage: ,
.adStorage: <consent status>,
.adUserData: <consent status>,
.adPersonalization: <consent status>,
])
}
See the previous chapters about more details on the SDK setup and implementation.
Verify your setup
You can verify that your consent settings are working as intended by viewing the log messages for your app.
Android
Follow these steps:
Enable verbose logging on your device. In the Android Studio logcat, find the log message that starts with Setting consent. For example, Ad storage is enabled, you'll see the following log message:
Setting consent, ... AD_STORAGE=granted
iOS
You can verify that your consent settings are working as intended by viewing the Xcode debug console for your app.
Follow these steps:
Enable verbose logging on your device. In the Xcode debug console, look for:
ad_storage analytics_storage ad_user_data ad_personalization For example, if Ad storage are enabled, you'll see the following message:
ad_storage is granted.
References
For further information and more technical details please refer to the Google Consent Mode documentation for mobile apps.
Feedback
How to report a bug
If you find a bug in the SDK, please send us a report via GitHub Issues. Android bugs should be reported in the Android SDK repository, iOS bugs in the iOS SDK repository.
Feature requests
We appreciate your feedback and are always interested in new ideas for our SDKs. If you have a feature request, please email us at support@cookieinformation.com.
Contributing
If you want to contribute to the SDK, please create a GitHub Issue first and describe your idea. We will then discuss the idea with you and decide whether it is a good fit for the SDK. If it is, you can create a pull request with your changes.