Compliant with GDPR, CCPA, COPPA, LGPD, PECR, PDPA, PIPEDA, and more.
UniConsent CMP is a package for handling GDPR IAB TCF 2.3 consent management in Android apps. You can find a demo app integrated with UniConsent CMP in the "uniconsent_demo" directory.
Add UniConsent_x.x.x.aar into your project. Example:
implementation files('libs/UniConsent_x.x.x.aar')
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'com.iabtcf:iabtcf-core:2.0.10'
implementation 'com.iabtcf:iabtcf-decoder:2.0.10'
Before integrating the SDK, customize the consent banner appearance in the UniConsent Dashboard to match your brand and optimize consent rates.
Go to Projects → Select your Project → Settings → Step 5: UI & Style Settings to configure:
For more precise control, add custom CSS in the CSS Content field under Step 5. This is recommended to make the banner feel native to your app and achieve the best consent rate:
/* Example: Style the accept button to match your brand */
.unic-btn-accept {
background-color: #4CAF50;
border-radius: 8px;
font-weight: 600;
}
/* Example: Adjust banner font */
.unic-banner {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
/* Example: Make the reject button less prominent */
.unic-btn-reject {
background-color: transparent;
border: 1px solid #ccc;
color: #666;
}
Tip: A well-branded consent UI that feels native to your app typically achieves higher consent rates. Users are more likely to engage positively with a banner that matches the look and feel they expect.
To use the UniConsent CMP in your app, follow these steps:
Initialize the CMP with an App ID from your account manager:
UniConsent UniConsentCMP = UniConsent.getInstance();
UniConsentCMP.setAppId("YOUR_APP_ID");
Display the CMP UI:
// Display CMP UI
UniConsent.getInstance().launchCMP(Stage.GDPRFirstScreen);
Automatically check if consent is expired when the vendorList updates:
// Automatic check if consent is expired when vendorList updates
UniConsentCMP.shouldRequestConsent();
Get the tcString if required:
// Get tcString if requried
UniConsent.getInstance().getTCString();
Read the consent status:
// Read consent status
UniConsent.getInstance().hasIABPurposeConsent(purposeId: 1)
Reset consent status if required:
// Reset consent status if required:
UniConsent.getInstance().clearData();
import com.uniconsent.sdk.Event;
import com.uniconsent.sdk.EventHandler;
import com.uniconsent.sdk.Stage;
import com.uniconsent.sdk.UniConsent;
public class MainActivity extends AppCompatActivity implements EventHandler {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
setContentView(R.layout.activity_main);
UniConsent UniConsentCMP = UniConsent.getInstance();
UniConsentCMP.setAppId("xxxxxx");
UniConsentCMP.init(this);
// register callback events
UniConsentCMP.subscribe(this);
// manual check rules after setContext
if (UniConsentCMP.shouldRequestConsent()) {
UniConsentCMP.launchCMP();
}
}
public void openUniConsentUI(View view) {
UniConsent.getInstance().launchCMP(Stage.GDPRFirstScreen);
}
@Override
public void handle(Event event) {
UniConsent.getInstance().hasIABPurposeConsent(1);
}
}
package com.example.myapplication
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.example.myapplication.ui.theme.MyApplicationTheme
import com.uniconsent.sdk.Event
import com.uniconsent.sdk.EventHandler
import com.uniconsent.sdk.Stage
import com.uniconsent.sdk.UniConsent
class MainActivity : ComponentActivity(), EventHandler {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val cmp = UniConsent.getInstance()
cmp.appId = "xxxxxx"
cmp.init(this)
cmp.subscribe(this)
// cmp.clearData()
if (cmp.shouldRequestConsent()) {
cmp.launchCMP();
}
setContent {
MyApplicationTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Spacer(modifier = Modifier.height(16.dp))
Button(
modifier = Modifier
.padding(16.dp),
onClick = {
UniConsent.getInstance().launchCMP(Stage.GDPRFirstScreen)
}
) {
Text("Privacy Settings")
}
}
}
}
}
}
override fun handle(event: Event?) {
Log.d("CMP_EVENT", event.toString())
UniConsent.getInstance().hasIABVendorConsent(1)
}
}
<uses-permission android:name="android.permission.INTERNET" />
Setup default consent status KV:
<meta-data android:name="firebase_analytics_collection_enabled" android:value="false" />
<meta-data android:name="google_analytics_default_allow_analytics_storage" android:value="false" />
<meta-data android:name="google_analytics_default_allow_ad_storage" android:value="false" />
<meta-data android:name="google_analytics_default_allow_ad_user_data" android:value="false" />
<meta-data android:name="google_analytics_default_allow_ad_personalization_signals" android:value="false" />
Control analytics based on the consent flags:
// <= 25.6.1
override fun handle(event: Event?) {
Log.d("CMP_EVENT", event.toString())
if(UniConsent.getInstance().hasIABPurposeConsent(1)) {
// Set consent types.
Map<FirebaseAnalytics.ConsentType, FirebaseAnalytics.ConsentStatus> consentMap = new EnumMap<>(FirebaseAnalytics.ConsentType.class);
consentMap.put(FirebaseAnalytics.ConsentType.ANALYTICS_STORAGE, FirebaseAnalytics.ConsentStatus.GRANTED);
consentMap.put(FirebaseAnalytics.ConsentType.AD_STORAGE, FirebaseAnalytics.ConsentStatus.GRANTED);
consentMap.put(FirebaseAnalytics.ConsentType.AD_USER_DATA, FirebaseAnalytics.ConsentStatus.GRANTED);
consentMap.put(FirebaseAnalytics.ConsentType.AD_PERSONALIZATION, FirebaseAnalytics.ConsentStatus.GRANTED);
mFirebaseAnalytics.setConsent(consentMap);
mFirebaseAnalytics.setAnalyticsCollectionEnabled(true);
} else {
// Set consent types.
Map<FirebaseAnalytics.ConsentType, FirebaseAnalytics.ConsentStatus> consentMap = new EnumMap<>(FirebaseAnalytics.ConsentType.class);
consentMap.put(FirebaseAnalytics.ConsentType.ANALYTICS_STORAGE, FirebaseAnalytics.ConsentStatus.DENIED);
consentMap.put(FirebaseAnalytics.ConsentType.AD_STORAGE, FirebaseAnalytics.ConsentStatus.DENIED);
consentMap.put(FirebaseAnalytics.ConsentType.AD_USER_DATA, FirebaseAnalytics.ConsentStatus.DENIED);
consentMap.put(FirebaseAnalytics.ConsentType.AD_PERSONALIZATION, FirebaseAnalytics.ConsentStatus.DENIED);
mFirebaseAnalytics.setConsent(consentMap);
mFirebaseAnalytics.setAnalyticsCollectionEnabled(false);
}
// other logics such as send analytics events
}
// > 25.6.1
override fun handle(event: Event?) {
Log.d("CMP_EVENT", event.toString())
// other logics such as send analytics events
// Example: send Firebase event or other analytics metrics
Bundle bundle = new Bundle();
bundle.putString(FirebaseAnalytics.Param.ITEM_ID, "id");
bundle.putString(FirebaseAnalytics.Param.ITEM_NAME, "name");
bundle.putString(FirebaseAnalytics.Param.CONTENT_TYPE, "image");
mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.SELECT_CONTENT, bundle);
}
Find more info at Set up consent mode for apps