Privacy and data handling
AppRefer tracks only with the user's permission, hashes personal data on the device, keeps test data separate and lets your server erase a user when they delete their account.
Tracking consent
The SDKs never show the App Tracking Transparency prompt. From SDK 0.6.0 they read the status your app already has (on Android, the consent you pass with setTrackingConsent()) and send it with the install. Matching an install to an ad click, sending conversions to ad networks and keeping advanced-matching data happen only when the user allowed tracking. Without permission an install gets Apple AdServices or organic attribution, and analytics, AppRefer Billing and Support keep working. The server checks the stored consent again on every forward and retry.
Installs that sent no consent
Installs from SDKs older than 0.6.0 send no consent status, and AppRefer treats those as allowed so existing apps keep their attribution. To treat a missing status as “not allowed”, settrackingConsentRequired: true on the app with PATCH /api/v1/apps/{appId} once every live version of your app is on 0.6.0 or later (or if older installs must never be tracked). See Tracking consent.Requests from installs that allowed tracking go to trk.apprefer.com; everything else goes to apprefer.com, and the two never fall back to each other. In your iOS privacy manifest, declare only trk.apprefer.com in NSPrivacyTrackingDomains. How undecided installs are held, and the trackingConsentRequired and probabilisticMatching app settings, are described under Attribution.
Turning collection off
If your app has its own privacy switch, call setCollectionEnabled(false) (SDK 0.9.1+). The choice is saved on the device. It stops attribution, consent reports, conversion-value updates and product events, and clears events waiting to be sent. AppRefer Billing and Support keep working, and Billing stops sending the install's device ID. To resume, call setCollectionEnabled(true) and then configure().
await AppRefer.setCollectionEnabled(false)When a user signs out, call reset() (SDK 0.9.0+). It clears the user's ID, queued events and Support session on the device and keeps the install's own attribution. Nothing more is sent until you call configure() for the next user.
On-device hashing
Personal data passed to setAdvancedMatching() is SHA-256 hashed on the device, so AppRefer never receives it in plain text. The SDK only sends it for installs that allowed tracking.
| Field | Example input | What is hashed |
|---|---|---|
| User@Example.com | Trimmed and lower-cased: user@example.com | |
| Phone | +1 (415) 555-1234 | Digits only: 14155551234 |
| First name | John | Trimmed and lower-cased: john |
| Last name | Doe | Trimmed and lower-cased: doe |
| Date of birth | 19900115 | Trimmed; pass it as YYYYMMDD |
These hashes are attached to conversions for Meta and TikTok, which expect hashed values. Email, phone and name details that arrive with a RevenueCat webhook are hashed on the server in the same way, and are kept only for installs that allowed tracking.
Data retention
| Data | Kept for | Purpose |
|---|---|---|
| Clicks (including IP address) | 30 days | Matching clicks to installs |
| Attributions | 400 days | Install-to-campaign mapping, long enough to cover yearly renewals |
| Forwarding retry queue | 30 days | Retrying failed sends to ad networks |
| Webhook de-duplication | 30 days | Ignoring repeated RevenueCat events |
| Held trials | 30 days | Qualified trials |
| Qualified purchase results and store notices | 400 days | Qualified purchases (observe only); ids stored as one-way hashes |
| Qualified purchase activity record | Up to 45 days | Counted SDK event ids and times per install, only for event names a rule counts; deleted when the user is erased |
| SKAdNetwork postbacks | 90 days | Postback validation |
| Audit log | 365 days | Who changed what |
| Billing events and store links | 400 days | Purchase idempotency and linking old app versions |
| Support sessions | 400 days after last use | In-app chat identity |
| Support screenshots | 400 days (unsent uploads: 1 day) | Attachments in conversations |
Records expire automatically. Aggregated analytics (installs, events, revenue) are kept in the reporting warehouse for long-term dashboards.
Test data stays separate
Data sent with a test key (pk_test_) and store sandbox purchases are kept apart from live data:
- They are never sent to ad networks.
- They don't appear in live dashboard views or revenue; use the Sandbox switch to see them.
- Installs are matched separately from live installs.
- Support conversations from test keys sit in a separate test inbox.
App Review buys with sandbox accounts in your release build, so a sandbox purchase sent with your live key still unlocks the purchase (AppRefer Billing) but is recorded as sandbox and never counted or forwarded.
SDK dependencies
No AppRefer SDK bundles another analytics or advertising SDK. The iOS SDK has no third-party dependencies. The others use only standard platform libraries:
- Android: Kotlin coroutines, Google Play Install Referrer and the Google Play services advertising ID library.
- Flutter:
shared_preferences,http,crypto,device_info_plus,package_info_plus,intland the officialin_app_purchaseplugins. - React Native: AsyncStorage and
react-native-iapas peer dependencies.
Erasing a user (account deletion)
When someone deletes their account in your app, your server calls POST /api/v1/apps/{appId}/users/erase with an organisation API key that has the users:erase scope.
curl -X POST https://apprefer.com/api/v1/apps/APP_ID/users/erase \
-H "Authorization: Bearer ak_live_..." \
-H "Content-Type: application/json" \
-d '{ "requestId": "del_8f3a2c91", "appUserId": "user_123" }'| Field | Required | Description |
|---|---|---|
requestId | Yes | Your deletion job ID, 8 to 64 letters, digits, _ or -. Retrying with it is safe. |
appUserId | Yes | The user ID you set with setUserId and use for purchases. |
deviceIds | No | Up to 20 device IDs. Each counts only if AppRefer already links it to this user. |
environment | No | all (default), live or sandbox |
AppRefer finds the user's devices itself, from setUserId and their events. It removes their attribution records, queued conversions, held trials, support conversations, the support context your backend sent and AppRefer Billing identity straight away and answers 202. Rows in the reporting warehouse follow within a few hours, once recent rows can be changed. Check progress with GET /api/v1/apps/{appId}/users/erase/{requestId}.
- Analytics events become anonymous counts: no user, device or session ID, no properties, and the time cut to the day, so they no longer link to each other or to anyone.
- Accounting records (payments, refunds, renewals, trial starts and the billing ledger) keep their amounts, dates and products, with the user replaced by a keyed one-way stand-in. They are never listed in the dashboard or API, and are deleted seven years after their date, which covers the six years after the end of the financial year that tax record-keeping rules require.
- App settings, links and integrations are never touched. Conversions already sent to ad networks can't be recalled.
- Reusing a
requestIdfor a different user returns 409. 30 days after the job finished AppRefer forgets the request and returns 409REQUEST_ID_EXPIRED.
Live and sandbox data
By default one call erases the user's live and sandbox data together. Send "environment": "sandbox" to erase only test data (installs and support chats made with a test key, App Store and Google Play sandbox purchases), for example to clear your testers before launch, or "live" for the reverse. The value is returned on the job; anything else is a 400, and retrying a requestId with a different environment is a 409.
A sandbox-only erase never touches live data, so it keeps the records AppRefer holds once per user for both sides (the Billing customer record, account tokens and store links). Use the default if you want those gone too.
Account deletion must use the default
In-app account deletion must useall. live leaves the user's sandbox purchases, test installs and test-key chats tied to them. Use a separate requestId per environment (for example an sb_ prefix for tester clean-ups): a requestId used once with sandbox can't later be reused for the full deletion.Your data, secured
Attribution data and ad network credentials are encrypted in transit and at rest, and integration secrets are never shown again after you save them. Your data is only sent to the ad networks and services you connect.