Analytics tracking can be disabled by user
Why it matters
GDPR Art. 7(3) grants users the right to withdraw consent at any time, and withdrawal must be as easy as giving consent. CCPA §1798.120 grants California consumers the right to opt out of the sale or sharing of personal information. An analytics opt-out toggle that exists in Settings but does not actually stop data collection is deceptive — and regulators have specifically targeted this pattern, where consent signals are recorded but not enforced. The ePrivacy Directive Art. 5(3) further requires that tracking cookies or equivalent tracking mechanisms require prior consent in EU member states. An analytics SDK that runs regardless of the user's stored preference treats user choice as cosmetic.
Severity rationale
Low because the user retains visibility of the broken opt-out, and enforcement requires regulators to test the feature — but a non-functional opt-out is a direct GDPR Art. 7(3) and CCPA §1798.120 violation.
Remediation
Implement the opt-out as a gate on the analytics call site, not just a stored preference. The SDK must not send any event when analyticsEnabled is false.
import AsyncStorage from '@react-native-async-storage/async-storage'
export async function trackEvent(name: string, props?: Record<string, unknown>) {
const pref = await AsyncStorage.getItem('analyticsOptOut')
if (pref === 'true') return // User opted out — do not send
analytics.track(name, props)
}
// In Settings screen
async function handleOptOutToggle(optOut: boolean) {
await AsyncStorage.setItem('analyticsOptOut', String(optOut))
if (optOut) {
analytics.reset() // Flush queued events and clear identity
}
}
Also call analytics.reset() on opt-out to flush any queued events and disassociate the device ID — some SDKs batch events and will send opted-out data if only initialization is gated.
Detection
-
ID:
analytics-opt-out -
Severity:
low -
What to look for: Search for analytics opt-out toggles in Settings screens. Enumerate all analytics SDK initialization calls and check whether each checks an opt-out flag before sending data. Quote the actual toggle implementation (or note its absence).
-
Pass criteria: At least 1 toggle exists in settings to disable analytics/tracking. When toggled off, at least 100% of analytics calls check the opt-out preference and skip data collection. Report the count even on pass: "Found N analytics call sites, all check opt-out flag."
-
Fail criteria: No analytics opt-out available to users. OR toggle exists but analytics still runs when disabled (opt-out flag not checked before sending events).
-
Skip (N/A) when: App does not use analytics or crash reporting (no analytics SDK found in dependencies).
-
Detail on fail: Quote the analytics initialization code.
"No option to disable analytics in settings"or"Analytics disabled setting exists but analytics events still sent when disabled" -
Remediation: Allow users to opt out of analytics:
// In settings const [analyticsEnabled, setAnalyticsEnabled] = useState(true) const toggleAnalytics = async (enabled) => { setAnalyticsEnabled(enabled) await AsyncStorage.setItem('analyticsEnabled', String(enabled)) if (enabled) { initAnalytics() } else { disableAnalytics() } } // When tracking events async function trackEvent(eventName) { const analyticsEnabled = await AsyncStorage.getItem('analyticsEnabled') if (analyticsEnabled !== 'false') { analytics.track(eventName) } }
External references
- gdpr · Art. 7(3) — Right to withdraw consent
- ccpa · §1798.120 — Right to opt-out of sale
- eprivacy · Art. 5(3) — Confidentiality of communications / cookie consent
Taxons
History
- 2026-04-18·v1.0.0·Initial import from mobile-permissions-privacy·automated