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
- 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.