Google Play closed testing for Capacitor and Ionic apps
Capacitor doesn't change Google's rule. If your Play Console account is a personal account created after November 13, 2023, you must run a closed test with at least 12 testers opted in for 14 continuous days before you can apply for production access (Play Console Help).
Capacitor's own docs say its apps are "normal native apps at the end of the day", deployed like any other Android app (Capacitor docs). The Capacitor-specific parts are the ones that bite: the target SDK is tied to your Capacitor major version, the android/ folder doesn't update itself, and the native project ships whatever web bundle you last synced. For the rule and every Play Console screen, start with the Google Play closed testing guide.
The android/ folder is your project
npx cap add android creates a full Android Studio project in android/ (Capacitor docs). From then on it belongs to you. Updating the npm packages doesn't rewrite it: the Capacitor 8 upgrade guide lists edits to variables.gradle, the Android Gradle plugin and the Gradle wrapper, and offers npx cap migrate to apply them (Capacitor docs).
So when you read "Capacitor 8 targets API 36", check the file. An app created on Capacitor 6 and upgraded through npm alone can still say 34.
Step 1: Capacitor 8 for API 36
Since August 31, 2026, new apps and app updates must target Android 16 (API level 36) or higher. Wear OS and Android Automotive OS apps need API 35, Android TV and Android XR apps API 34 (Play Console Help).
Capacitor ties the target SDK to its major version (Capacitor docs):
| Capacitor Android | Target SDK |
|---|---|
| 8.x | 36 |
| 7.x | 35 |
| 6.x | 34 |
It also says it "does not support custom target SDK versions". Raising the number on Capacitor 7 may build, but you're on your own. Upgrade to Capacitor 8 instead. The latest release is 8.6.0, published October 28, 2026 (npm, checked on November 9, 2026).
The value lives in android/variables.gradle. The 8.6.0 template has (Capacitor template):
minSdkVersion = 24
compileSdkVersion = 36
targetSdkVersion = 36Capacitor 8 needs Node.js 22 or later and Android Studio Otter 2025.2.1 or newer. The upgrade guide moves the Android Gradle plugin to 8.13.0 and the Gradle wrapper to 8.14.3 (Capacitor docs). The target API 36 guide lists what to retest after the bump.
Step 2: Set your application ID before the first upload
The template's applicationId is com.getcapacitor.app. Change it at the top of android/app/build.gradle (Capacitor docs), and keep appId in your Capacitor config the same.
Do it now. Google says once you upload an artifact, the package name is fixed and cannot be changed (Play Console Help). Set the app name in strings.xml (app_name) too: it's what testers see on their home screen.
Step 3: Build the web app, then sync
Every release starts the same way (Capacitor docs):
npm run build # or ng build, whatever your web build is
npx cap syncnpx cap sync copies your built web bundle into the native projects and updates native dependencies. Skip it and the AAB contains your previous web build. Testers then report bugs you already fixed.
Step 4: Build a signed AAB
From the command line. npx cap build android builds the native project into a signed AAB or APK. It takes --keystorepath, --keystorepass, --keystorealias, --keystorealiaspass and --androidreleasetype (AAB or APK) (Capacitor docs). The same settings can go under android.buildOptions in your Capacitor config, where releaseType defaults to "AAB" and signingType to "jarsigner" (Capacitor docs). Leave signingType on jarsigner for an AAB: Google says you cannot use apksigner to sign an app bundle (Android Developers). Keep passwords out of a committed config file: pass them in CI as flags.
From Android Studio. npx cap open android, then Build > Generate Signed Bundle/APK, choose Android App Bundle, and create or select your upload keystore (Android Developers).
Back up the keystore and both passwords. With Play App Signing, Google can reset a lost upload key, but an app signing key you manage yourself can't be reset (Play Console Help). If you use Google Sign-In or Firebase, register the fingerprint of Google's app signing key too, not only your upload key, or sign-in fails for testers who installed from Google Play (same source).
Step 5: Raise versionCode every release
The template sets versionCode 1 and versionName "1.0" in android/app/build.gradle (Capacitor template). Google Play needs a higher versionCode for each upload, up to 2,100,000,000 (Play Console Help). You'll ship fixes during the 14 days: bump it each time, and bump versionName so testers can tell builds apart.
Step 6: Permissions
The template's AndroidManifest.xml already declares INTERNET (Capacitor template). For the rest, Capacitor's docs say "the plugin you choose to use will ask you to set a permission", which you add to android/app/src/main/AndroidManifest.xml (Capacitor docs).
Native libraries can also merge permissions you never typed. Google's example: the Google Mobile Ads SDK declares com.google.android.gms.permission.AD_ID, which ends up in your app's manifest (Play Console Help). Open the merged manifest in Android Studio before you upload.
Google evaluates high-risk permissions such as SMS or Call Log on test tracks too. An undeclared one on an active closed release blocks you from publishing changes (Play Console Help).
Step 7: Remove development settings from the config
Three Capacitor config options are meant for development (Capacitor docs):
server.urlloads an external URL in the WebView for live reload. Capacitor: "This is not intended for use in production." Left in, your testers' app points at your laptop.server.cleartextallows HTTP traffic for live-reload servers. Same warning.android.webContentsDebuggingEnableddefaults tofalseand is turned on automatically during development. Don't force it totruein the build you upload.
Step 8: Minification and the release build
The template ships with minifyEnabled false in the release build type (Capacitor template). If you turn R8 on, test the shrunk build: plug-ins that use reflection may need keep rules. Note that the template references proguard-android.txt. Google says AGP 9.0 dropped support for that file in favor of proguard-android-optimize.txt (Android Developers). The 8.6.0 template still uses AGP 8.13.0, so this matters when you move to AGP 9.
Test the release build on a real phone. Capacitor needs a WebView based on Chrome 60 or later, and notes that the System WebView doesn't update itself on emulators (Capacitor docs).
Step 9: Release on the closed testing track
In Play Console, go to Test and release > Testing > Closed testing, then Manage track. Create a release, upload the .aab, add testers in the Testers tab, pick countries, and send the changes for review.
The opt-in link only shows once the app status is Published, and the first time it can take several hours to work (Play Console Help). If it's missing, see where to find the opt-in link. Keep your 12 closed testers off the internal track: Google says a user who opts into your internal test can't receive your closed test.
How long it really takes
- Capacitor 7 to 8 upgrade: an hour or two with
npx cap migrateon a small app, longer with many plug-ins. - First signed AAB: about an hour if Android Studio already works.
- First closed release: Google can take up to seven days, longer in exceptional cases, for some accounts (Play Console Help).
- The test: 14 continuous days. Production access review: usually seven days or less (Play Console Help).
Plan three to four weeks from the first closed upload to production.
Frequently asked questions
Do Capacitor and Ionic apps need 12 testers for 14 days?
Yes, if your Play Console account is a personal account created after November 13, 2023. A WebView app follows the same rule as any native app: a closed test with at least 12 testers opted in for 14 continuous days.
Which Capacitor version targets API level 36?
Capacitor 8. Capacitor's own matrix ties the target SDK to the major version: 8.x targets 36, 7.x targets 35, 6.x targets 34. Capacitor says it doesn't support custom target SDK versions.
Where is targetSdkVersion in a Capacitor project?
In android/variables.gradle. The Capacitor 8 template sets minSdkVersion 24, compileSdkVersion 36 and targetSdkVersion 36.
How do I build a signed AAB with Capacitor?
Run npx cap build android with your keystore options, or set them under android.buildOptions in the Capacitor config, whose default release type is AAB. You can also use Build > Generate Signed Bundle/APK in Android Studio.
My closed test build shows an old version of my web app. Why?
The native project only contains the web bundle you last copied into it. Run your web build, then npx cap sync, before every release build.
Sources
- support.google.com/googleplay/android-developer/answer/14151465
- support.google.com/googleplay/android-developer/answer/11926878
- support.google.com/googleplay/android-developer/answer/9845334
- support.google.com/googleplay/android-developer/answer/9842756
- support.google.com/googleplay/android-developer/answer/17367361
- support.google.com/googleplay/android-developer/answer/9214102
- support.google.com/googleplay/android-developer/answer/6048248
- support.google.com/googleplay/android-developer/answer/9859751
- developer.android.com/studio/publish/app-signing
- developer.android.com/build/building-cmdline
- developer.android.com/build/shrink-code
- capacitorjs.com/docs/android/setting-target-sdk
- capacitorjs.com/docs/updating/8-0
- capacitorjs.com/docs/android
- capacitorjs.com/docs/android/configuration
- capacitorjs.com/docs/basics/workflow
- capacitorjs.com/docs/cli/commands/build
- capacitorjs.com/docs/config
- npmjs.com/package/@capacitor/android
- github.com/ionic-team/capacitor/tree/8.6.0/android-template