Privacy & consent
Gate the Grovs iOS SDK on user consent, and see what it collects.
Gating collection on consent
A disabled SDK collects nothing. To start a launch disabled, pass your stored consent to configure. Calling setSDK(enabled: false) afterwards is too late: configure starts the first round of collection.
let hasConsent = UserDefaults.standard.bool(forKey: "analyticsConsent")
Grovs.configure(
APIKey: "your-api-key",
useTestEnvironment: false,
enabled: hasConsent,
delegate: self
)Toggle it as consent changes:
func userDidChangeConsent(_ granted: Bool) {
UserDefaults.standard.set(granted, forKey: "analyticsConsent")
Grovs.setSDK(enabled: granted)
}The SDK doesn't persist the flag. Pass your stored value to configure on every launch.
A disabled configure calls its completion with false without authenticating. Treat that as "not started", not a failure.
While the SDK is disabled
- Nothing leaves the device: no authentication, device lookup, events, screen views or purchases.
- Automatic screen tracking stops.
- Backend features are refused: deep link resolution and link generation.
- Changes to
userIdentifier,userAttributes,pushTokenand screen aliases are held. - Tapped pushes deliver nothing and report no opens. Unreported push opens are dropped when you disable the SDK.
- Already-queued events and purchases stay on disk.
Re-enabling authenticates and sends everything held or queued.
What the SDK collects
| Data | When | Why |
|---|---|---|
| App version and build, bundle ID, device model, user agent, screen size, time zone, preferred language | When the SDK authenticates and looks up the device | Matching installs and opens to link clicks; analytics |
| Identifier for vendor (IDFV) and a Grovs device identifier stored in the keychain | Same | Recognizing the device across launches and reinstalls |
| User identifier, user attributes, push token | Only if you set them | Showing users in the dashboard; delivering push campaigns and messages |
| Push campaign opens: campaign ID and session | When the user taps a Grovs push and your app passes it to handleNotificationResponse | Campaign reports |
| Installs, opens, time spent, reactivations | Automatically | Attribution and analytics |
| Custom events and screen views | When you call track / trackScreenView, and through automatic screen tracking | Analytics |
| Purchases | When you call logInAppPurchase or logCustomPurchase | Revenue analytics |
| Clipboard contents | Read once, on the first launch with the SDK (or a later launch if that check couldn't complete), when your project has recent copy-to-clipboard clicks and the clipboard holds a web URL. Sent only if it's a link on a Grovs host or one of your clipboardDomains | Deterministic install attribution. See clipboard-assisted deferred deep linking |
The SDK doesn't read the advertising identifier (IDFA) and doesn't need App Tracking Transparency.
Privacy manifest
The SDK ships a PrivacyInfo.xcprivacy for both Swift Package Manager and CocoaPods. It declares:
- Collected data types: Device ID, User ID, Product Interaction and Purchase History, for app functionality and analytics. None is used for tracking.
- Required-reason APIs:
UserDefaults(reasonCA92.1) and file timestamps (reasonC617.1, for the SDK's disk cache).
Xcode merges it into your app's privacy report. To see it, archive the app and choose Generate Privacy Report in the Organizer.
App Store privacy details
Your App Store Connect privacy details must cover what the SDK collects for you. Typically:
- Identifiers → Device ID
- Identifiers → User ID, if you set
userIdentifier - Usage Data → Product Interaction
- Purchases → Purchase History, if you log purchases
Once you set userIdentifier, Apple treats this data as linked to the user's identity. Anything in userAttributes or event properties (an email or name, say) is data you collect too and needs its own declaration.
Logs
SDK logs go through os_log. In release builds, message content is private and shows as <private> in Console.app. The default level is .error. See setDebug.