How to Set Up Android Subscriptions with RevenueCat (The Actually Complete Guide)
I spent way too long getting subscriptions working in my Android app. Not because it’s conceptually hard, but because the guides out there…

How to Set Up Android Subscriptions with RevenueCat (The Actually Complete Guide)
I spent way too long getting subscriptions working in my Android app. Not because it’s conceptually hard, but because the guides out there skip steps, use outdated screenshots, or assume you already know where things are in the Google Play Console.
This is the guide I wish I had. We’re going from zero to a working subscription paywall in an Android app using RevenueCat. No backend needed. No iOS stuff. Just Android.
Here’s what the flow looks like when we’re done:
- User taps “Go Premium”
- A paywall appears (either RevenueCat’s pre-built one or your custom UI)
- User picks a plan and pays through Google Play
- RevenueCat tracks the subscription, handles renewals, grace periods, all of it
- Your app checks
isPremiumand unlocks features
Let’s go.
Part 1: Google Play Console (Creating Your Subscriptions)
Before RevenueCat can sell anything, you need actual products set up in Google Play.
Create Your Subscriptions
- Go to Google Play Console
- Select your app (or create one if you haven’t)
- In the left sidebar, go to Monetize > Products > Subscriptions
- Click Create subscription
- Fill in:
- Product ID: Something like
premium_monthly. This ID is permanent, so pick something you won't hate later. - Name: “Premium Monthly” (users see this)
-
Click Create
-
Now you need to add a base plan. Click Add base plan:
- Base plan ID:
monthly(or whatever makes sense) - Renewal type: Auto-renewing
- Billing period: 1 month
- Price: Set your price. Click Set price, pick your default country, and Google will auto-convert for other regions.
-
Click Activate on the base plan
-
Click Save on the subscription
-
Make sure the subscription status shows Active
Repeat for any other plans (yearly, weekly, whatever you need).
Important: You must have uploaded at least an APK or AAB to some testing track (even Internal Testing) before subscriptions will work. If you haven’t done that yet, go to Testing > Internal testing, create a release, and upload a signed build. It doesn’t need to be your final app, it just needs to exist.
Add License Test Accounts
This lets you test purchases without being charged real money.
- In Google Play Console, go to Settings > License testing (in the left sidebar, under the “All apps” level, not inside a specific app)
- Add the Gmail addresses of your test accounts
- Set the License response to
RESPOND_NORMALLY - Save
These accounts can now make test purchases. Subscriptions renew on an accelerated schedule during testing (a monthly sub renews every 5 minutes).
Part 2: Google Cloud Console (Service Account Setup)
RevenueCat needs a service account to talk to Google Play on your behalf. This part has a few steps, but each one is straightforward.
Create a Google Cloud Project (or Use an Existing One)
- Go to Google Cloud Console
- Click the project dropdown at the top of the page
- Click New Project
- Name it something like “MyApp Play Billing”
- Click Create
- Make sure the new project is selected in the dropdown
Enable the Required APIs
You need two APIs enabled. Missing either one will cause weird errors later.
- Go to APIs & Services > Library (or search “API Library” in the Cloud Console search bar)
- Search for Google Play Android Developer API
- Click it, then click Enable
- Go back to the API Library
- Search for Google Play Developer Reporting API
- Click it, then click Enable
Both. You need both. The first one handles purchases and subscriptions. The second one handles reporting data that RevenueCat uses for analytics and validation.
Create a Service Account
- Go to IAM & Admin > Service Accounts
- Click Create Service Account
- Fill in:
- Name: Something like
revenuecat-integration - Description: “Service account for RevenueCat subscription management”
-
Click Create and Continue
-
For the role, you can skip this step (we’ll set permissions in Play Console instead). Click Continue
-
Click Done
Generate the JSON Key
- Find your new service account in the list and click on it
- Go to the Keys tab
- Click Add Key > Create new key
- Select JSON
- Click Create
- A JSON file downloads. Keep this file safe. You’ll upload it to RevenueCat in a minute.
Part 3: Connect the Service Account to Google Play Console
This is where a lot of guides get it wrong. They tell you to go to “Setup > API access” in Google Play Console. That flow is outdated and inconsistent. Here’s what actually works:
Grant Permissions via Users and Permissions
- Go to Google Play Console
- Click Users and permissions in the left sidebar (at the account level, not inside an app)
- Click Invite new users
- In the email field, paste the service account email. You can find this in the JSON key file you downloaded (look for the
client_emailfield) or back in Google Cloud Console under your service account details. It looks something likerevenuecat-integration@your-project.iam.gserviceaccount.com. - Set the permissions:
- Under Account permissions, you can leave defaults
- Click the App permissions tab
- Click Add app and select your app
- Grant these permissions:
- ✅ View app information and download bulk reports
- ✅ View financial data, orders, and cancellation survey responses
- ✅ Manage orders and subscriptions
- ✅ Manage store presence
-
Click Invite user
-
Click Send invite
The Waiting Game
Here’s the thing nobody tells you: credentials take 24 to 48 hours to fully activate. During this time, RevenueCat might show errors when trying to validate your credentials.
The workaround: Go to your app in Google Play Console, navigate to Monetize > Products > Subscriptions, open any subscription, change something trivial in the description (add a period, whatever), and save it. This seems to kick the credential activation process. Some people report it starts working within a few hours after doing this.
Part 4: RevenueCat Dashboard Setup
Create a RevenueCat Project
- Go to RevenueCat Dashboard and sign up or log in
- Click Create new project
- Name it (your app name works fine)
Add Your Android App
- Inside your project, click Apps in the sidebar
- Click Add app (or the + New button)
- Select Google Play Store
- Fill in:
- App name: Your app’s name
- Package name: Your Android package name (e.g.,
com.yourcompany.yourapp). This must match exactly.
- Click Save
Upload Service Account Credentials
- In your app settings, find the Service credentials section
- Upload the JSON key file you downloaded from Google Cloud
- Click Save
The “Credentials need attention” Problem
After uploading, RevenueCat will try to validate your credentials. If you just set everything up, you’ll likely see a warning: “Credentials need attention” or “Could not validate credentials”.
Don’t panic. This almost always means one of three things:
- The credentials haven’t activated yet. Remember the 24–48 hour window from Part 3? This is that. Try the subscription description edit trick, then come back later.
- You haven’t uploaded an APK/AAB to any track. Google Play won’t validate service account credentials until there’s at least one build uploaded. Go upload something to Internal Testing.
- Missing API. Double-check that both the Google Play Android Developer API AND the Google Play Developer Reporting API are enabled in Google Cloud Console.
Once the credentials validate, you’ll see a green checkmark. Move on.
Create Products, Entitlements, Offerings, and Packages
This is RevenueCat’s way of organizing what you sell. Here’s the hierarchy:
- Products = mirrors of your Google Play subscriptions
- Entitlements = what the user “gets” (e.g., “premium access”)
- Offerings = a group of packages you show to the user
- Packages = individual options within an offering (monthly, yearly, etc.)
Step 1: Create Products
- Go to Products in the sidebar
- Click + New
- Select your app (the Google Play one)
- Enter the Product identifier. This must exactly match the Product ID from Google Play Console (e.g.,
premium_monthly). - Enter the Base plan ID (e.g.,
monthly). This must match what you set up in Play Console. - Click Add
Repeat for each subscription.
Step 2: Create an Entitlement
- Go to Entitlements in the sidebar
- Click + New
- Give it an identifier like
premium - Click Add
- Click into the new entitlement
- Click Attach and attach all the products that should grant this entitlement
Step 3: Create an Offering
- Go to Offerings in the sidebar
- There’s usually a “Default” offering already. Click into it.
- Add packages:
- Click + New under Packages
- Select a package type (Monthly, Annual, etc.) or use Custom
- Attach the corresponding product to each package
Get Your API Key
- Go to your app in RevenueCat (click the app name)
- Find the API keys section
- Copy the Public SDK key (starts with
goog_). This is safe to include in your app. It's not a secret.
Part 5: Android Code
Add Dependencies
In your app-level build.gradle.kts:
dependencies {
// RevenueCat SDK
implementation("com.revenuecat.purchases:purchases:9.19.2")
// RevenueCat pre-built paywall UI (optional, but saves a ton of time)
implementation("com.revenuecat.purchases:purchases-ui:9.19.2")
}
Sync your project.
Note: RevenueCat 9.x bundles Google Play Billing Library 7+, which is required by Google as of August 2025. You don’t need to add the billing library separately.
Initialize RevenueCat in Your Application Class
Create or update your Application class:
import android.app.Application
import com.revenuecat.purchases.LogLevel
import com.revenuecat.purchases.Purchases
import com.revenuecat.purchases.PurchasesConfiguration
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
Purchases.logLevel = LogLevel.DEBUG
Purchases.configure(
PurchasesConfiguration.Builder(
context = this,
apiKey = "goog_YourPublicKeyHere"
).build()
)
}
}
Register it in your AndroidManifest.xml:
<application android:name=".MyApp" ...>
Set Launch Mode
In your AndroidManifest.xml, ensure your Activity uses standard or singleTop launch mode. singleTask or singleInstance can break the billing flow.
<activity
android:name=".MainActivity"
android:launchMode="standard" />
Easy Paywall with PaywallDialog
The fastest way to get a paywall up and running. RevenueCat has pre-built paywall UI that you design in their dashboard:
@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
@Composable
fun PremiumScreen() {
var showPaywall by remember { mutableStateOf(false) }
Button(onClick = { showPaywall = true }) {
Text("Go Premium")
}
if (showPaywall) {
PaywallDialog(
PaywallDialogOptions.Builder()
.setDismissRequest { showPaywall = false }
.build()
)
}
}
A few things to note:
- The
@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)annotation is required. The paywall UI is still marked as experimental in RevenueCat 9.x. PaywallDialogOptions.Builder()is the current API. Some older guides referencePaywallOptions.Builder(), which is wrong.- The paywall automatically shows the offerings you configured in RevenueCat’s dashboard. You design the paywall in their dashboard, not in code.
Custom Paywall (Full Control)
If you want to build your own UI, you can fetch offerings and launch purchases manually:
import com.revenuecat.purchases.Purchases
import com.revenuecat.purchases.getOfferingsWith
import com.revenuecat.purchases.models.StoreTransaction
import com.revenuecat.purchases.purchaseWith
class SubscriptionViewModel : ViewModel() {
private val _offerings = MutableStateFlow<Offerings?>(null)
val offerings: StateFlow<Offerings?> = _offerings.asStateFlow()
private val _isPremium = MutableStateFlow(false)
val isPremium: StateFlow<Boolean> = _isPremium.asStateFlow()
fun loadOfferings() {
Purchases.sharedInstance.getOfferingsWith(
onError = { error ->
Log.e("Subscriptions", "Error fetching offerings: ${error.message}")
},
onSuccess = { offerings ->
_offerings.value = offerings
}
)
}
fun purchase(activity: Activity, packageToPurchase: Package) {
Purchases.sharedInstance.purchaseWith(
PurchaseParams.Builder(activity, packageToPurchase).build(),
onError = { error, userCancelled ->
if (!userCancelled) {
Log.e("Subscriptions", "Purchase error: ${error.message}")
}
},
onSuccess = { storeTransaction, customerInfo ->
if (customerInfo.entitlements["premium"]?.isActive == true) {
_isPremium.value = true
}
}
)
}
}
Then in your Composable:
@Composable
fun CustomPaywallScreen(viewModel: SubscriptionViewModel = viewModel()) {
val offerings by viewModel.offerings.collectAsStateWithLifecycle()
val activity = LocalContext.current as Activity
LaunchedEffect(Unit) {
viewModel.loadOfferings()
}
offerings?.current?.availablePackages?.let { packages ->
LazyColumn {
items(packages) { pkg ->
Card(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.clickable { viewModel.purchase(activity, pkg) }
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = pkg.product.title,
style = MaterialTheme.typography.titleMedium
)
Text(
text = pkg.product.price.formatted,
style = MaterialTheme.typography.bodyLarge
)
Text(
text = pkg.product.description,
style = MaterialTheme.typography.bodyMedium
)
}
}
}
}
}
}
Checking Premium Status
You’ll want to check this in various places to gate features:
fun checkPremiumStatus() {
Purchases.sharedInstance.getCustomerInfo(
callback = object : ReceiveCustomerInfoCallback {
override fun onReceived(customerInfo: CustomerInfo) {
val isPremium = customerInfo.entitlements["premium"]?.isActive == true
}
override fun onError(error: PurchasesError) {
// Handle error, maybe default to non-premium
}
}
)
}
Or as a suspend function (cleaner in ViewModels):
suspend fun isPremium(): Boolean {
return try {
val customerInfo = Purchases.sharedInstance.awaitCustomerInfo()
customerInfo.entitlements["premium"]?.isActive == true
} catch (e: Exception) {
false
}
}
Restore Purchases
Always give users a way to restore purchases. This is required by Google Play policy:
fun restorePurchases() {
Purchases.sharedInstance.restorePurchases(
callback = object : ReceiveCustomerInfoCallback {
override fun onReceived(customerInfo: CustomerInfo) {
val isPremium = customerInfo.entitlements["premium"]?.isActive == true
}
override fun onError(error: PurchasesError) {
// Show error to user
}
}
)
}
Part 6: Testing
Testing with License Testers
- Make sure the tester’s Gmail is added in Play Console > Settings > License testing (from Part 1)
- The tester must be opted into your Internal Testing track. Share the opt-in link from Testing > Internal testing > Testers tab
- The tester installs the app from the Play Store (or Internal App Sharing)
- When they hit the paywall, Google Play shows a test card instead of charging real money
- Test subscriptions renew on a compressed timeline:
- Weekly sub: renews every 5 minutes
- Monthly sub: renews every 5 minutes
- Yearly sub: renews every 30 minutes
- Subscriptions auto-cancel after 6 renewals
What to Test
- Purchasing each subscription tier
- Upgrading/downgrading between tiers
- Canceling and resubscribing
- Restoring purchases
- Checking premium status after purchase
- Checking premium status after the subscription expires
- What happens when the user is offline
Verifying in RevenueCat
After a test purchase, go to the RevenueCat dashboard:
- Click Customers in the sidebar
- Find your test user (search by app user ID or anonymous ID)
- You should see the transaction, the active entitlement, and subscription details
If the purchase shows up in Google Play but not in RevenueCat, your credentials are probably still propagating (see Part 3).
Common Problems and Fixes
“Credentials need attention” in RevenueCat
You just set up the service account. Wait 24–48 hours. Try editing a subscription description in Play Console to speed it up. Also verify both Google Cloud APIs are enabled.
PaywallDialog shows nothing or crashes
Make sure you have offerings configured in RevenueCat dashboard with at least one package. The PaywallDialog renders based on your dashboard configuration. If there are no offerings, there's nothing to show.
“This version of the app is not configured for billing”
The user (or you) is not using a build distributed through a Play Console track. Debug builds from Android Studio won’t work for purchases. You need to install via Internal Testing, Closed Testing, or production.
Purchase flow doesn’t appear or immediately dismisses
Check your Activity’s launchMode in the manifest. It must be standard or singleTop. The singleTask and singleInstance modes break the billing flow.
“Item already owned” error
The user already has an active subscription. Call restorePurchases() to sync the state, or check getCustomerInfo() to see what they already have.
Test purchases aren’t showing up in RevenueCat
- Verify the product IDs match exactly (case-sensitive) between Play Console and RevenueCat
- Verify the base plan IDs match
- Check that your service account credentials have validated (green checkmark)
- Make sure you’re using the correct API key (the
goog_one, not a secret key)
“BillingClient is not ready”
RevenueCat wasn’t initialized before you tried to make a purchase. Make sure Purchases.configure() runs in your Application.onCreate(), not in an Activity.
Google Play returns “Error: Service unavailable”
This happens on emulators without Google Play Services. Test on a physical device or an emulator image that includes the Play Store (use a “Google Play” system image, not “Google APIs”).
Official Docs and Resources
RevenueCat
- RevenueCat Docs (main)
- Android SDK Installation
- Displaying Paywalls
- API Keys / Authentication
- SDK Quickstart
- Products, Entitlements & Offerings
- RevenueCat Android SDK (GitHub)
- RevenueCat Community Forums
- Google Play Console
- Google Cloud Console
- Google Play Developer API
- Google Play Billing
- Play Console Users and Permissions
If this saved you time, I’m glad. The service account credential dance is the part that trips everyone up. Once that’s validated and green, the rest honestly just works. Happy shipping.
메타데이터
- post_id
- a6f17c8ba9cf
- slug
- how-to-set-up-android-subscriptions-with-revenuecat-the-actually-complete-guide-a6f17c8ba9cf
- url
- https://medium.com/@githukueliud/how-to-set-up-android-subscriptions-with-revenuecat-the-actually-complete-guide-a6f17c8ba9cf
- canonical_url
- https://medium.com/@githukueliud/how-to-set-up-android-subscriptions-with-revenuecat-the-actually-complete-guide-a6f17c8ba9cf
- author_url
- https://medium.com/@githukueliud
- status
- ok
- fetched_at
- 2026-06-09 15:37:30