Skip to main content

Integrating Customer Center on Android

AIAsk AIChatGPTClaude

Installation

Release

Before integrating the Customer Center in Android, you need to add the com.revenuecat.purchases:purchases-ui SDK 8.12.2 or higher to your app.

implementation 'com.revenuecat.purchases:purchases:<latest version>'
implementation 'com.revenuecat.purchases:purchases-ui:<latest version>'

Integration

There's a CustomerCenter composable that can be used to display the Customer Center. It's intended to be used as a full screen composable so make sure to use it with a fillMaxSize modifier:

import com.revenuecat.purchases.ui.revenuecatui.customercenter.CustomerCenter

...

@Composable
fun YourAppScreen() {
var isCustomerCenterVisible by remember { mutableStateOf(false) }

if (isCustomerCenterVisible) {
CustomerCenter(modifier = Modifier.fillMaxSize(), onDismiss = { isCustomerCenterVisible = false })
return
}

Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Button(onClick = {
isCustomerCenterVisible = true
}) {
Text(text = "Show customer center")
}
}
}

Alternatively, you can instantiate the Customer Center as an Activity in com.revenuecat.purchases:purchases-ui SDK 8.13.0 or higher:

import com.revenuecat.purchases.ui.revenuecatui.customercenter.ShowCustomerCenter

class MyActivity : ComponentActivity() {
private val customerCenter = registerForActivityResult(ShowCustomerCenter()) {
// Handle the dismissal
}

fun showCustomerCenter() {
customerCenter.launch()
}
}

Ensuring Proper Theming for Customer Center

To ensure that Customer Center displays correctly with the right colors, contrast, and theme consistency, it needs to be wrapped in Material 3's MaterialTheme. This allows it to dynamically adapt to dark and light mode while applying the correct Material Design colors to all UI elements. If your app already uses Material 3's MaterialTheme with appropriate color schemes for dark and light mode, no additional changes are needed. However, if CustomerCenter is the only composable in your hierarchy, if you're using Material 2, or if you're using another theming system, you may need to explicitly wrap it in Material 3's MaterialTheme to ensure proper theming.

import androidx.compose.material3.MaterialTheme

val isDarkTheme = isSystemInDarkTheme()
val colorScheme = if (isDarkTheme) darkColorScheme() else lightColorScheme()

MaterialTheme(
colorScheme = colorScheme,
) {
CustomerCenter(
modifier = Modifier.fillMaxSize(),
onDismiss = { isCustomerCenterVisible = false }
)
}

Listening to Customer Center Events

You can listen to Customer Center events in two ways: using a global listener, or using a local listener through the CustomerCenter composable options.

First, create a CustomerCenterListener implementation:

private fun createCustomerCenterListener(): CustomerCenterListener {
return object : CustomerCenterListener {
override fun onManagementOptionSelected(action: CustomerCenterManagementOption) {
when (action) {
CustomerCenterManagementOption.MissingPurchase -> {
// User selected missing purchase option
}
CustomerCenterManagementOption.Cancel -> {
// User selected cancel option
}
is CustomerCenterManagementOption.CustomUrl -> {
val uri: Uri = action.uri
// User selected a custom URL option
}
}
}

override fun onRestoreInitiated(resume: Resumable) {
performAuthentication { result ->
when (result) {
is Success -> resume().also {
println("Authentication complete, presenting restore flow")
}
is Failure -> resume(false).also {
println("Authentication failed, canceling restore flow")
presentErrorAlert()
}
}
}
}

override fun onRestoreStarted() {
// Restore purchases process started
}

override fun onRestoreCompleted(customerInfo: CustomerInfo) {
// Restore purchases completed successfully
}

override fun onRestoreFailed(error: PurchasesError) {
// Restore purchases failed
}

override fun onShowingManageSubscriptions() {
// Manage subscriptions screen is displayed
}

override fun onFeedbackSurveyCompleted(feedbackSurveyOptionId: String) {
// User completed a feedback survey
}
}
}

Then, you can use it in one of two ways:

  1. As a global listener that will be called for all Customer Center instances:
// Create and set the global listener
val customerInfoListener = createCustomerCenterListener()
Purchases.sharedInstance.customerCenterListener = customerInfoListener
  1. As a local listener through the CustomerCenter composable options:
val customerCenterListener = remember { createCustomerCenterListener() }

if (isCustomerCenterVisible) {
CustomerCenter(
modifier = Modifier.fillMaxSize(),
options = CustomerCenterOptions.Builder()
.setListener(customerCenterListener)
.build(),
) {
isCustomerCenterVisible = false
}
return
}

The following events are available:

  • onManagementOptionSelected: Called when a user selects a management option (missing purchase, cancel, or custom URL)
  • onRestoreInitiated: Called before the restore process begins. Call resume() to continue or resume(false) to cancel the restore.
  • onRestoreStarted: Called when the restore process begins
  • onRestoreCompleted: Called when the restore process completes successfully
  • onRestoreFailed: Called when the restore process fails
  • onShowingManageSubscriptions: Called when the manage subscriptions screen is shown
  • onFeedbackSurveyCompleted: Called when a user completes a feedback survey

If you need to gate the restore flow, implement onRestoreInitiated on either your local CustomerCenterOptions.Builder().setListener(...) listener or your global Purchases.sharedInstance.customerCenterListener. You do not need to set both. The restore will pause until your listener calls resume, which makes this useful for authentication or parental gates before continuing.

If you do set both a local listener and a global listener, the restore gate runs in two steps:

  1. The local CustomerCenterOptions listener is called first.
  2. If it calls resume() or resume(true), the global Purchases.sharedInstance.customerCenterListener is called next.

Restore only proceeds after both listeners resume with true. If either listener calls resume(false), the restore is cancelled before onRestoreStarted runs. In practice, that means the global listener has the final say if you implement both.

📘Availability

Restore interception in Customer Center is available on the native Android and iOS SDKs.

Custom Actions

📘Custom Actions support

The minimum supported version is Android SDK version 9.2.0.

Custom Actions allow you to add your own custom management options to the Customer Center. When a customer taps on a custom action, your app receives a callback with the custom action identifier, allowing you to execute your own code.

To handle custom actions, create a CustomerCenterListener with the onCustomActionSelected callback:

// Create a listener to handle custom actions
val customerCenterListener = object : CustomerCenterListener {
override fun onCustomActionSelected(actionIdentifier: String, purchaseIdentifier: String?) {
when (actionIdentifier) {
"contact_support" -> openSupportChat(purchaseIdentifier)
"delete_account" -> showAccountDeletionDialog()
"rate_app" -> openAppStoreRating()
}
}
}

// Display Customer Center with custom action handling
CustomerCenter(
modifier = Modifier.fillMaxSize(),
options = CustomerCenterOptions.Builder()
.setListener(customerCenterListener)
.build(),
) {
// Handle dismissal
}

Custom actions are configured in the RevenueCat dashboard under Customer Center settings, where you can:

  • Set a custom identifier for the action
  • Configure the display text and localization
  • Position the action within the management options

Setup promotional offers

Promotional Offers allow developers to apply custom pricing and trials to new customers and to existing and lapsed subscriptions. Unique promotional offers can be assigned to different paths and survey responses in the Customer Center, but first they must be setup in Google Play Console.

The Customer Center will automatically show offers based on specific user actions. By default we have defined it for cancellations but it can be modified to any of the defined paths. Refer to configuring Google Play Store promotional offers for detailed instructions.

Learn more about configuring the Customer Center in the configuration guide.