Your consent banner works; you tested it. But have you checked what your app sends right after a user taps “Reject”? That exact question just cost Fnac €7 million: France’s CNIL fined the retailer over a tracker in its mobile app that kept sending user activity to a third party, refusal or not. Mobile app consent isn’t decided on the consent screen. It’s decided in your SDKs’ network requests, and that’s what a mobile app consent SDK audit is for.
This guide takes the tracking side of the story: what was actually held against Fnac, which SDKs need prior consent, and above all an audit method you can run in half a day with a proxy, then replay on every app release. Plus the settings for the most common SDKs and a QA checklist.
As always with these topics: nothing here is legal advice. I link to the CNIL’s texts throughout; read them with whoever owns compliance on your side.
What the CNIL held against Fnac, in plain terms
The facts, as published by the CNIL (sanction notice): on October 22, 2026 (decision SAN-2026-015), its restricted committee imposed a €7 million fine, split into €6 million for Fnac Darty Participations et Services and €1 million for Fnac Direct. The decision was made public on October 29. It all started with a complaint from the privacy group noyb, followed by an inspection of the app in March 2024.
The tracker made API calls to a third-party domain carrying an identifier assigned by Fnac and the user’s activity, including the products they viewed. The purpose: personalized recommendations (accessories, services, similar products) and training the recommendation algorithm. The CNIL doesn’t name the vendor, and I won’t guess.
A recommendation tracker isn’t “strictly necessary”
The legal basis is Article 82 of the French Data Protection Act, the same rule that governs website cookies. There are only two exemptions: the tracker is needed to transmit the communication, or it’s strictly necessary for a service the user explicitly requested. The CNIL found that product recommendations fit neither. Users asked for an app to shop in, not for an engine that learns from their browsing.
That’s the lesson for your own calls: “it improves the experience” is not an exemption. Personalization, commercial targeting, model training: prior consent.
The real breach: the refusal wasn’t honored
According to the CNIL, the companies failed to recognize the user’s choice not to consent. In other words, the fine isn’t about a missing banner; it’s about a banner whose “no” didn’t stop the data flow. On top of the fine, the CNIL ordered Fnac to comply within one month, with a €10,000 penalty per day of delay.
In my experience, it’s also the most common defect in app QA: the banner is wired to two or three SDKs, and a fourth one, added later by another team, was never connected to the consent platform.
Mobile app consent: which SDKs need prior consent
In September 2024 the CNIL published a recommendation dedicated to mobile apps, updated on April 8, 2025 (CNIL page, in French). It covers the whole chain: publishers, developers, SDK providers, operating systems and app stores. The principle doesn’t change: any processing that isn’t needed for the app to work requires consent, and refusing must be as easy as accepting. The CNIL had announced a dedicated inspection campaign on mobile apps starting in spring 2025.
Analytics, attribution, advertising, recommendations
| SDK type | Examples | Prior consent? |
|---|---|---|
| Product analytics | Firebase / GA4, Amplitude, Mixpanel | Yes, unless strictly exempt audience measurement (rare) |
| Mobile attribution (MMP) | Adjust, AppsFlyer | Yes, as soon as an advertising ID or ad network sharing is involved |
| Advertising and conversions | Meta SDK, ad network SDKs | Yes |
| Recommendations and personalization | Recommendation engines, targeted A/B testing | Yes (the Fnac case) |
| Crash and performance | Crashlytics and similar | Assess based on the data collected and its use |
| Push notifications | Push service | The OS permission doesn’t count as tracking consent |
What stays exempt, and why app analytics rarely is
The audience measurement exemption exists, but it’s narrow: anonymous statistics, strictly limited to the publisher, with no cross-referencing or sharing with third parties. An analytics SDK that shares data with an ad network, enables advertising signals or follows users across apps falls out of it immediately. And beware a common shortcut: OS permissions (location, notifications, ATT on iOS) are not GDPR consent. The CNIL recommendation points out that accepting geolocation for a feature doesn’t mean agreeing to personalized ads.
Mobile app consent SDK audit: half a day with a proxy
The only audit that counts is the network one. An SDK list in a spreadsheet tells you what should happen; a request capture tells you what actually happens.
Inventory: declared SDKs and embedded SDKs
Start with the project’s dependency list (Gradle on Android, CocoaPods or Swift Package Manager on iOS). Then look for what isn’t listed in plain sight: an ad network SDK can bundle its own sub-SDKs, and a payment or chat library can call an analytics service. For each SDK, write down its purpose, the domain it calls and how it is (or isn’t) connected to your consent platform.
The refusal network test with a proxy
Install an intercepting proxy on your machine (Charles, Proxyman or mitmproxy), route the test phone’s traffic through it and install its certificate. Then run this scenario, which I consider the bare minimum:
- uninstall the app, then reinstall it, to start from a clean state;
- start the capture before opening the app: calls made at launch, before any choice, are the most revealing;
- on the banner, tap “Reject all”;
- browse three product pages, add an item to the cart, run a search;
- kill the app, relaunch it, do a short journey again: some SDKs only re-read consent on the next launch, or forget it.
Expected result: zero calls to consent-gated third-party domains, whether before the choice or after the refusal. Then repeat with “Accept all”: you should see the calls appear. If nothing changes between the two runs, your banner is decorative.
One limit to know about: some apps reject proxy certificates (certificate pinning). In that case, audit a QA build with pinning disabled, rather than concluding too quickly that no calls are made.
Reading the requests: identifiers, events, third-party domains
Filter the capture by domain and look for three things in every request to a third party: a persistent identifier (customer ID, advertising ID, install ID), an event or screen name, and business content (product reference, category, cart value). A call to a third party carrying a customer ID and product references after a refusal is precisely the pattern the CNIL fined Fnac for.
Consent settings for common SDKs
The method names below come from the vendors’ documentation, checked in November 2026. They change with major SDK versions: always check the documentation for your version.
Firebase and GA4: consent mode for apps
Google applies the same consent mode to apps as on the web, with four types: analytics_storage, ad_storage, ad_user_data and ad_personalization (Google documentation). The principle has two steps:
- a denied default state, declared before the very first launch:
GOOGLE_ANALYTICS_DEFAULT_ALLOW_ANALYTICS_STORAGE(and its equivalents for the three other types) set tofalsein the Info.plist on iOS,google_analytics_default_allow_*meta-data in the manifest on Android; - an update when the user chooses, with
setConsent, which only changes the types you pass and persists across launches.
If you’d rather stop all collection until the user has chosen, Firebase also lets you disable collection at launch and re-enable it with setAnalyticsCollectionEnabled. To check, turn on verbose logging: Firebase prints the state of each consent type in the debug console. If you already track app conversions in GA4, I cover how they show up in reports in my guide to GA4 app conversions in cross-channel reports; and GA4’s behavior on refusal is the same as on the web, explained in Consent Mode v2 in GA4.
Adjust and MMPs: nothing before the choice
For an MMP, the most robust rule is simple: don’t initialize the SDK until the user has made a choice, and don’t initialize it at all on refusal if your use case isn’t exempt. Adjust also provides dedicated methods (Adjust documentation): trackThirdPartySharing to control sharing with partners (to call before initialization), trackMeasurementConsent to pass measurement consent, and gdprForgetMe for erasure requests. AppsFlyer and other MMPs have equivalents: look for delayed “start” or “init” in their documentation.
Meta SDK and ad SDKs: turn off auto-initialization
The Meta SDK initializes itself and logs events automatically by default. Meta documents how to delay it (Meta documentation): on Android, a com.facebook.sdk.AutoInitEnabled meta-data set to false in the manifest, and the AutoLogAppEventsEnabled flag set to false; after consent, FacebookSdk.setAutoInitEnabled(true) then FacebookSdk.fullyInitialize(). Same logic for ad network SDKs: always look for the manual initialization option.
The server-side case: a proxy doesn’t get you off the hook
Routing your flows through an sGTM server or a custom proxy changes the domain being called, not the obligation. If your server then relays user activity to an ad network or a recommendation engine, it’s still a consent-gated tracker, and it’s even harder to audit from the phone, since everything goes to your own domain. If you run server-side GTM for your mobile apps, the check also happens server-side: every event must carry the consent state, and every outgoing tag must respect it.
A QA checklist to replay on every release
| Step | Question to ask | Done? |
|---|---|---|
| Inventory | Does every SDK have a documented purpose, domain and link to the banner? | |
| Embedded SDKs | Have the SDKs’ own dependencies been checked? | |
| Default state | Is nothing sent to a third party before the choice, on first launch? | |
| Refusal | After “Reject all”, zero calls to consent-gated domains? | |
| Relaunch | Is the refusal still applied after an app restart? | |
| Acceptance | Do the calls appear after “Accept all”? | |
| Withdrawal | Does withdrawing consent in settings stop the flows without reinstalling? | |
| Server-side | Does the server respect each event’s consent state? | |
| Evidence | Is the network capture archived with the tested app version? |
The last row matters more than it looks: the CNIL requires Fnac to demonstrate that its new tool collects consent. A dated capture per version is your best evidence.
FAQ
What exactly did the CNIL hold against Fnac?
A tracker in its mobile app sent a third party an identifier and the user’s activity, including viewed products, for personalized recommendations, without honoring the user’s refusal. The result: a €7 million fine and a compliance order with a daily penalty.
Do all app analytics SDKs need consent?
Almost always. The audience measurement exemption is narrow (anonymous statistics, limited to the publisher, no third-party sharing), and most SDKs on the market fall out of it as soon as an advertising signal is enabled.
Is iOS ATT permission enough?
No. App Tracking Transparency is Apple’s permission for the advertising identifier; it doesn’t replace the consent required under Article 82 for other trackers.
How do I prove my app honors refusals?
With a network capture taken after a refusal, on a clean install, archived with the app version number. Redo it on every release that adds or updates an SDK.
The takeaway
The Fnac fine doesn’t punish a missing banner; it punishes an ignored refusal. For mobile app consent, the only check that matters happens on the network: clean install, refusal, journey, capture. Schedule that audit this week on your production version, then build it into your release QA, and start with the personalization and advertising SDKs: that’s where the risk is, and usually the surprises too.