[ Web Proxy ]
URL:
Viewing: https://firebase.google.com/docs/admob/cpp/privacy/ [Back]  [Original]

Get started  |  Google for Developers Skip to main content
Google for Developers [Google for Developers]

Get started Stay organized with collections Save and categorize content based on your preferences.

outlined_flag

The Google User Messaging Platform (UMP) SDK is a privacy and messaging tool to help you manage privacy choices. For more information, see About Privacy & messaging.

Prerequisites

Create a message type

Create user messages with one of the Available user message types under the Privacy & messaging tab of your AdMob account. The UMP SDK attempts to display a privacy message created from the AdMob Application ID set in your project.

For more details, see About privacy and messaging.

Install the SDK

  1. Follow the steps to install the Firebase C++ SDK. The UMP C++ SDK is included in the Firebase C++ SDK.

  2. Ensure that you configure your app's AdMob app ID in the project before continuing.

  3. In your code, initialize the UMP SDK by calling ConsentInfo::GetInstance().

    • On Android, you need to pass in the JNIEnv and Activity provided by the NDK. You only need to do this the first time you call GetInstance().
    • Alternatively, if you're already using the Firebase C++ SDK in your app, you can pass in a firebase::App the first time you call GetInstance().
    #include "firebase/ump/ump.h"
    
    namespace ump = ::firebase::ump;
    
    // Initialize using a firebase::App
    void InitializeUserMessagingPlatform(const firebase::App& app) {
      ump::ConsentInfo* consent_info = ump::ConsentInfo::GetInstance(app);
    }
    
    // Initialize without a firebase::App
    #ifdef ANDROID
    void InitializeUserMessagingPlatform(JNIEnv* jni_env, jobject activity) {
      ump::ConsentInfo* consent_info = ump::ConsentInfo::GetInstance(jni_env, activity);
    }
    #else  // non-Android
    void InitializeUserMessagingPlatform() {
      ump::ConsentInfo* consent_info = ump::ConsentInfo::GetInstance();
    }
    #endif
    

Subsequent calls to ConsentInfo::GetInstance() all return the same instance.

Note: The GetInstance() methods have an optional firebase::InitResult output parameter, which returns firebase::kInitResultSuccess if the SDK was initialized successfully, or firebase::kInitResultFailedMissingDependency if any required dependencies are missing from your application. Ensure you have followed all of the installation steps for your platform if this error occurs.

If you're finished using the UMP SDK, you can shut down the SDK by deleting the ConsentInfo instance:

void ShutdownUserMessagingPlatform() {
  ump::ConsentInfo* consent_info = ump::ConsentInfo::GetInstance();
  delete consent_info;
}
Note: You don't need to initialize the Firebase C++ SDK prior to initializing the User Messaging Platform SDK.

Use a Future to monitor asynchronous operations

A firebase::Future provides you a way to determine the completion status of asynchronous method calls.

All UMP C++ functions and method calls that operate asynchronously return a Future, and also provide a "last result" function to retrieve the Future from the most recent operation.

There are two ways to obtain a result from a Future:

  1. Call OnCompletion(), passing in your own callback function, which is called when the operation completes.
  2. Periodically check the Future's status(). When the status changes from kFutureStatusPending to kFutureStatusCompleted, the operation has been completed.

After the asynchronous operation is completed, you should check the Future's error() to obtain the operation's error code. If the error code is 0 (kConsentRequestSuccess or kConsentFormSuccess), the operation completed successfully; otherwise, check the error code and error_message() to determine what went wrong.

Note: The error code returned by RequestConsentInfoUpdate() uses the enum ConsentRequestError; all other operations use ConsentFormError.

Completion callback

Here is an example of how to use OnCompletion to set a completion callback, which is called when the asynchronous operation completes.

void MyApplicationStart() {
  // [... other app initialization code ...]

  ump::ConsentInfo *consent_info = ump::ConsentInfo::GetInstance();

  // See the section below for more information about RequestConsentInfoUpdate.
  firebase::Future<void> result = consent_info->RequestConsentInfoUpdate(...);

  result.OnCompletion([](const firebase::Future<void>& req_result) {
    if (req_result.error() == ump::kConsentRequestSuccess) {
      // Operation succeeded. You can now call LoadAndShowConsentFormIfRequired().
    } else {
      // Operation failed. Check req_result.error_message() for more information.
    }
  });
}

Update loop polling

In this example, after an asynchronous operation is started at app launch, the results are checked elsewhere, in the game's update loop function (which runs once per frame).

ump::ConsentInfo *g_consent_info = nullptr;
bool g_waiting_for_request = false;

void MyApplicationStart() {
  // [... other app initialization code ...]

  g_consent_info = ump::ConsentInfo::GetInstance();
  // See the section below for more information about RequestConsentInfoUpdate.
  g_consent_info->RequestConsentInfoUpdate(...);
  g_waiting_for_request = true;
}

// Elsewhere, in the game's update loop, which runs once per frame:
void MyGameUpdateLoop() {
  // [... other game logic here ...]

  if (g_waiting_for_request) {
    // Check whether RequestConsentInfoUpdate() has finished.
    // Calling "LastResult" returns the Future for the most recent operation.
    firebase::Future<void> result =
      g_consent_info->RequestConsentInfoUpdateLastResult();

    if (result.status() == firebase::kFutureStatusComplete) {
      g_waiting_for_request = false;
      if (result.error() == ump::kConsentRequestSuccess) {
        // Operation succeeded. You can call LoadAndShowConsentFormIfRequired().
      } else {
        // Operation failed. Check result.error_message() for more information.
      }
    }
  }
}

For more information about firebase::Future, see the Firebase C++ SDK documentation and the GMA C++ SDK documentation.

Note: In the UMP C++ SDK, all asynchronous operations return firebase::Future&lt;void&gt;.

You should request an update of the user's consent information at every app launch, using RequestConsentInfoUpdate(). This request checks the following:

#include "firebase/ump/ump.h"

namespace ump = ::firebase::ump;

void MyApplicationStart(ump::FormParent parent) {
  ump::ConsentInfo* consent_info = ump::ConsentInfo::GetInstance();

  // Create a ConsentRequestParameters struct..
  ump::ConsentRequestParameters params;
  // Set tag for under age of consent. False means users are NOT under age of consent.
  params.tag_for_under_age_of_consent = false;

  consent_info->RequestConsentInfoUpdate(params).OnCompletion(
    [*](const Future<void>& req_result) {
      if (req_result.error() != ump::kConsentRequestSuccess) {
        // req_result.error() is a kConsentRequestError enum.
        LogMessage("Error requesting consent update: %s", req_result.error_message());
      }
      // Consent information is successfully updated.
    });
}
Warning: Using other ways of checking consent status, such as the cache on your app or a previously saved consent string, can lead to a TCF 3.3 error if consent is expired.

Load and present the privacy message form

After you have received the most up-to-date consent status, call LoadAndShowConsentFormIfRequired() to load any forms required to collect user consent. After loading, the forms present immediately.

Key Point: If no privacy message forms require collection of user consent prior to requesting ads, the callback is invoked immediately.
#include "firebase/ump/ump.h"

namespace ump = ::firebase::ump;

void MyApplicationStart(ump::FormParent parent) {
  ump::ConsentInfo* consent_info = ump::ConsentInfo::GetInstance();

  // Create a ConsentRequestParameters struct..
  ump::ConsentRequestParameters params;
  // Set tag for under age of consent. False means users are NOT under age of consent.
  params.tag_for_under_age_of_consent = false;

  consent_info->RequestConsentInfoUpdate(params).OnCompletion(
    [*](const Future<void>& req_result) {
      if (req_result.error() != ump::kConsentRequestSuccess) {
        // req_result.error() is a kConsentRequestError enum.
        LogMessage("Error requesting consent update: %s", req_result.error_message());
      } else {
        consent_info->LoadAndShowConsentFormIfRequired(parent).OnCompletion(
        [*](const Future<void>& form_result) {
          if (form_result.error() != ump::kConsentFormSuccess) {
            // form_result.error() is a kConsentFormError enum.
            LogMessage("Error showing privacy message form: %s", form_result.error_message());
          } else {
            // Either the form was shown and completed by the user, or consent was not required.
          }
        });
      }
    });
}

See above for an example of checking for completion using update loop polling rather than a completion callback.

Note: Depending on the platform, FormParent is either a JNI jobject reference to an Android Activity, or a pointer to an iOS UIViewController, cast to an FormParent type.

If you need to perform any actions after the user has made a choice or dismissed the form, place that logic in the code that handles the Future returned by LoadAndShowConsentFormIfRequired().

Privacy options

Some privacy message forms are presented from a publisher-rendered privacy options entry point, letting users manage their privacy options at any time. To learn more about which message your users see at the privacy options entry point, see Available user message types.

Request ads with user consent

Before requesting ads, use ConsentInfo::GetInstance()‑> CanRequestAds() to check if you've obtained consent from the user:

Listed are the following places to check if you can request ads while gathering consent:

Important: ConsentInfo::GetInstance()‑> CanRequestAds() always returns false until you have called RequestConsentInfoUpdate()

If an error occurs during the consent gathering process, check if you can request ads. The UMP SDK uses the consent status from the previous app session.

Prevent redundant ad request work

As you check ConsentInfo::GetInstance()‑> CanRequestAds() after gathering consent and after calling RequestConsentInfoUpdate(), ensure your logic prevents redundant ad requests that might result in both checks returning true. For example, with a boolean variable.

The following complete example uses update loop polling, but you can also use OnCompletion callbacks to monitor asynchronous operations. Use whichever technique fits your code structure better.

#include "firebase/future.h"
#include "firebase/gma/gma.h"
#include "firebase/ump/ump.h"

namespace gma = ::firebase::gma;
namespace ump = ::firebase::ump;
using firebase::Future;

ump::ConsentInfo* g_consent_info = nullptr;
// State variable for tracking the UMP consent flow.
enum { kStart, kRequest, kLoadAndShow, kInitGma, kFinished, kErrorState } g_state = kStart;
bool g_ads_allowed = false;

void MyApplicationStart() {
  g_consent_info = ump::ConsentInfo::GetInstance(...);

  // Create a ConsentRequestParameters struct..
  ump::ConsentRequestParameters params;
  // Set tag for under age of consent. False means users are NOT under age of consent.
  params.tag_for_under_age_of_consent = false;

  g_consent_info->RequestConsentInfoUpdate(params);
  // CanRequestAds() can return a cached value from a previous run immediately.
  g_ads_allowed = g_consent_info->CanRequestAds();
  g_state = kRequest;
}

// This function runs once per frame.
void MyGameUpdateLoop() {
  // [... other game logic here ...]

  if (g_state == kRequest) {
    Future<void> req_result = g_consent_info->RequestConsentInfoUpdateLastResult();

    if (req_result.status() == firebase::kFutureStatusComplete) {
      g_ads_allowed = g_consent_info->CanRequestAds();
      if (req_result.error() == ump::kConsentRequestSuccess) {
        // You must provide the FormParent (Android Activity or iOS UIViewController).
        ump::FormParent parent = GetMyFormParent();
        g_consent_info->LoadAndShowConsentFormIfRequired(parent);
        g_state = kLoadAndShow;
      } else {
        LogMessage("Error requesting consent status: %s", req_result.error_message());
        g_state = kErrorState;
      }
    }
  }
  if (g_state == kLoadAndShow) {
    Future<void> form_result = g_consent_info->LoadAndShowConsentFormIfRequiredLastResult();

    if (form_result.status() == firebase::kFutureStatusComplete) {
      g_ads_allowed = g_consent_info->CanRequestAds();
      if (form_result.error() == ump::kConsentRequestSuccess) {
        if (g_ads_allowed) {
          // Initialize GMA. This is another asynchronous operation.
          firebase::gma::Initialize();
          g_state = kInitGma;
        } else {
          g_state = kFinished;
        }
        // Optional: shut down the UMP SDK to save memory.
        delete g_consent_info;
        g_consent_info = nullptr;
      } else {
        LogMessage("Error displaying privacy message form: %s", form_result.error_message());
        g_state = kErrorState;
      }
    }
  }
  if (g_state == kInitGma && g_ads_allowed) {
    Future<gma::AdapterInitializationStatus> gma_future = gma::InitializeLastResult();

    if (gma_future.status() == firebase::kFutureStatusComplete) {
      if (gma_future.error() == gma::kAdErrorCodeNone) {
        g_state = kFinished;
        // TODO: Request an ad.
      } else {
        LogMessage("Error initializing GMA: %s", gma_future.error_message());
        g_state = kErrorState;
      }
    }
  }
}

Testing

If you want to test the integration in your app as you're developing, follow these steps to programmatically register your test device. Be sure to remove the code that sets these test device IDs before you release your app.

  1. Call RequestConsentInfoUpdate().
  2. Check the log output for a message similar to the following example, which shows your device ID and how to add it as a test device:

    Android

    Use new ConsentDebugSettings.Builder().addTestDeviceHashedId("33BE2250B43518CCDA7DE426D04EE231")
    to set this as a debug device.
    

    iOS

    <UMP SDK>To enable debug mode for this device,
    set: UMPDebugSettings.testDeviceIdentifiers = @[2077ef9a63d2b398840261c8221a0c9b]
    
  3. Copy your test device ID to your clipboard.

  4. Modify your code to set ConsentRequestParameters.debug_settings.debug_device_ids to a list of your test device IDs.

    void MyApplicationStart() {
      ump::ConsentInfo consent_info = ump::ConsentInfo::GetInstance(...);
    
      ump::ConsentRequestParameters params;
      params.tag_for_under_age_of_consent = false;
      params.debug_settings.debug_device_ids = {"TEST-DEVICE-HASHED-ID"};
    
      consent_info->RequestConsentInfoUpdate(params);
    }
    

Force a geography

The UMP SDK provides a way to test your app's behavior as though the device were located in various regions, such as the European Economic Area (EEA), the United Kingdom (UK), and Switzerland using debug_settings.debug_geography. Note that debug settings only work on test devices.

void MyApplicationStart() {
  ump::ConsentInfo consent_info = ump::ConsentInfo::GetInstance(...);

  ump::ConsentRequestParameters params;
  params.tag_for_under_age_of_consent = false;
  params.debug_settings.debug_device_ids = {"TEST-DEVICE-HASHED-ID"};
  // Geography appears as EEA for debug devices.
  params.debug_settings.debug_geography = ump::kConsentDebugGeographyEEA

  consent_info->RequestConsentInfoUpdate(params);
}

When testing your app with the UMP SDK, you might find it helpful to reset the state of the SDK so that you can simulate a user's first install experience. The SDK provides the Reset() method to do this.

  ConsentInfo::GetInstance()->Reset();
Caution: This method is intended to be used for testing purposes only. You shouldn't call Reset() in production code.

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026-08-15 UTC.

[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2026-08-15 UTC."],[],["The Google User Messaging Platform (UMP) SDK manages user privacy choices. Key actions include: creating messages in AdMob, installing the SDK, and initializing it via `ConsentInfo::GetInstance()`. Use `RequestConsentInfoUpdate()` to check if consent is needed and if a privacy options entry point is required. `LoadAndShowConsentFormIfRequired()` loads consent forms. Use `CanRequestAds()` before requesting ads. Test integration using `ConsentRequestParameters.debug_settings` to set test device IDs and debug geographies. Use `Reset()` to reset the consent state.\n"]]

Web Proxy Viewer  |  New URL  |  Original Page