Consent & Privacy
How the consent gate works on every LinkTrail SDK: what is held until setConsent, what grant and deny send, CMP integration, and the store privacy answers.
Every LinkTrail SDK — iOS, Android, React Native and Flutter — ships the same consent model, because the two wrappers call the native SDKs. This page is the single description of it; the SDK pages link here rather than restating it.
The gate
Consent gating is on by default (requireConsent: true) and is deny-by-default: an unset decision is treated like a denial, never like a grant. While the decision is unset the install is held — nothing leaves the device: no install call, no clipboard read on iOS, no device identifier. The hold is persisted, so a user who answers on a later launch is still attributed.
An app that never calls setConsent gets no deferred link and no attribution. Wire both answers of your consent prompt to setConsent, or pass requireConsent: false if consent is collected elsewhere.
What each state does
| Undecided (default) | Granted | Denied | |
|---|---|---|---|
| Install call | Held — nothing sent | Sent once, counted and attributed | Sent once, uncounted; on iOS it carries no device ID |
| Deferred link (first launch) | Does not route | Routes via onLink | Routes via onLink — resolved, not recorded |
| Re-engagement link (app installed) | Routes; the open is not recorded | Routes; the open is recorded | Routes; the open is not recorded |
| Custom events (trackEvent) | Dropped | Sent | Dropped; anything queued is cleared |
Calling setConsent
Call setConsent(true) or setConsent(false) once your consent UI resolves — for both answers. A decision either way releases the held install, and each answer produces exactly one install. Denial is not silence: the uncounted install is what resolves the deferred link, so a user who declines still lands on the screen the link promised.
iOS
LinkTrail.shared?.setConsent(true)Android
LinkTrail.shared?.setConsent(true)React Native
LinkTrail.setConsent(true);Flutter
await LinkTrail.setConsent(true);There is no consent getter on any platform. The native SDKs persist the decision, but your app is the source of truth: store the choice yourself and replay it with setConsent after configure on every launch, so a user who already answered never sees the prompt twice. Grant also flushes the offline event queue; deny clears it.
Android 0.0.5: decide on the first launch. The deferred link is delivered at most once — by the first install call that goes out, whichever answer released it — so if that pass resolved no routable link, a later setConsent(true) fires onAttribution but not onLink. And setConsent only re-sends the install when autoTrackInstall is on; with it off, call trackInstall() after the decision. Details on the Android SDK page.
Collecting consent elsewhere
If a consent management platform (CMP) or your own flow already governs tracking, opt out of the gate with requireConsent: false. Tracking then runs from configure and setConsent is never consulted. The gate exists so that no identifier is sent before the user has answered — switch it off only when something else already guarantees that.
iOS
LinkTrailOptions(requireConsent: false)Android
LinkTrailOptions(requireConsent = false)React Native
await LinkTrail.configure('lt_live_...', { requireConsent: false });Flutter
LinkTrailOptions(requireConsent: false)The iOS paste button
On iOS the deferred click token is read through a paste control, and the user's tap on it counts as the consent act. The native LinkTrailPasteButton records consent before it sends the install (grantsConsent: true by default; pass grantsConsent: false under a CMP and the install is held with the token until your setConsent). The React Native button (0.0.4 on npm) hands the token to the SDK but does not record consent — call LinkTrail.setConsent(true) in onTokenPasted. The Flutter widget only delivers the token — call setConsent(true), then trackInstallWithClickToken(token), in onToken. Each SDK page has the snippet.
App Tracking Transparency
The SDK needs no ATT permission: it reads no IDFA and no IDFV, and routing a user needs no advertising identifier. requestTrackingAuthorization() is a convenience for apps that run IDFA-based ad networks alongside LinkTrail; it needs NSUserTrackingUsageDescription in Info.plist or the prompt never appears. Consent for LinkTrail's own tracking is the setConsent decision, not the ATT answer — the SDK does not derive one from the other.
What is sent
With consent granted, the install call carries your app's bundle ID / package name, the platform, the click token when one was recovered, and the SDK's device identifier — on iOS a random, app-scoped per-install UUID stored in UserDefaults (no IDFA, no IDFV); on Android the App Set ID, with a random persisted UUID as fallback. A denied install on iOS carries no device identifier and no idempotency key. Custom events carry the event name, the optional value and currency, and the same device identifier.
Store privacy questionnaires
- App Store Connect → App Privacy. The SDK ships a privacy manifest (
PrivacyInfo.xcprivacy) declaring Identifiers → Device ID, linked to the user, not used for tracking, for Analytics and App Functionality;NSPrivacyTrackingis false and it lists no tracking domains. Answer the questionnaire the same way. - Google Play → Data safety. Declare Device or other IDs (the App Set ID, or the SDK's UUID fallback), collected for Analytics and App functionality. LinkTrail processes it on your behalf.
Processor terms, sub-processors and the full data inventory are in the DPA and the Privacy Policy.