Skip to main content

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

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.