Pour gérer le consentement RGPD d'AdMob dans une application Capacitor, utilisez l'UMP (User Messaging Platform) de Google SDK : demandez les informations de consentement à chaque lancement, affichez le formulaire de consentement si nécessaire, et n'initialisez les publicités que lorsque canRequestAds est vrai. Vous avez également besoin d'un point d'entrée pour les options de confidentialité afin que les utilisateurs puissent modifier leur choix, et sur iOS, le flux UMP doit précéder le prompt App Tracking Transparency. Ce guide présente le flux complet avec deux configurations : un plugin qui encapsule l'UMP en JavaScript, et @capgo/capacitor-admob avec un petit bridge natif de consentement.
Le rôle de l'UMP et pourquoi AdMob l'exige
Depuis janvier 2024, Google impose aux éditeurs diffusant des publicités auprès d'utilisateurs de l'EEE, du Royaume-Uni et de la Suisse d'utiliser une plateforme de gestion du consentement (CMP) certifiée par Google et intégrée au framework TCF de l'IAB. L'UMP SDK est la CMP certifiée de Google, gratuite et intégrée à la console AdMob.
L'UMP fait trois choses pour vous :
- Détecter si l'utilisateur se trouve dans une région où le consentement est requis.
- Afficher le message de consentement configuré dans AdMob, dans la langue de l'utilisateur.
- Stocker les choix de l'utilisateur sous forme de TC String sur l'appareil (le standard
IABTCF_clésUserDefaultssur iOS etSharedPreferencessur Android), que le SDK Google Mobile Ads SDK et les partenaires de médiation lisent lors de la demande d'annonces.
Vous pouvez également utiliser l'UMP pour les réglementations de confidentialité des États américains, qu'AdMob appelle messages « US states », depuis la même console.
Étape 1 : créez les messages dans AdMob
Dans la console AdMob, allez dans Confidentialité et messagerie:
- Créer un Réglementations européennes message (RGPD). Choisissez les applications concernées, les langues et votre liste de partenaires publicitaires.
- Créez éventuellement un États américains message.
- Sur iOS, créez un explication IDFA message si vous prévoyez de demander l’App Tracking Transparency. UMP l’affichera avant le prompt système ATT.
- Publiez les messages. Un message non publié ne s’affichera jamais.
Si le formulaire n'apparaît jamais dans votre app par la suite, vérifiez d'abord qu'aucun message n'est resté non publié ou non assigné.
Étape 2 : définir l'ordre des opérations
L'ordre qui fonctionne pour la plupart des apps :
- L'app démarre.
- Request consent info update with UMP (every launch).
- Si nécessaire, charger et afficher le formulaire de consentement.
- Si
canRequestAdsest vrai, démarrer le Mobile Ads SDK et charger les publicités. - Show a “Privacy settings” entry in your settings screen when UMP says privacy options are required.
Google permet également de démarrer le Mobile Ads SDK en parallèle de la demande de consentement quand canRequestAds était déjà vrai lors d'une session précédente. Cela réduit le délai avant la première publicité pour les utilisateurs récurrents.
Option A : un plugin qui encapsule l'UMP en JavaScript
@capacitor-community/admob (la version 8 supporte Capacitor 8) expose directement les méthodes UMP : requestConsentInfo, showConsentForm, showPrivacyOptionsForm et resetConsentInfo.
bun add @capacitor-community/admob
bunx cap sync
import {
AdMob,
AdmobConsentStatus,
AdmobConsentDebugGeography,
} from '@capacitor-community/admob';
export async function initAdsWithConsent(isDebug: boolean) {
await AdMob.initialize();
let info = await AdMob.requestConsentInfo(
isDebug
? {
debugGeography: AdmobConsentDebugGeography.EEA,
testDeviceIdentifiers: ['YOUR_TEST_DEVICE_ID'],
}
: undefined,
);
if (info.isConsentFormAvailable && info.status === AdmobConsentStatus.REQUIRED) {
info = await AdMob.showConsentForm();
}
// The enum value is the string 'REQUIRED'
const showPrivacyEntry = String(info.privacyOptionsRequirementStatus) === 'REQUIRED';
return { canRequestAds: info.canRequestAds, showPrivacyEntry };
}
export async function openPrivacyOptions() {
await AdMob.showPrivacyOptionsForm();
}
Ce plugin est la seule exception à l'ordre ci-dessus : son README exige AdMob.initialize() avant requestConsentInfo(), et sur iOS, le formulaire de consentement ne peut pas être affiché avant initialize() ne soit exécuté. initialize() démarre le SDK mais ne demande pas de publicités ; la règle qui compte est donc de ne jamais charger de publicité avant que canRequestAds est vrai. Si vous avez besoin que le SDK reste en pause jusqu'à ce que l'utilisateur ait répondu, utilisez l'option B, où le consentement s'exécute avant AdMob.start().
Vérifier canRequestAds avant chaque chargement de publicité, et pas seulement au démarrage, car l'utilisateur peut retirer son consentement via le formulaire d'options de confidentialité.
Option B : @capgo/capacitor-admob avec un bridge UMP natif
@capgo/capacitor-admob vous offre AdMob.start(), la configuration de la demande, les bannières, les interstitiels, les publicités récompensées et les interstitiels récompensés, ainsi que l'autorisation de suivi iOS. Il n'encapsule pas UMP, vous devez donc ajouter un petit plugin local à l'application qui exécute le flux de consentement avant d'appeler AdMob.start().
bun add @capgo/capacitor-admob
bunx cap sync
Ajouter l'UMP SDK
- iOS : ajouter le package de Google
GoogleUserMessagingPlatformpackage avec Swift Package Manager (Capacitor 8 projets utilisent SPM par défaut), ou le pod CocoaPods du même nom si votre projet utilise encore CocoaPods. - Android : dans
android/app/build.gradle:
dependencies {
implementation "com.google.android.ump:user-messaging-platform:<latest version>"
}
Utilisez la dernière release du dépôt Maven de Google.
Plugin de consentement iOS
Créer ios/App/App/ConsentPlugin.swift:
import Capacitor
import UserMessagingPlatform
@objc(ConsentPlugin)
public class ConsentPlugin: CAPPlugin, CAPBridgedPlugin {
public let identifier = "ConsentPlugin"
public let jsName = "Consent"
public let pluginMethods: [CAPPluginMethod] = [
CAPPluginMethod(name: "gather", returnType: CAPPluginReturnPromise),
CAPPluginMethod(name: "showPrivacyOptions", returnType: CAPPluginReturnPromise),
]
@objc func gather(_ call: CAPPluginCall) {
let parameters = RequestParameters()
DispatchQueue.main.async {
ConsentInformation.shared.requestConsentInfoUpdate(with: parameters) { error in
if let error = error {
call.reject(error.localizedDescription)
return
}
guard let vc = self.bridge?.viewController else {
call.reject("No view controller")
return
}
ConsentForm.loadAndPresentIfRequired(from: vc) { formError in
if let formError = formError {
call.reject(formError.localizedDescription)
return
}
call.resolve(self.state())
}
}
}
}
@objc func showPrivacyOptions(_ call: CAPPluginCall) {
DispatchQueue.main.async {
guard let vc = self.bridge?.viewController else {
call.reject("No view controller")
return
}
ConsentForm.presentPrivacyOptionsForm(from: vc) { formError in
if let formError = formError {
call.reject(formError.localizedDescription)
return
}
call.resolve(self.state())
}
}
}
private func state() -> [String: Any] {
return [
"canRequestAds": ConsentInformation.shared.canRequestAds,
"privacyOptionsRequired":
ConsentInformation.shared.privacyOptionsRequirementStatus == .required,
]
}
}
Enregistrez-le depuis une CAPBridgeViewController sous-classe, et définissez cette classe sur le view controller dans Main.storyboard:
import Capacitor
class MainViewController: CAPBridgeViewController {
override open func capacitorDidLoad() {
bridge?.registerPluginInstance(ConsentPlugin())
}
}
Plugin de consentement Android
Créer android/app/src/main/java/com/example/app/ConsentPlugin.java (utilisez votre nom de package) :
package com.example.app;
import com.getcapacitor.JSObject;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
import com.getcapacitor.annotation.CapacitorPlugin;
import com.google.android.ump.ConsentInformation;
import com.google.android.ump.ConsentRequestParameters;
import com.google.android.ump.UserMessagingPlatform;
@CapacitorPlugin(name = "Consent")
public class ConsentPlugin extends Plugin {
@PluginMethod
public void gather(PluginCall call) {
ConsentInformation info = UserMessagingPlatform.getConsentInformation(getContext());
ConsentRequestParameters params = new ConsentRequestParameters.Builder().build();
getActivity().runOnUiThread(() ->
info.requestConsentInfoUpdate(
getActivity(),
params,
() -> UserMessagingPlatform.loadAndShowConsentFormIfRequired(getActivity(), formError -> {
if (formError != null) {
call.reject(formError.getMessage());
return;
}
call.resolve(state(info));
}),
requestError -> call.reject(requestError.getMessage())
)
);
}
@PluginMethod
public void showPrivacyOptions(PluginCall call) {
getActivity().runOnUiThread(() ->
UserMessagingPlatform.showPrivacyOptionsForm(getActivity(), formError -> {
if (formError != null) {
call.reject(formError.getMessage());
return;
}
call.resolve(state(UserMessagingPlatform.getConsentInformation(getContext())));
})
);
}
private JSObject state(ConsentInformation info) {
JSObject ret = new JSObject();
ret.put("canRequestAds", info.canRequestAds());
ret.put(
"privacyOptionsRequired",
info.getPrivacyOptionsRequirementStatus() ==
ConsentInformation.PrivacyOptionsRequirementStatus.REQUIRED
);
return ret;
}
}
Enregistrez-le dans MainActivity.java avant super.onCreate:
public class MainActivity extends BridgeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
registerPlugin(ConsentPlugin.class);
super.onCreate(savedInstanceState);
}
}
Appelez-le depuis TypeScript
import { registerPlugin } from '@capacitor/core';
import { AdMob, BannerAd } from '@capgo/capacitor-admob';
interface ConsentState {
canRequestAds: boolean;
privacyOptionsRequired: boolean;
}
interface ConsentPlugin {
gather(): Promise<ConsentState>;
showPrivacyOptions(): Promise<ConsentState>;
}
const Consent = registerPlugin<ConsentPlugin>('Consent');
export async function startAds() {
let state: ConsentState;
try {
state = await Consent.gather();
} catch (err) {
console.warn('Consent flow failed', err);
return { showPrivacyEntry: false };
}
if (state.canRequestAds) {
await AdMob.start();
const banner = new BannerAd({
adUnitId: 'ca-app-pub-3940256099942544/2934735716', // Google test banner (iOS)
position: 'bottom',
});
await banner.show();
}
return { showPrivacyEntry: state.privacyOptionsRequired };
}
export const openPrivacyOptions = () => Consent.showPrivacyOptions();
Les modifications natives code nécessitent un nouveau build store. Ensuite, le texte de consentement de votre écran de paramètres et la logique de placement des publicités peuvent être déployés via les live updates Capgo.
Step 3: add the privacy options entry point
Lorsque UMP signale que les options de confidentialité sont requises, Google s’attend à ce qu’une méthode visible permette de rouvrir les choix de consentement. Ajoutez une ligne « Paramètres de confidentialité » à votre page de paramètres et masquez-la lorsqu’elle n’est pas requise :
const { showPrivacyEntry } = await startAds();
document.querySelector('#privacy-row')?.toggleAttribute('hidden', !showPrivacyEntry);
document.querySelector('#privacy-row')?.addEventListener('click', () => openPrivacyOptions());
Après que l’utilisateur a modifié ses choix, relisez canRequestAds avant la prochaine demande de publicité.
Étape 4 : App Tracking Transparency sur iOS
L’ATT est distinct du RGPD. L’ATT contrôle l’accès à l’IDFA sur iOS. Le consentement RGPD détermine si et comment les données personnelles peuvent être traitées. Vous avez généralement besoin des deux pour un utilisateur de l’UE sur iOS.
- Ajoutez
NSUserTrackingUsageDescriptionversInfo.plist. - Laissez UMP afficher le message explicatif IDFA et déclencher l’ATT, si vous avez configuré ce message dans AdMob. Sinon, demandez l’ATT vous-même après le flux de consentement.
Avec @capgo/capacitor-admob vous pouvez lire et demander l’état de l’ATT directement :
import { AdMob, TrackingAuthorizationStatus } from '@capgo/capacitor-admob';
const { status } = await AdMob.trackingAuthorizationStatus();
if (status === TrackingAuthorizationStatus.notDetermined) {
await AdMob.requestTrackingAuthorization();
}
Capgo propose également un plugin App Tracking Transparency autonome si vous avez besoin de l’ATT pour d’autres SDK. N’oubliez pas de déclarer le suivi dans votre manifeste de confidentialité et les étiquettes de confidentialité de l’App Store, voir notre guide du manifeste de confidentialité.
Étape 5 : tester avec la géographie de debug
UMP n’affiche le formulaire RGPD qu’aux utilisateurs qu’il localise dans l’EEE, le Royaume-Uni ou la Suisse. Pour tester ailleurs :
- Lancez l’app une fois et trouvez la ligne de log d’UMP contenant l’ID haché de votre appareil.
- Ajoutez-le comme appareil de test et définissez la géographie de debug sur l’EEE. Avec le plugin communautaire, passez
debugGeographyettestDeviceIdentifiersversrequestConsentInfo. Dans un pont natif, définissezDebugSettingssur iOS etConsentDebugSettingssur Android uniquement dans les builds de debug. - Réinitialisez le consentement entre les exécutions (
resetConsentInfo()dans le plugin communautaire,ConsentInformation.reset()natively) so the form shows again.
Ne publiez jamais de réglages de debug dans les builds de release. Conditionnez-les à un flag de build.
Étape 6 : gérer les erreurs sans bloquer l'app
Les demandes de consentement peuvent échouer : pas de réseau, app ID mal configuré ou aucun message publié. Traitez l’échec comme « pas de pubs pour l’instant », pas comme un crash :
- Si
requestConsentInfoUpdateéchoue maiscanRequestAdsétait true lors d'une session précédente, vous pouvez toujours demander des annonces. - Si le formulaire ne se charge pas, loggez l'erreur et réessayez au prochain lancement.
- Never show ads while the consent form is on screen.
Troubleshooting
Le formulaire ne s'affiche jamais. Message non publié, non associé à cet ID d'application, ou vous êtes hors EEE sans géographie de debug. Vérifiez l'ID d'application AdMob dans Info.plist et AndroidManifest.xml correspond à la console.
Le formulaire s'affiche à chaque lancement. L'utilisateur l'a fermé sans choisir, ou vous appelez reset en production code.
canRequestAds false pour les utilisateurs américains. Vous avez publié un message pour les États-Unis et l’utilisateur a refusé la vente ou le partage de ses données. N’affichez que des publicités limitées via le SDK, sans le contourner.
Mediation partners get no consent. Assurez-vous que chaque adaptateur de partenaire est à jour et figurant dans la liste des partenaires publicitaires de votre message GDPR.
Le prompt ATT iOS n’apparaît jamais. NSUserTrackingUsageDescription est manquant, ou l’utilisateur a désactivé « Autoriser les apps à demander à suivre » dans les Réglages.
La conformité au-delà du formulaire
UMP gère la partie publicitaire. Votre app doit toujours inclure une politique de confidentialité listant AdMob, les règles de conservation des données et un moyen de traiter les demandes de données. Notre checklist de conformité RGPD couvre le reste de l’application.