The General Data Protection Regulation, better known as GDPR, took effect on May 25, 2018. It’s a set of rules designed to give EU citizens more control over their personal data. Any businesses established in the EU or with users based in Europe are required to comply with GDPR or risk facing heavy fines. The California Consumer Privacy Act (CCPA) went into effect on January 1, 2020.We have put together some resources below to help publishers understand better the steps they need to take to be GDPR compliant.

Keep in mind that it’s best to contact qualified legal professionals, if you haven’t done so already, to get more information and be well-prepared for compliance.

Major Steps:

    Step 1: Update Privacy Policy
    Step 2: Add Consent Window
    Step 3: Modify Integration Code

You can learn more about GDPR and CCPA and their differences here.

Step 1: Update Privacy Policy

1.1 Make sure your privacy policy includes information about advertising ID collection.

Don’t forget to add information about IP address and advertising ID collection, as well as the link to Appodeal’s privacy policy to your app’s privacy policy in App Store.

To speed up the process, you could use privacy policy generators —just insert advertising ID, IP address, and location (if you collect a user’ location) in the "Personally Identifiable Information you collect" field (in line with other information about your app) and the link to Appodeal’s privacy policy in "Link to the privacy policy of third party service providers used by the app".

1.2 Add a privacy policy to your mobile app.You must add your explicit privacy policies in two places: your app’s Store Listing page and within your app.

You can find detailed instructions on adding your privacy policy to your app on legal service websites. For example, Iubenda, the solution tailored to legal compliance, provides a comprehensive guide on including a privacy policy in your app.

Make sure that your privacy policy website has an SSL-certificate—this point might seem to be obvious, but it’s still essential.

Here’s are two useful resources that you can utilize while working on your app compliance:

    App privacy details on the App Store
    Recommendations on Developing a Meaningful Privacy Policy (by Attorney General California Department of Justice)

Please note that although we’re always eager to back you up with valuable information, we’re not authorized to provide any legal advice. It’s important to address your questions to lawyers who work specifically in this area.

Step 2: Add Consent Window

In order for Appodeal and our ad providers to deliver ads that are more relevant to your users, as a mobile app publisher, you need to collect explicit user consent in the regions covered by GDPR and CCPA.

Stack Consent Manager comes with a pre-made consent window that you can easily present to your users. That means you no longer need to create your own consent window.

2.1. Using Appodeal consent manager SDK

Minimal requirements: Appodeal SDK 2.7.0 or higher.

2.1.1. Choose your type of installation

CocoaPods

1.Add following line into your Podfile

pod 'StackConsentManager', '~> 1.1.0'

2.Run pod install

2.1.2. Synchronise

Consent manager SDK can be synchronized at any moment of application lifecycle. We recommend to synchronize it at application launch. Multiple synchronization calls are allowed.

Import StackConsentManager/StackConsentManager.h in AppDelegate.m

import StackConsentManager
Call synchronise consent in  -application:didFinishLaunchingWithOptions:

Required parameter is appKey - Appodeal API Key. 

Optional parameters are customParameters (string - any dictionary of custom parameters) and completion (block that invokes after synchronization)

/// Initialisation 
class YourAppDelegate: AppDelegate {
	override func application(
		_ application: UIApplication, 
		didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?
	) -> Bool {
        STKConsentManager.shared().synchronize(withAppKey: "Your app key") { [unowned self] error in
			error.map { print("Error while synchronising consent manager: \($0)") }
			guard STKConsentManager.shared().shouldShowConsentDialog == .true else {
				// Initialise SDK here
				return
			}
			// Load and present consent dialog                                   
		}
		return true
	}
}


After synchroizatio completion, you can receive information about the previous user consent and regulation zone. Before synchronization these parameters are undefined

// Check regulation
let regulation = STKConsentManager.shared().regulation
// Check consent status
let status = STKConsentManager.shared().consentStatus
// Available after first show (synchronisation is required)
let consentString = STKConsentManager.shared().iabConsentString


2.1.3. Advanced

You can force consent manager to write iAB keys in NSUserDefaults by setting up storage property before synchronization to STKConsentDialogStorageUserDefaults

SDK does not remove iAB keys from NSUserDefaults and only overrides them

// Store IAB strings in user defaults
// should be called before synchronize
STKConsentManager.shared().storage = .userDefaults


You can register yourself as a vendor before synchronization. 

ParameterTypeDescription
idIntegeriAB id. If you are not registered as iAB vendor you can use custom id
nameStringDisplay name. Will be displayed in the consent window
statusString Custom string to check consent result for the concrete vendor
purposesIdsArray of integersiAB purposes ids array
featuresIdsArray of integersiAB features ids array
legIntPurposeIdsArray of integersiAB leg int purposes ids array
// Register custom vendor (will be displayed on consent window)
// should be called before synchronize
STKConsentManager.shared().registerCustomVendor { builder in
	let _ = builder
        .appendPolicyURL(URL(string: "https://cmg.com/privacy")!)
        .appendName("My app")
        .appendBundle("com.app.bundle")
        .appendPurposesIds([1, 2, 3])
        .appendFeaturesIds([5, 6])
        .appendLegIntPurposeIds([1])
}

SDK allows to call consent window api only after synchronization 

After SDK synchronized, you can load the consent window. Loading allowed in any regulation zone and independent from previous consent.

class YourViewController: UIViewController {
	override func viewDidLoad() {
		super.viewDidLoad()
		STKConsentManager.shared().loadConsentDialog { [unowned self] error in
			error.map { print("Error while loading consent dialog: \($0)") }
			guard 
				let controller = self.window?.rootViewController, 
				STKConsentManager.shared().isConsentDialogReady 
			else {
				// Initialise SDK here
				return
			}
			STKConsentManager.shared().showConsentDialog(fromRootViewController: controller, 
				delegate: self)
		}
	}
}


2.1.4. Display consent dialog

You can check that the consent window is ready or not

// Indicates that consent window ready to present
let isReady = STKConsentManager.shared().isConsentDialogReady

After consent window Is ready you can present it from the top view controller

// Show consent dialog
STKConsentManager.shared().showConsentDialog(fromRootViewController: controller, delegate: self)


Handling presentation callbacks

/// Get consent manager presentation callbacks
class YourViewController: UIViewController, STKConsentManagerDisplayDelegate {
    
	// MARK: STKConsentManagerDisplayDelegate
	func consentManagerWillShowDialog(_ consentManager: STKConsentManager) {}
    
	func consentManager(_ consentManager: STKConsentManager, didFailToPresent error: Error) {
		// Something went wrong
		initializeAppodealSDK()
	}
    
	func consentManagerDidDismissDialog(_ consentManager: STKConsentManager) {
		// Resume app
		initializeAppodealSDK()
	}
}

2.2. Creating your own Consent Window

If you don't want to use the Stack Content Manager SDK, you can create own consent window.

Tips on implementing a consent window:

  • To keep your UX as compelling as it was before, you can stylize your consent window to match the main app interface.

  • In order to avoid annoying users, save the returned consent result between sessions so they aren’t asked every time they open your app.

  • Once an end-user changes their mind and decides to withdraw their consent, they should proceed to “Settings” to limit ad tracking. You can add a special “Withdraw my consent” button to your app instead, so users won’t have to look for a setting themselves.

  • Remember that you are only required to collect consent in countries covered by GDPR

Step 3: Modify Integration Code

You need to update their apps to collect the user consent prior to initializing our SDK

1. Starting from version 2.7.0 you can use the Stack Consent Manager SDK to process and pass the user's consent:

Read our implementation Stack Consent Manager guide here.

Publishers need to pass the Consent result object from Stack Consent Manager SDK to the +initialize method of our SDK.

let report = STKConsentManager.shared().consent!
Appodeal.initialize(withApiKey: YOUR_APPODEAL_APP_KEY, types: adTypes, consentReport: report)

2. If you don't want to use the Stack Content Manager SDK, you can use the old version to pass the user's consent:

Publishers need to pass the boolean consent flag(with 'false' meaning that the user declined to give the consent) to the +initialize method of our SDK.

Appodeal.initialize(withApiKey: YOUR_APPODEAL_APP_KEY, types: adTypes, hasConsent: consent)