Um AdMob-GDPR-Consent in einer Capacitor-App zu handhaben, nutzt du Googles User Messaging Platform (UMP) SDK: Fordere bei jedem Start Consent-Informationen an, zeige das Consent-Formular, wenn erforderlich, und initialisiere Anzeigen nur, wenn canRequestAds true ist. Du brauchst außerdem einen Einstiegspunkt für Datenschutzoptionen, damit Nutzer ihre Wahl ändern können, und auf iOS sollte der UMP-Flow vor dem App Tracking Transparency-Prompt kommen. Dieser Guide zeigt den kompletten Flow mit zwei Setups: ein Plugin, das UMP in JavaScript kapselt, und @capgo/capacitor-admob mit einer kleinen nativen Consent-Bridge.
Was UMP macht und warum AdMob es verlangt
Seit Januar 2024 verlangt Google von Publishern, die Werbung an Nutzer im EWR, in UK und in der Schweiz ausspielen, eine von Google zertifizierte Consent-Management-Plattform (CMP), die mit dem IAB Transparency and Consent Framework (TCF) integriert ist. Die UMP SDK ist Googles eigene zertifizierte CMP, kostenlos und in der AdMob-Konsole enthalten.
Die UMP erledigt drei Dinge für dich:
- Erkennt, ob sich der Nutzer in einer Region befindet, in der eine Einwilligung erforderlich ist.
- Zeigt die in AdMob konfigurierte Consent-Nachricht in der Sprache des Nutzers an.
- Speichert die Auswahl des Nutzers als TC-String auf dem Gerät (die Standard-
IABTCF_Keys inUserDefaultsauf iOS undSharedPreferencesauf Android), den die Google Mobile Ads SDK und Mediationspartner beim Anfordern von Werbung lesen.
Du kannst die UMP auch für die Datenschutzvorschriften der US-Bundesstaaten nutzen, die AdMob „US states“-Nachrichten nennt, und zwar in derselben Konsole.
Schritt 1: Nachrichten in AdMob erstellen
Gehe in der AdMob-Konsole zu Datenschutz & Messaging:
- Erstelle ein Europäische Vorschriften Nachricht (DSGVO). Wählen Sie aus, auf welche Apps sie zutrifft, die Sprachen und Ihre Liste der Werbetreibenden.
- Erstellen Sie optional eine US-Bundesstaaten Nachricht.
- Erstellen Sie auf iOS eine IDFA-Erklärung Nachricht, wenn Sie App Tracking Transparency anfordern möchten. UMP zeigt sie vor dem System-ATT-Prompt an.
- Veröffentlichen Sie die Nachrichten. Eine unveröffentlichte Nachricht wird nie angezeigt.
Falls das Formular später nicht in Ihrer App erscheint, prüfen Sie zuerst, ob die Nachricht unveröffentlicht oder nicht zugewiesen ist.
Schritt 2: Reihenfolge der Operationen festlegen
The order that works for most apps:
- App startet.
- Consent-Info-Update mit UMP anfordern (bei jedem Start).
- Falls erforderlich, Consent-Formular laden und anzeigen.
- Wenn
canRequestAdstrue ist, starte die Mobile Ads SDK und lade Anzeigen. - Zeige einen Eintrag „Datenschutzeinstellungen“ in deinem Einstellungsbildschirm an, wenn UMP meldet, dass Datenschutzoptionen erforderlich sind.
Google erlaubt es auch, die Mobile Ads SDK parallel zur Consent-Anfrage zu starten, wenn canRequestAds bereits aus einer vorherigen Sitzung true war. Das verkürzt die Zeit bis zur ersten Anzeige für wiederkehrende Nutzer.
Option A: ein Plugin, das UMP in JavaScript kapselt
@capacitor-community/admob (Version 8 unterstützt Capacitor 8) stellt UMP-Methoden direkt bereit: requestConsentInfo, showConsentForm, showPrivacyOptionsForm und 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();
}
Dieses Plugin ist die einzige Ausnahme von der obigen Reihenfolge: Sein README verlangt AdMob.initialize() bevor requestConsentInfo(), und unter iOS kann das Consent-Formular erst angezeigt werden, wenn initialize() has run. initialize() startet das SDK, fordert aber keine Ads an. Die entscheidende Regel ist also: Lade niemals eine Ad, bevor canRequestAds wahr ist. Wenn das SDK gestoppt bleiben soll, bis der User geantwortet hat, nutze Option B, bei der der Consent vor AdMob.start().
Prüfen canRequestAds bei jedem Ad-Load läuft, nicht nur beim Startup, da der User den Consent über das Privacy-Optionen-Formular widerrufen kann.
Option B: @capgo/capacitor-admob mit einer nativen UMP-Bridge
@capgo/capacitor-admob bietet dir AdMob.start(), Konfiguration, Banner-, Interstitial-, Belohnungs- und Belohnungs-Interstitial-Anzeigen sowie iOS-Tracking-Autorisierung. Es kapselt UMP nicht, daher fügst du ein kleines app-lokales Plugin hinzu, das den Consent-Flow ausführt, bevor du AdMob.start().
bun add @capgo/capacitor-admob
bunx cap sync
Füge das UMP SDK hinzu
- iOS: füge Googles
GoogleUserMessagingPlatformPaket mit Swift Package Manager hinzu (Capacitor 8 Projekte nutzen standardmäßig SPM) oder das CocoaPods-Pod mit demselben Namen, falls dein Projekt noch CocoaPods verwendet. - Android: in einem
android/app/build.gradle:
dependencies {
implementation "com.google.android.ump:user-messaging-platform:<latest version>"
}
Nutze die neueste Version aus Googles Maven-Repository.
iOS-Consent-Plugin
Erstellen 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,
]
}
}
Registriere es aus einer CAPBridgeViewController Subklasse und setze diese Klasse auf den View Controller in Main.storyboard:
import Capacitor
class MainViewController: CAPBridgeViewController {
override open func capacitorDidLoad() {
bridge?.registerPluginInstance(ConsentPlugin())
}
}
Android-Consent-Plugin
Erstellen android/app/src/main/java/com/example/app/ConsentPlugin.java (deinen Paketnamen verwenden):
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;
}
}
Registriere es in MainActivity.java bevor super.onCreate:
public class MainActivity extends BridgeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
registerPlugin(ConsentPlugin.class);
super.onCreate(savedInstanceState);
}
}
Aufruf aus 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();
Native code Änderungen erfordern einen neuen Store-Build. Danach können die Consent-Texte in Ihrem Einstellungsbildschirm und die Logik für die Anzeigenplatzierung per Capgo Live Updates.
Schritt 3: Einstiegspunkt für die Datenschutzoptionen hinzufügen
Wenn UMP meldet, dass Datenschutzoptionen erforderlich sind, erwartet Google eine sichtbare Möglichkeit, die Consent-Auswahl erneut zu öffnen. Füge deiner Einstellungsseite eine Zeile „Datenschutzeinstellungen“ hinzu und verstecke sie, wenn sie nicht erforderlich ist:
const { showPrivacyEntry } = await startAds();
document.querySelector('#privacy-row')?.toggleAttribute('hidden', !showPrivacyEntry);
document.querySelector('#privacy-row')?.addEventListener('click', () => openPrivacyOptions());
Nachdem der Benutzer seine Auswahl geändert hat, lies canRequestAds erneut vor der nächsten Ad-Anfrage.
Schritt 4: App Tracking Transparency auf iOS
ATT ist unabhängig von der DSGVO. ATT steuert den Zugriff auf die IDFA auf iOS. Der DSGVO-Consent steuert, ob und wie personenbezogene Daten verarbeitet werden dürfen. Für EU-Nutzer auf iOS benötigst du in der Regel beides.
- Füge
NSUserTrackingUsageDescriptionzuInfo.plist. - Lass UMP die IDFA-Erklärung anzeigen und ATT auslösen, falls du diese Nachricht in AdMob konfiguriert hast. Andernfalls fordere ATT selbst nach dem Consent-Flow an.
Mit @capgo/capacitor-admob du kannst den ATT-Status direkt lesen und anfordern:
import { AdMob, TrackingAuthorizationStatus } from '@capgo/capacitor-admob';
const { status } = await AdMob.trackingAuthorizationStatus();
if (status === TrackingAuthorizationStatus.notDetermined) {
await AdMob.requestTrackingAuthorization();
}
Capgo hat auch ein eigenständiges App Tracking Transparency-Plugin falls du ATT für andere SDKs benötigst. Vergiss nicht, Tracking in deiner Privacy-Manifest und den App Store-Privacy-Labels zu deklarieren, siehe unsere Privacy-Manifest-Guide.
Schritt 5: Mit Debug-Geografie testen
UMP zeigt das DSGVO-Formular nur Nutzern im EWR, UK oder der Schweiz an. Zum Testen außerhalb:
- Starte die App einmal und suche in den Logs nach der UMP-Zeile mit der gehashten ID deines Geräts.
- Füge sie als Testgerät hinzu und setze die Debug-Geografie auf EWR. Übergib mit dem Community-Plugin
debugGeographyundtestDeviceIdentifierszurequestConsentInfo. In einer nativen Bridge setzeDebugSettingsauf iOS undConsentDebugSettingsauf Android nur in Debug-Builds. - Setze den Consent zwischen den Runs zurück (
resetConsentInfo()im Community-Plugin,ConsentInformation.reset()nativ), damit das Formular erneut erscheint.
Liefere niemals Debug-Einstellungen in Release-Builds aus. Mache sie von einem Build-Flag abhängig.
Schritt 6: Fehler behandeln, ohne die App zu blockieren
Consent-Anfragen können fehlschlagen: kein Netzwerk, falsch konfigurierte App-ID oder keine veröffentlichte Nachricht. Behandle das Scheitern als „erstmal keine Werbung“, nicht als Crash:
- Wenn
requestConsentInfoUpdatefehlschlägt, abercanRequestAdsin einer früheren Sitzung true war, kannst du weiterhin Werbung anfordern. - If the form fails to load, log it and retry on the next launch.
- Zeige niemals Werbung, während das Consent-Formular auf dem Bildschirm ist.
Fehlerbehebung
Das Formular wird nie angezeigt. Nachricht nicht veröffentlicht, nicht dieser App-ID zugeordnet oder Sie befinden sich außerhalb des EWR ohne Debug-Geografie. Prüfen Sie die AdMob-App-ID in Info.plist und AndroidManifest.xml entspricht der Konsole.
Das Formular erscheint bei jedem Start. Der User hat es ohne Auswahl geschlossen, oder du rufst reset in der Produktion auf code.
canRequestAds false für US-Nutzer. Du hast eine Nachricht für US-Bundesstaaten veröffentlicht und der User hat dem Verkauf oder der Weitergabe widersprochen. Zeige nur eingeschränkte Ads über SDK an, umgehe es nicht.
Mediation-Partner erhalten keine Einwilligung. Stelle sicher, dass jeder Partner-Adapter aktuell ist und in der Ad-Partner-Liste deiner GDPR-Nachricht aufgeführt wird.
Der iOS-ATT-Prompt erscheint nie. NSUserTrackingUsageDescription fehlt, oder der User hat „Apps erlauben, Tracking anzufordern“ in den Einstellungen deaktiviert.
Compliance über das Formular hinaus
UMP übernimmt die Ad-Seite. Deine App braucht weiterhin eine Datenschutzerklärung, die AdMob, Regeln zur Datenaufbewahrung und den Umgang mit Datenanfragen abdeckt. Unsere GDPR-Compliance-Checkliste deckt den Rest der App ab.