Skip to content
The mobile SDKs are available on request. Email support@grona.ai to get access.

App Store privacy and privacy manifest

This page helps your app team answer Apple’s privacy questions for the Grona SDK. Apple holds your app responsible for the data that the SDKs inside it collect, so Grona’s data belongs in your App Store privacy details. The SDK ships its own privacy manifest. This page explains what it declares and why, and how to carry it into the answers you give in App Store Connect.

Apple counts data as collected when it is transmitted off the device. The Grona SDK sends events only when both of these hold:

  • You set an eventsURL in your options. Without one, the SDK sends no events and keeps no queue.
  • The shopper’s consent is .granted. Under .unknown events stay in memory and none are sent. Under .denied nothing is collected. See Consent.

If you turn on sendPreConsentEvents, events buffered under .unknown are sent once consent is granted, so your consent text must cover them.

Three other requests leave the device:

  • The configuration fetch carries no identifiers in any consent state.
  • Preview pairing sends the install id when a tester opens a preview link. It is refused under .denied.
  • Image downloads fetch component images from the image hosts in your signed configuration. They carry no Grona identifiers, but the image host sees the device’s IP address.

Asking for consent does not remove the need to declare. Apple asks you to declare data that you collect on an ongoing basis after the shopper agrees.

The Grona target includes PrivacyInfo.xcprivacy as a processed resource. Xcode reads it when you generate your app’s privacy report. It declares:

Key Value
NSPrivacyTracking false
NSPrivacyTrackingDomains Not present. The SDK contacts no tracking domains.
NSPrivacyCollectedDataTypes Six data types, all linked to the shopper and none used for tracking. See Data types.
NSPrivacyAccessedAPITypes Two required-reason APIs: File timestamp, reason C617.1, and System boot time, reason 35F9.1. See Required-reason APIs.

The file that ships in the 0.1.0 package:

PrivacyInfo.xcprivacy
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeDeviceID</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
<string>NSPrivacyCollectedDataTypePurposeProductPersonalization</string>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
<string>NSPrivacyCollectedDataTypePurposeDeveloperAdvertising</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeUserID</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
<string>NSPrivacyCollectedDataTypePurposeProductPersonalization</string>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
<string>NSPrivacyCollectedDataTypePurposeDeveloperAdvertising</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeProductInteraction</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
<string>NSPrivacyCollectedDataTypePurposeProductPersonalization</string>
<string>NSPrivacyCollectedDataTypePurposeDeveloperAdvertising</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeAdvertisingData</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
<string>NSPrivacyCollectedDataTypePurposeProductPersonalization</string>
<string>NSPrivacyCollectedDataTypePurposeDeveloperAdvertising</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypePurchaseHistory</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
<string>NSPrivacyCollectedDataTypePurposeProductPersonalization</string>
<string>NSPrivacyCollectedDataTypePurposeDeveloperAdvertising</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeOtherDiagnosticData</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
</array>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
</array>
</dict>
</plist>

With consent granted and an events endpoint set, the SDK sends the following. Each row names the App Store data type it matches.

App Store category and data type What Grona sends Purposes declared
Identifiers: Device ID The SDK’s install id, a random UUID the SDK generates, and a random session id Analytics, Product Personalization, App Functionality, Developer’s Advertising or Marketing
Identifiers: User ID The customer id you pass to Grona.identify, only while a shopper is identified Analytics, Product Personalization, App Functionality, Developer’s Advertising or Marketing
Usage Data: Product Interaction Campaign events (eligible, visible, served, exposure, taps on Grona content, dismissals), product views, cart adds and removals Analytics, Product Personalization, Developer’s Advertising or Marketing
Usage Data: Advertising Data Which Grona content was served and seen Analytics, Product Personalization, Developer’s Advertising or Marketing
Purchases: Purchase History The purchase event (order id, order total, currency, the Grona treatments, and the products in the order that a Grona campaign showed or added) and the checkout total Analytics, Product Personalization, Developer’s Advertising or Marketing
Diagnostics: Other Diagnostic Data The SDK version, your app’s version, the platform and the iOS version, on every batch of events Analytics, App Functionality

Product ids and prices travel only for products a Grona campaign showed or added in the session. Other products are counted without them, and the full basket never leaves the device. Exception: on keyed placements such as cart_line, campaign events carry the line’s product id as their key, in every arm. So while a cart_line campaign is live, the product ids of the cart lines bound to it leave the device.

  • Why everything is linked. Every event carries the install id, and the customer id while a shopper is identified. Data sent with an identifier is linked to the shopper.
  • Why App Functionality. Grona assigns shoppers to variants from the install id and the customer id, and checks SDK versions against the configuration.
  • Why Advertising Data and Developer’s Advertising or Marketing. Grona’s banners and offers promote your products to targeted shoppers, and Grona measures who saw them. That is the plain reading of both of Apple’s definitions, so the manifest declares them. If your team concludes they do not apply to how you use Grona, your privacy details are your decision. Xcode’s privacy report still lists them, because the report reads the SDK’s manifest. If you drop them, drop Advertising or marketing from your Play answers too, so both stores tell the same story.

The SDK does not send:

  • location, contacts, photos, files or any other device content;
  • names, email addresses or phone numbers;
  • search text or browsing history;
  • the shopper’s profile from Grona.setProfile, which stays on the device;
  • the full basket from Grona.setBasket, which stays on the device. Only the product ids of cart lines bound to a keyed placement such as cart_line leave it, as campaign event keys.

The SDK does not read or send location. Grant fetching runs through your own GronaGrantSource and your own backend. Declare that data flow as part of your app, as you would any call to your own servers.

Every request reaches Grona’s servers from the device’s IP address. Grona truncates IP addresses when it receives them and does not derive location from them, so the SDK adds no location entry to your answers.

Apple requires every SDK to declare the required-reason APIs its own code calls. The Grona SDK declares two categories.

Category Reason Why the SDK needs it
File timestamp (NSPrivacyAccessedAPICategoryFileTimestamp) C617.1 The SDK keeps its event queue and state in its own files inside your app’s container, and may read the size and dates of those files to bound its storage. It reads no other file’s metadata, and nothing read this way leaves the device.
System boot time (NSPrivacyAccessedAPICategorySystemBootTime) 35F9.1 The SDK reads the system uptime clock to measure time between events inside your app and to run its timers: the one-second visibility dwell, the two-second visit grace period, and back-off. The uptime clock does not move when the shopper changes the device’s date and time. Neither the boot time nor anything derived from it leaves the device.

The SDK uses no other required-reason category. It stores everything in its own files, so it does not use UserDefaults. It never checks free disk space, and it never reads the list of active keyboards.

The manifest sets NSPrivacyTracking to false and lists no tracking domains. The SDK never calls App Tracking Transparency, so your app needs no NSUserTrackingUsageDescription for Grona.

Apple defines tracking as linking data from your app with data from other companies’ apps, websites or offline properties for targeted advertising or advertising measurement, or sharing data with data brokers. The SDK’s answer of no tracking holds while all of these are true:

  • The SDK reads no advertising identifier and no other device identifier, and does no fingerprinting. This is how the SDK is built.
  • Grona uses your app’s data only for your app’s analytics and personalisation, as your service provider. It does not combine your shoppers’ data with other Grona customers’ data to target or measure campaigns, and does not share it with data brokers or advertising networks or export audiences from it. Confirm this in your contract with Grona.
  • Your app does not send Grona’s ids or events to advertising platforms, data brokers or retail media networks, and does not join them with other companies’ data for advertising.

If your app sends Grona’s customer id or purchase events to an advertising platform, your app is tracking. It must then ask for permission with App Tracking Transparency, and your privacy details must mark that data as used to track the shopper, whatever the SDK’s manifest says.

  1. Generate the privacy report. Archive your app, then in Xcode’s Organizer choose Generate Privacy Report. The report combines your app’s privacy manifest with the manifests of the SDKs it links, including Grona’s.

  2. Enter the answers in App Store Connect. Open your app’s App Privacy page and add each data type from the report, with your app’s own data. Grona’s data types all go under Data Linked to You, with the purposes in the table above.

  3. Keep consent in mind. Declare the data types even if every shopper is asked for consent first.

  4. Review after each SDK update. The iOS SDK changelog notes every change to the manifest. You can update your answers in App Store Connect without a new app release.

  • On the device. Grona.reset() clears the event queue, the customer id, the profile, grants, the basket snapshot and preview pins, and issues a new install id. Call it from your account deletion or erasure flow. See Identify shoppers.
  • Already sent. To delete data Grona already holds for a customer id or install id, contact Grona support.