What the mobile SDKs send
Last updated
This page lists the data that the Whisperr mobile SDKs (Swift, React Native,
Flutter) send to https://api.whisperr.net over HTTPS. Use it to fill in the
App Store privacy answers and the
Google Play Data safety answers. You own your app’s
answers: also add the data that the rest of your app collects.
What do the SDKs send with no code from you?
Section titled “What do the SDKs send with no code from you?”| Data | What it is |
|---|---|
anonymous_id | A random ID that the SDK creates on the device. It identifies the device before identify(). reset() creates a new one. |
| Automatic events | app_installed, app_updated, app_opened (with cold_start) and app_backgrounded (with foreground_ms). trackAutomaticEvents: false (Flutter), trackAppLifecycleEvents: false (React Native) or automaticEvents: false (Swift) turns them off. |
| Launch source and visit counts | From React Native 0.7.0, Flutter 0.8.0 and Swift 0.7.0. app_opened adds launch_source and, for a link, the redacted path (link_route, ids replaced by :id), the host of an http(s) link (link_host) and the link’s utm_source, utm_medium and utm_campaign. It never sends the full URL or the query. A push or email open adds the Whisperr message ID. app_backgrounded adds the session ID and counts of screens, events and errors in the visit. |
Errors (app_error) | From the same versions. For an uncaught error, and for each trackError() call: the error type (error_name, such as TypeError), a fingerprint (a hash of the type and the top three function names of the stack), the kind, whether it was fatal, and the last screen name. Never the error message, the stack, file paths or URLs. captureErrors: false turns off the automatic capture; trackError() still sends. |
Crashes (app_crashed) | From the same versions. On the next launch after the app ended while in the foreground: the crash kind, how it was detected, the app version, session ID and last screen name of that run. Debug builds never send it. It follows the automatic-events switch above. |
| App and device context | Automatic events carry app_version, app_build, platform, os_name, os_version, sdk_name, sdk_version, locale, and timezone or timezone_offset_minutes. Every event carries app_version, app_build, platform, sdk_name and sdk_version in its context. The React Native SDK also puts the OS name (os) and the SDK name and version (library) there. |
| Event metadata | The time of each event (occurred_at) and a random $message_id per event, used to remove duplicates. A random session_id that changes after 30 minutes without events (React Native; Flutter from 0.8.0 and Swift from 0.7.0, where it also changes on each cold start). |
| Notification permission (Swift only) | The Swift SDK reads the permission each time the app comes to the foreground and sends push_permission_changed when it changed. From 0.7.0 it also sends the notification settings the device exposes (alerts_enabled, lock_screen, scheduled_summary, time_sensitive). automaticPushPermission: false or automaticEvents: false turns this off. |
| Restore identify | At app start, for a user your app identified before: the user ID, the anonymous_id, the locale, the time zone and the app language. |
What do the SDKs send only when your code passes it?
Section titled “What do the SDKs send only when your code passes it?”| Data | Call |
|---|---|
| User ID | identify(userId): your app’s own ID for the user. |
| Events and screens | track() and screen(), with the properties you pass. |
| Traits, such as a first name | identify(userId, traits: …). identify() adds locale and the time zone (timezone, or timezone_offset_minutes in Flutter). |
| Email address | An email channel or the email parameter in identify(). |
| Phone number | The phone parameter or a phone channel in identify(). Whisperr does not send SMS today, so you don’t need to send a phone number. |
| Push token | setPushToken(). With the token, the SDK sends its kind (fcm, apns, expo or onesignal_sub), the platform, the app’s bundle ID or package name (client_app_id), the Firebase, EAS or OneSignal project ID (provider_project), and for APNs tokens the environment (push_env), when it knows them. |
| Notification permission | React Native and Flutter: setPushPermission(), or requestPushAuthorization() in React Native. It sends push_permission_changed with the status when it changed. |
| Push opens | trackPushOpened() (Swift: handleNotificationResponse()) sends push_opened with the Whisperr message ID, the deep link, action_id and cold_start. |
| Push receipts | trackPushReceived() (Swift: handleWillPresent(); Flutter: whisperr_firebase_messaging calls it) sends push_received for a Whisperr push. |
| App language | setAppLanguage(): the language the user picked in your app, as the trait app_language. |
Whisperr drops event property keys that are named like personal data, such as
email, phone or first_name. It also drops trait values that are email
addresses or phone numbers. Send those as channels.
What does Whisperr add that the SDK does not send?
Section titled “What does Whisperr add that the SDK does not send?”| Data | What it is |
|---|---|
| Country | For each event sent with the publishable key, Whisperr derives the country (an ISO 3166-1 alpha-2 code such as DE) from the request’s IP address at its edge and stores it as context.country. A country the app already put in the event context is kept. |
Declare this as approximate location if your answers count a country as location. See the App Store and Google Play pages.
What do the SDKs not collect?
Section titled “What do the SDKs not collect?”The SDKs do not read the advertising ID (IDFA, Android advertising ID), the
identifier for vendor, the device model or name, GPS or other device location,
contacts or photos. They do not put the IP address in any payload. Whisperr
still derives a country from the IP address of each event request (see
above). The Swift SDK’s privacy manifest declares no tracking
(NSPrivacyTracking is false).
What do the SDKs store on the device?
Section titled “What do the SDKs store on the device?”The SDKs keep their queue, the user ID, the anonymous_id, the opt-out
choice, the last push token sent, the last notification permission reported,
the app language, the last app version seen, the IDs of push messages already
reported, and a record of the last identify sent (the user ID, the locale,
time zone and app language it carried, and the time), used to skip a repeated
restore identify. The React Native SDK also keeps its session_id. From
React Native 0.7.0, Flutter 0.8.0 and Swift 0.7.0 the SDKs also keep a
running-visit record (session ID, last screen name, app version) while the
app is in the foreground, used to detect app_crashed. The Swift
SDK uses UserDefaults and declares it in its privacy manifest with reason CA92.1. The Flutter SDK uses
shared_preferences. The React Native SDK uses AsyncStorage when it is
installed, or the storage adapter you pass.
How does Whisperr use the data, and how do I delete it?
Section titled “How does Whisperr use the data, and how do I delete it?”Whisperr uses the data to predict churn and to send your retention messages. For your users’ data, Whisperr is your processor. It does not sell personal data or use it for advertising. See the privacy policy, in particular Retention and Your rights.
When a user asks you to delete their data, call
DELETE /v1/users/{external_id} from your backend with
the server key. optOut() stops new data from the device, but it does not
delete data that Whisperr already has.
Common questions
Do the Whisperr mobile SDKs read the advertising ID?
No. The Swift, React Native and Flutter SDKs do not read the IDFA, the Android advertising ID or the identifier for vendor. Their only device-level IDs are a random anonymous_id they create and the push token you pass.
Can a user stop the SDK from sending data?
Yes. Call optOut(). The SDK deletes its queue and sends nothing until optIn(), except requests that opt this device's push token out. Data already sent stays on the server until you erase it.
How do I delete a user's data from Whisperr?
Call DELETE /v1/users/{external_id} from your backend with the server key (wrk_…). The publishable key in your app cannot erase data.