Skip to main content

Privacy & Compliance Guide

Use TeadsPrivacy to pass GDPR, CCPA, and GPP consent to the SDK. If you use an IAB-compliant CMP, the SDK reads consent automatically.

Supported Privacy Standards​

GDPR (General Data Protection Regulation)​

Full support for European privacy requirements including:

  • IAB TCF v1.1 and v2.0 consent strings
  • Purpose and vendor consent management
  • Legitimate interest handling

CCPA (California Consumer Privacy Act)​

Complete CCPA compliance with:

  • IAB US Privacy String support
  • Opt-out mechanism implementation
  • Sale of personal information controls

GPP (Global Privacy Platform)​

Support for the IAB's Global Privacy Platform:

  • Multi-jurisdiction privacy signals
  • Section-specific consent handling
  • Future-proof privacy framework

ATT (App Tracking Transparency)​

iOS 14+ privacy features:

  • IDFA consent management
  • SKAdNetwork integration
  • Privacy nutrition labels support

Basic Implementation​

Automatic Privacy Detection​

The SDK automatically detects and respects privacy signals from your CMP (Consent Management Platform):

Swift-only: App/Scene are SwiftUI-only constructs with no Objective-C equivalent — see the Installation Guide for the Objective-C Teads.configure pattern in a UIKit AppDelegate.

import TeadsSDK

// The SDK automatically reads consent from UserDefaults
// No additional configuration needed if using IAB-compliant CMP

@main
struct YourApp: App {
init() {
// Initialize SDK - privacy is handled automatically
Teads.configure(with: "YOUR_PARTNER_KEY")
}
}

Manual Privacy Configuration​

For apps with custom consent implementations:

import TeadsSDK

class PrivacyManager {

func configurePrivacy() {
let privacy = TeadsPrivacy.shared

// GDPR consent
privacy.setGDPRApplies(true)
privacy.setGDPRConsentString("YOUR_CONSENT_STRING")

// CCPA consent
privacy.setUSPrivacyString("1YNN")

// GPP consent
privacy.setGPPString("DBABLA~BAAAAAAAAAA")

// IDFA consent
privacy.setIDFAConsent(true)
}
}

Complete Privacy Implementation Example​

If you are not using a CMP, set consent yourself:

import TeadsSDK
import AppTrackingTransparency
import AdSupport

class ComprehensivePrivacyManager {

static let shared = ComprehensivePrivacyManager()
private let privacy = TeadsPrivacy.shared

// MARK: - Initialization

func initializePrivacy() {
// Check for automatic consent
if hasAutomaticConsent() {
print("Using automatic consent from CMP")
} else {
// Configure manual consent
configureManualConsent()
}

// Request IDFA if needed
requestIDFAIfAppropriate()

// Monitor consent changes
observeConsentChanges()
}

// MARK: - Automatic Consent Detection

private func hasAutomaticConsent() -> Bool {
let defaults = UserDefaults.standard

// Check for IAB consent strings
let hasGDPR = defaults.object(forKey: "IABTCF_TCString") != nil
let hasCCPA = defaults.object(forKey: "IABUSPrivacy_String") != nil
let hasGPP = defaults.object(forKey: "IABGPP_HDR_GppString") != nil

return hasGDPR || hasCCPA || hasGPP
}

// MARK: - Manual Configuration

private func configureManualConsent() {
// Determine user location
let userLocation = determineUserLocation()

switch userLocation {
case .eu:
configureGDPR()
case .california:
configureCCPA()
case .other:
configureDefaultPrivacy()
}
}

private func configureGDPR() {
// Check if user has given consent
if let savedConsent = loadSavedGDPRConsent() {
privacy.setGDPRApplies(true)
privacy.setGDPRConsentString(savedConsent)
} else {
// Show consent dialog
showGDPRConsentDialog()
}
}

private func configureCCPA() {
// Check opt-out status
let optedOut = UserDefaults.standard.bool(forKey: "user_opted_out_ccpa")
let usPrivacyString = optedOut ? "1YYN" : "1YNN"
privacy.setUSPrivacyString(usPrivacyString)
}

private func configureDefaultPrivacy() {
// No specific privacy requirements
privacy.setGDPRApplies(false)
}

// MARK: - IDFA Management

private func requestIDFAIfAppropriate() {
// Only request if not determined
guard ATTrackingManager.trackingAuthorizationStatus == .notDetermined else {
updateIDFAStatus()
return
}

// Wait for appropriate moment
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.requestIDFAPermission()
}
}

private func requestIDFAPermission() {
ATTrackingManager.requestTrackingAuthorization { [weak self] status in
self?.updateIDFAStatus()
}
}

private func updateIDFAStatus() {
let authorized = ATTrackingManager.trackingAuthorizationStatus == .authorized
privacy.setIDFAConsent(authorized)

if authorized {
let idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString
print("IDFA available: \(idfa)")
}
}

// MARK: - Consent Monitoring

private func observeConsentChanges() {
// Monitor UserDefaults for consent changes
NotificationCenter.default.addObserver(
self,
selector: #selector(consentDidChange),
name: UserDefaults.didChangeNotification,
object: nil
)
}

@objc private func consentDidChange() {
// Re-read consent values
initializePrivacy()
}

// MARK: - Consent UI

private func showGDPRConsentDialog() {
// Show your consent UI
ConsentViewController.present { [weak self] consentString in
self?.privacy.setGDPRApplies(true)
self?.privacy.setGDPRConsentString(consentString)
self?.saveGDPRConsent(consentString)
}
}

// MARK: - Persistence

private func saveGDPRConsent(_ consent: String) {
UserDefaults.standard.set(consent, forKey: "app_gdpr_consent")
}

private func loadSavedGDPRConsent() -> String? {
UserDefaults.standard.string(forKey: "app_gdpr_consent")
}

// MARK: - Location Detection

private enum UserLocation {
case eu, california, other
}

private func determineUserLocation() -> UserLocation {
// Implement location detection logic
// This is a simplified example
let locale = Locale.current
let regionCode = locale.regionCode ?? ""

let euCountries = ["AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE",
"FI", "FR", "DE", "GR", "HU", "IE", "IT", "LV",
"LT", "LU", "MT", "NL", "PL", "PT", "RO", "SK",
"SI", "ES", "SE"]

if euCountries.contains(regionCode) {
return .eu
} else if regionCode == "US" {
// Check if California (simplified)
return .california
} else {
return .other
}
}
}

Testing Privacy Compliance​

Debug Privacy Settings​

#if DEBUG
extension TeadsPrivacy {

func debugPrintPrivacyStatus() {
print("=== Privacy Status ===")
print("GDPR Applies: \(gdprApplies)")
print("GDPR Consent: \(gdprConsentString ?? "none")")
print("US Privacy: \(usPrivacyString ?? "none")")
print("GPP String: \(gppString ?? "none")")
print("IDFA Consent: \(idfaTrackingAuthorized)")
print("===================")
}
}

// Usage
TeadsPrivacy.shared.debugPrintPrivacyStatus()
#endif

Privacy Checklist​

Implementation Checklist​

  • Consent Management

    • Request user consent before loading the ad
    • Implement or integrate CMP
    • Handle GDPR consent
    • Handle CCPA compliance
    • Support GPP if applicable
  • iOS Specific

    • Implement ATT for iOS 14+
    • Update Info.plist privacy descriptions
    • Handle IDFA availability
  • Testing

    • Test with consent given
    • Test with consent denied
    • Test consent changes
    • Test different geographic regions

Info.plist Requirements​

Add these keys to your Info.plist:

<key>NSUserTrackingUsageDescription</key>
<string>This app uses your data to provide personalized ads that support our free content.</string>

<key>SKAdNetworkItems</key>
<array>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>teads-network-id.skadnetwork</string>
</dict>
<!-- Add other network IDs as needed -->
</array>

Best Practices​

1. Early Initialization​

Initialize privacy settings as early as possible:

Swift-only: App/Scene are SwiftUI-only constructs with no Objective-C equivalent — see the Installation Guide for the Objective-C Teads.configure pattern in a UIKit AppDelegate.

@main
struct YourApp: App {
init() {
// Initialize privacy first
ComprehensivePrivacyManager.shared.initializePrivacy()

// Then initialize SDK
Teads.configure(with: "YOUR_PARTNER_KEY")
}
}

Additional Resources​

Support​

For privacy-related questions:


Privacy is fundamental to building trust with your users. The Teads SDK helps you maintain that trust while maximizing monetization opportunities.