iOS SDK - Data Privacy

Complying with Data Privacy Laws

Implement privacy-compliant data collection by notifying Singular of user consent choices for GDPR, CCPA, and other consumer privacy regulations.

When users consent or decline to share their information with third parties, use Singular's privacy methods to communicate their choice. This ensures compliance with regulations like California Consumer Privacy Act (CCPA) and enables partners to respect user privacy preferences.

Learn More: See User Privacy and Limit Data Sharing for detailed information on how Singular processes privacy consent.


Limit Data Sharing

Control Third-Party Data Sharing

Notify Singular whether users have consented to share their personal data with third-party partners using the limitDataSharing method.

Method Signature:

+ (void)limitDataSharing:(BOOL)shouldLimitDataSharing;

Parameters:

  • NO (false): User has opted in and consented to share their data
  • YES (true): User has opted out and does not consent to share their data

Important: While optional, this method affects attribution data sharing. Some partners only share complete attribution information when explicitly notified that users have opted in.

Usage Examples

Swift Objective-C
// User has opted in to share their data
Singular.limitDataSharing(false)

// User has opted out and declined to share their data
Singular.limitDataSharing(true)

// Example: Set based on user preference
func handlePrivacyConsent(userConsented: Bool) {
    // Pass inverse: false = opted in, true = opted out
    Singular.limitDataSharing(!userConsented)
    
    print("Data sharing: \(userConsented ? "Enabled" : "Limited")")
}

How It Works:

Singular uses this setting in User Privacy Postbacks and passes it to partners who require it for regulatory compliance.


Per-Event Limit Data Sharing

Override Data Sharing on a Single Event

You can override the global limitDataSharing setting for a single event or custom revenue call by passing the ATTRIBUTE_SNG_LIMIT_DATA_SHARING attribute alongside your other event arguments. This is useful when a user updates their consent inline with an action and you want that specific event to reflect the new choice immediately, without changing the SDK-wide setting for subsequent events.

Accepted Values:

  • NO (false): User has opted in for this event only
  • YES (true): User has opted out for this event only

Important: The attribute must be a boolean ( BOOL in Objective-C, Bool in Swift). Non-boolean inputs are ignored and the request falls back to the global limitDataSharing setting. Either way, the attribute is removed from the event's arguments before the request is sent, so it never appears in your event payload.

Usage Examples

Swift Objective-C
// Example 1: Standard event, opt out only for this event
var dic: [AnyHashable: Any] = [:]
dic[ATTRIBUTE_SNG_LIMIT_DATA_SHARING] = true
dic["order_id"] = "12345"

Singular.event("checkout_completed", withArgs: dic)

// Example 2: Custom revenue, opt in only for this event
var attributes: [AnyHashable: Any] = [:]
attributes[ATTRIBUTE_SNG_LIMIT_DATA_SHARING] = false
attributes["sku"] = "premium_monthly"

Singular.customRevenue("premium_purchase",
                      currency: "USD",
                      amount: 9.99,
                      withAttributes: attributes)

How It Works:

When a valid boolean is supplied, the SDK removes the attribute from the event's arguments and writes it to the request's data_sharing_options.limit_data_sharing field — overriding the global limitDataSharing setting for that single request only. The global setting and the result of getLimitDataSharing are not modified, so any subsequent events that do not supply the attribute continue to use the global choice.


GDPR Compliance Methods

Manage user tracking consent and control SDK functionality to comply with GDPR (General Data Protection Regulation) and other privacy regulations.

Tracking Consent Management

trackingOptIn

Record explicit user consent for tracking by sending a GDPR opt-in event to Singular servers.

Info.plist prerequisite: If your app uses Apple's App Tracking Transparency (iOS 14.5+) — which is required to access the IDFA on consenting users — declare NSUserTrackingUsageDescription in your Info.plist with a clear user-facing explanation before showing the ATT prompt or calling +trackingOptIn . Apps that prompt for tracking without this key are rejected at App Review.

Method Signature:

+ (void)trackingOptIn;

When to Use:

  • GDPR Compliance: Call when users explicitly consent to tracking in GDPR-regulated regions
  • Consent Recording: Marks users as having provided GDPR consent in Singular's systems
  • Default Behavior: Without this call, SDK continues tracking but doesn't specifically record consent
Swift Objective-C
// User accepted tracking consent
Singular.trackingOptIn()

// Example: Call after consent dialog
func onUserAcceptedTracking() {
    Singular.trackingOptIn()
    print("User opted in to tracking")
}

Tracking Control Methods

stopAllTracking

Completely disable all SDK tracking activities for the current user on this device.

Method Signature:

+ (void)stopAllTracking;

Critical Warning: This method permanently disables the SDK until resumeAllTracking is called. The disabled state persists across app restarts and can only be reversed programmatically.

Behavior:

  • Immediate Effect: Stops all tracking, event reporting, and data collection instantly
  • Persistent State: Remains disabled even after app closes and reopens
  • No Automatic Reset: Must explicitly call resumeAllTracking to re-enable
Swift Objective-C
// User declined all tracking
Singular.stopAllTracking()

// Example: Handle user opt-out
func onUserDeclinedTracking() {
    Singular.stopAllTracking()
    print("All tracking stopped")
    
    // Optionally store preference
    saveUserTrackingPreference(false)
}

resumeAllTracking

Re-enable tracking after it was stopped with stopAllTracking .

Method Signature:

+ (void)resumeAllTracking;

Use Cases:

  • Consent Change: User changes privacy preferences and opts back into tracking
  • Privacy Settings: User updates consent through app settings menu
  • Regional Compliance: Re-enable tracking when user moves to non-regulated regions
Swift Objective-C
// User opted back in to tracking
Singular.resumeAllTracking()

// Example: Handle consent update
func onUserResumedTracking() {
    Singular.resumeAllTracking()
    print("Tracking resumed")
    
    // Optionally update stored preference
    saveUserTrackingPreference(true)
}

isAllTrackingStopped

Check whether tracking has been disabled for the current user.

Method Signature:

+ (BOOL)isAllTrackingStopped;

Returns:

  • YES (true): Tracking is currently stopped via stopAllTracking
  • NO (false): Tracking is active (either never stopped or resumed)

Returns NO if the SDK has not been initialized, regardless of any previous tracking state. Always confirm +start: has completed before relying on this value, and treat NO as "not stopped or not yet initialized" rather than "actively tracking."

Swift Objective-C
// Check current tracking status
let isTrackingStopped = Singular.isAllTrackingStopped()

// Example: Display privacy status in settings
func getPrivacyStatusText() -> String {
    return Singular.isAllTrackingStopped() ? "Tracking: Disabled" : "Tracking: Enabled"
}

// Example: Sync UI with tracking state
func updatePrivacyToggle() {
    let isStopped = Singular.isAllTrackingStopped()
    privacyToggle.isOn = !isStopped
    print("Current tracking state: \(isStopped ? "Stopped" : "Active")")
}

Children's Privacy Protection

trackingUnder13

Notify Singular that the user is under 13 years old to comply with COPPA (Children's Online Privacy Protection Act) and other child privacy regulations.

Method Signature:

+ (void)trackingUnder13;

Compliance Requirements:

  • COPPA Compliance: Required for apps that collect data from children under 13 in the United States
  • Age-Gated Content: Use when users identify themselves as under 13 during registration or age verification
  • Restricted Tracking: Limits data collection to comply with children's privacy protection laws
Swift Objective-C
// User identified as under 13
Singular.trackingUnder13()

// Example: Call after age verification
func onAgeVerified(userAge: Int) {
    if userAge < 13 {
        Singular.trackingUnder13()
        print("COPPA mode enabled for user under 13")
    }
}

Important: Call this method as early as possible after determining the user is under 13, ideally during app initialization or immediately after age verification. This ensures all subsequent tracking respects children's privacy regulations.


limitAdvertisingIdentifiers

Restrict the collection and use of advertising identifiers (IDFA on iOS) during SDK initialization for mixed audience apps.

Configuration Property:

@property (assign) BOOL limitAdvertisingIdentifiers;

Use Cases:

  • Mixed Audience Apps: Apps that serve both adults and children where age is determined before app launch
  • Known COPPA Users: When you know at initialization time that the user is under 13
  • Privacy-First Approach: Apply advertising identifier limitations from the first SDK session

Configuration Method

Set advertising identifier limitations during SDK initialization for apps that know privacy requirements upfront.

Swift Objective-C
// Limit advertising identifiers at initialization
let config = SingularConfig(apiKey: "SDK_KEY", andSecret: "SDK_SECRET")
config?.limitAdvertisingIdentifiers = true

Singular.start(config)

Kids SDK build: limitAdvertisingIdentifiers is compiled out of the Singular Kids SDK build (guarded by #ifndef SINGULAR_KIDS ). If you are integrating Singular-Kids-SDK , this property is unavailable — the Kids SDK enforces stricter identifier handling automatically. Use trackingUnder13 for runtime COPPA flagging.

Runtime Method

Toggle advertising identifier collection at any point after +start: . Useful for mixed-audience apps where the age gate, consent prompt, or content selection happens after the SDK has already started.

+ (void)setLimitAdvertisingIdentifiers:(BOOL)enabled;
Swift Objective-C
// Apply identifier limit after the user enters kids mode
func onKidsModeSwitched(isKidsMode: Bool) {
    Singular.setLimitAdvertisingIdentifiers(isKidsMode)
}

The runtime method also requires a BOOL argument — calling +setLimitAdvertisingIdentifiers without arguments will not compile. Like the config-time property, this method is unavailable in the Kids SDK build.

Best Practice: For comprehensive COPPA compliance, use both limitAdvertisingIdentifiers during initialization and call trackingUnder13() when the user's age is verified. This ensures complete protection from the first session.


Implementation Best Practices

Complete Privacy Management Example

Implement comprehensive privacy controls that respect user preferences and comply with regulations.

Swift Objective-C
import Foundation

class PrivacyManager {
    
    private let userDefaults = UserDefaults.standard
    private let consentKey = "user_consent"
    private let dataSharingKey = "data_sharing"
    
    // Initialize privacy settings on app start
    func initializePrivacy() {
        let hasUserConsent = getUserConsent()
        let allowDataSharing = getDataSharingPreference()
        
        // Apply stored preferences
        if hasUserConsent {
            Singular.trackingOptIn()
            Singular.resumeAllTracking()
        } else {
            Singular.stopAllTracking()
        }
        
        // Set data sharing preference
        Singular.limitDataSharing(!allowDataSharing)
        
        print("Privacy initialized: consent=\(hasUserConsent), sharing=\(allowDataSharing)")
    }
    
    // User accepts tracking via consent dialog
    func userAcceptedTracking() {
        saveUserConsent(true)
        Singular.trackingOptIn()
        Singular.resumeAllTracking()
        print("User accepted tracking")
    }
    
    // User declines tracking
    func userDeclinedTracking() {
        saveUserConsent(false)
        Singular.stopAllTracking()
        print("User declined tracking")
    }
    
    // User updates data sharing preference
    func setDataSharingEnabled(_ enabled: Bool) {
        saveDataSharingPreference(enabled)
        // Note: limitDataSharing uses inverse logic
        Singular.limitDataSharing(!enabled)
        print("Data sharing: \(enabled ? "Enabled" : "Limited")")
    }
    
    // Get current tracking status
    func isTrackingEnabled() -> Bool {
        return !Singular.isAllTrackingStopped()
    }
    
    // Private helper methods
    private func getUserConsent() -> Bool {
        return userDefaults.bool(forKey: consentKey)
    }
    
    private func saveUserConsent(_ consent: Bool) {
        userDefaults.set(consent, forKey: consentKey)
    }
    
    private func getDataSharingPreference() -> Bool {
        return userDefaults.bool(forKey: dataSharingKey)
    }
    
    private func saveDataSharingPreference(_ enabled: Bool) {
        userDefaults.set(enabled, forKey: dataSharingKey)
    }
}

Best Practices:

  • Persistent Storage: Save user preferences in UserDefaults or secure storage
  • Early Initialization: Apply privacy settings before SDK initialization when possible
  • UI Sync: Keep settings UI synchronized with actual SDK state using isAllTrackingStopped
  • Clear Communication: Provide clear, accessible privacy controls in app settings
  • Compliance Documentation: Maintain clear records of privacy implementation for regulatory audits