Privacy & Compliance Guide
The Teads SDK is designed with privacy at its core, providing comprehensive tools for managing user consent and ensuring compliance with global privacy regulations. This guide covers everything you need to know about privacy management, consent handling, and regulatory compliance.
Overview
The SDK includes the TeadsPrivacy component that:
- ✅ Automatically detects and respects IAB consent strings
- ✅ Supports GDPR, CCPA, and GPP frameworks
- ✅ Manages IDFA (Identifier for Advertisers) consent
- ✅ Provides manual consent configuration options
- ✅ Ensures end-to-end privacy compliance
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):
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.setSubjectToIDFAConsent(true)
    }
}
Complete Privacy Implementation Example
Here's a comprehensive example combining all privacy frameworks for apps with custom consent implementations, meaning for when you are not using a CMP to handle it on your behalf:
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.setSubjectToIDFAConsent(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: \(subjectToGDPR)")
        print("GDPR Consent: \(gdprConsentString ?? "none")")
        print("US Privacy: \(usPrivacyString ?? "none")")
        print("GPP String: \(gppString ?? "none")")
        print("IDFA Consent: \(subjectToIDFAConsent)")
        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:
@main
struct YourApp: App {
    init() {
        // Initialize privacy first
        ComprehensivePrivacyManager.shared.initializePrivacy()
        // Then initialize SDK
        Teads.configure(with: "YOUR_PARTNER_KEY")
    }
}
Additional Resources
- IAB TCF v2.0 Specification
- IAB CCPA Compliance Framework
- IAB Global Privacy Platform
- Apple App Tracking Transparency
Support
For privacy-related questions:
- Email: privacy@teads.com
- Legal: legal@teads.com
Privacy is fundamental to building trust with your users. The Teads SDK helps you maintain that trust while maximizing monetization opportunities.