For personal Google Play developer accounts created after 13 November 2023

Get your 12 testers for Android, and security-check your app before Google reviews it

Google Play won't grant production access until 12 testers have been opted in to your closed test for 14 continuous days, and then it asks what those testers actually did. TestersWiz finds the testers and collects evidence that they installed and used your app. It also checks your APK for the leaked keys, risky settings and policy gaps that anyone who downloads it can find. Google alone decides production access.

You do not have to be accepted, and you do not have to finish a test. Even an application a developer turns down still counts.

  • Install-proof screenshot at opt-in, reviewed by a person
  • No cap on testers: recruit past 12 to cover drop-outs
  • Security findings mapped to OWASP MASVS controls
  • Your APK is never installed or run, and is deleted when the scan ends
  • No ratings, reviews or incentivized installs, ever

By Syed Qadri · Last reviewed

Google Play's 12 testers requirement, precisely

If you created a personal developer account after 13 November 2023, you can't publish to production until you have run a closed test with at least 12 testers opted in, continuously, for 14 days. The full breakdown of the 12 testers, 14 days rule takes each word apart; this is the short version.

What Google requires
WhoPersonal developer accounts created after 13 November 2023. Organization (D-U-N-S) accounts and older personal accounts are exempt. Play Console shows the account type in your account details.
WhereA closed testing track. Internal testing does not count.
How manyAt least 12 opted-in testers. It was 20 until December 2024, which is why older posts still say 20.
How long14 continuous days at 12 or more. Days don't add up across gaps.
What countsA tester who opted in through your track's opt-in link.
What doesn'tBeing on the email list or in the Google Group without opting in; a sideloaded APK; installs from an internal track.
ThenYou apply for production access from the Play Console Dashboard. Google says review usually takes seven days or less, but can take longer.

The engagement trap: why 12 opt-ins isn't the finish line

Meeting the count lets you apply; it doesn't get you approved. The production access application asks three sets of questions:

  1. 1. About your closed test

    How you recruited testers, how easy that was, how engaged they were, and a summary of their feedback.

  2. 2. About your app

    Its intended audience, the value it provides, and expected installs in its first year.

  3. 3. About your production readiness

    What you changed during the test, and how you decided the app was ready.

A developer who borrowed 12 inactive accounts has nothing true to write in the first or the third. That is the trap. How to answer the production access questions goes through each one.

What Google verifies

Google does not publish the signals it uses to judge engagement, and any page that lists them is guessing. The working assumption that holds up: Google runs the store, the track and the install, so it can see whether testers installed through Play and whether the app was used, and it has said it can refuse production access when testing looks insufficient. Plan for a test that would survive a person reading your answers.

The failures we see most

FailureWhy it failsFix
Tester accepted the Google Group invite but never opted inGroup membership is not an opt-inSend the opt-in link (Testing → Closed testing → your track → Testers), not the Group link
Tester installed an APK you sent themA sideload is not a Google Play installRemove it; install from the Play listing after opting in
Track not available in the tester's countryThe opt-in page loads, but the app is not available to themClosed testing → your track → Countries/regions: add them, or select all
Everyone joined on day 1 and went silentThe count is met, but there is nothing to report in section 1Collect feedback on a schedule, and ship at least one update from it
Count dipped to 11 on day 9 and nobody noticedContinuity is brokenRecruit 14–16; check the count daily, not on day 14

To check that your own test device installed from Google Play rather than a sideload:

adb shell pm list packages -i com.your.app
# package:com.your.app  installer=com.android.vending   <- installed from Google Play
# installer=null, or a file manager                      <- sideloaded

Step by step: from closed track to production access

Before day 0

  1. 1

    Confirm the requirement applies to you (account type and creation date). Don't spend two weeks on a test you don't need.

  2. 2

    Build the release you intend to ship: a signed AAB, the current target API level (API 36 for new apps and updates since 31 August 2026), isMinifyEnabled = true, and not debuggable.

  3. 3

    Security-check that build now. Your testers install this exact binary, and anything in it is public from the first download. The checklist is below.

  4. 4

    Create the closed track: Testing → Closed testing → create or edit a track → upload the AAB → release notes → roll out to the track. Closed releases are reviewed, so wait until the release is available to testers.

  5. 5

    Set up testers: an email list, or a Google Group (@googlegroups.com) people can join themselves. Set Countries/regions to include every tester.

  6. 6

    Copy the opt-in link: https://play.google.com/apps/testing/com.your.app.

Days 0–14

  1. 7

    Recruit 14–16 testers, not 12. On TestersWiz the listing keeps recruiting for the whole window, volunteers on a self-serve track get your Group and opt-in link straight away, each files an install-proof screenshot when they opt in, and you confirm each Gmail against your Play Console tester list before admitting them.

  2. 8

    Watch the count daily, and top up the moment it drops toward 12.

  3. 9

    Collect evidence as you go: screenshot check-ins (on TestersWiz, day 3), written feedback (from day 12), feedback through Google Play's testing feedback, and your own crash and ANR data in Android vitals.

  4. 10

    Ship at least one update from that feedback. A new build does not reset the 14-day count, and it gives you a concrete answer to "what did you change?".

Day 14 onwards

  1. 11

    Apply for production from the Dashboard. Answer with specifics: numbers, named fixes, quoted feedback. Answers that could describe any app tell Google nothing about yours.

  2. 12

    Keep testers opted in until access is granted. The review can take a week.

  3. 13

    Release with a staged rollout (for example 10% → 50% → 100%), and watch Android vitals between steps.

Security audit for your app: a MASVS checklist before closed testing

Why audit before the closed test, not after launch

  • An APK is public from the first install. Your testers download the same binary the world will. Hardcoded keys, backend URLs and debug flags are readable with free tools in minutes, so a key leaked on day 0 of testing is already compromised.
  • Some findings block the release, not just the risk: an outdated target API level; sensitive permissions such as QUERY_ALL_PACKAGES, background location, SMS and call log, exact alarms or all-files access, which need a Play Console declaration; and a Data Safety form that doesn't match the SDKs in your build.
  • Fixing after testing means re-testing. A new build doesn't reset Google's clock, but a fix that changes behaviour deserves the testers' 14 days too.

A note on the standard. OWASP MASVS v2 has eight control groups: STORAGE, CRYPTO, AUTH, NETWORK, PLATFORM, CODE, RESILIENCE and PRIVACY. The old L1/L2 levels were removed from MASVS in v2.0; how deep to test now lives in the MASTG testing profiles. Obfuscation and tamper detection belong to MASVS-RESILIENCE, not MASVS-CODE.

Setup: turn your bundle into something you can inspect

# App Bundle -> universal APK (debug-signed, which is fine for inspection)
bundletool build-apks --bundle=app-release.aab --output=app.apks --mode=universal
unzip -p app.apks universal.apk > app.apk

aapt2 dump badging app.apk | grep -E "package:|sdkVersion|targetSdkVersion"
apkanalyzer manifest debuggable app.apk          # must print: false
apkanalyzer manifest print app.apk > AndroidManifest.xml
jadx -d out/ app.apk                             # decompiled sources + resources

MASVS-STORAGE: insecure data storage

CheckHow to verifyFix
Tokens or personal data in plaintext SharedPreferences, files or SQLiteOn a debug build: adb shell run-as com.your.app ls shared_prefs databases files, then read the filesEncrypt with a Keystore-backed key (see MASVS-CRYPTO); keep session tokens in memory where you can
Secrets in logsadb logcat --pid=$(adb shell pidof -s com.your.app), filtered for token, bearer and passwordStrip logging from release builds, for example with a no-op logging tree or R8 -assumenosideeffects on Log
App data included in backupsandroid:allowBackup, android:fullBackupContent, and on Android 12+ android:dataExtractionRulesExclude credential and token files from cloud backup and device transfer
Sensitive files on shared storageSearch for getExternalStorage and MediaStore writes of private dataUse app-specific internal storage

Jetpack Security's EncryptedSharedPreferences was deprecated by Google in 2025. Existing code keeps working; for new code, use the Android Keystore directly (below) or Google's Tink library.

MASVS-CRYPTO: cryptography and key management

CheckHow to verifyFix
ECB mode by defaultCipher.getInstance("AES") resolves to AES/ECB/PKCS5Padding on AndroidAES/GCM/NoPadding with a Keystore key
Hardcoded keys and static IVsSecretKeySpec( with literal bytes; IvParameterSpec(ByteArray(16))Generate keys in the Keystore and let the cipher create the IV
Weak hashes for passwords or integrityMD5, SHA-1, DES, RC4Hash passwords on the server (Argon2 or bcrypt); SHA-256 or above for integrity
Predictable randomnessjava.util.Random or kotlin.random.Random used for tokensSecureRandom
Server secrets shipped in the appSearch the decompiled output for sk_live_, sk-, service_role, AKIARotate first, then move the call behind your own backend. No obfuscation protects a secret shipped to the client
A Keystore-backed AES-GCM key (Kotlin)
val kg = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
kg.init(
    KeyGenParameterSpec.Builder("session_key",
        KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
        .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
        .setKeySize(256)
        .build()
)
val cipher = Cipher.getInstance("AES/GCM/NoPadding").apply { init(Cipher.ENCRYPT_MODE, kg.generateKey()) }
val iv = cipher.iv  // generated by Keystore; store it with the ciphertext

MASVS-NETWORK: network communication

CheckHow to verifyFix
Cleartext HTTP allowedandroid:usesCleartextTraffic="true" in the manifest, or cleartextTrafficPermitted="true" in network_security_config.xml. Cleartext is blocked by default from targetSdk 28Remove both; use HTTPS everywhere
Release build trusts user-installed CAs<certificates src="user"/> outside <debug-overrides>. User CAs aren't trusted by default from targetSdk 24Keep user CAs in debug-overrides only
Broken TLS validationAn X509TrustManager with an empty checkServerTrusted, or a HostnameVerifier that returns trueDelete it and use the platform defaults
Dynamic confirmationProxy a release build through mitmproxy with its CA installed as a user certificateIf traffic decrypts, one of the rows above is wrong

Certificate pinning is optional depth for high-risk apps. Done badly, it bricks your app at the next certificate rotation. If you pin, pin the SPKI, include a backup pin, and set an expiry.

res/xml/network_security_config.xml
<network-security-config>
  <base-config cleartextTrafficPermitted="false" />
  <domain-config>
    <domain includeSubdomains="true">api.example.com</domain>
    <pin-set expiration="2027-06-30">
      <pin digest="SHA-256">CURRENT_SPKI_BASE64=</pin>
      <pin digest="SHA-256">BACKUP_SPKI_BASE64=</pin>
    </pin-set>
  </domain-config>
</network-security-config>
Get a server's SPKI pin
openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null \
 | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der \
 | openssl dgst -sha256 -binary | openssl enc -base64

MASVS-PLATFORM: intents, exported components, deep links and WebViews

CheckHow to verifyFix
Components other apps can openexported="true" in the merged manifest. From targetSdk 31, every component with an intent filter must declare exportedexported="false" unless it must be public; protect public ones with a signature permission
Internal screens reachable directlyadb shell am start -n com.your.app/.internal.AdminActivity should fail as not exportedAs above
Readable content providersadb shell content query --uri content://com.your.app.provider/usersexported="false", grantUriPermissions scoped to specific paths, parameterized queries
Intent redirectionCode that launches an Intent taken from another intent's extrasNever forward untrusted intents; build a new explicit intent
Mutable PendingIntentPendingIntent.get* without FLAG_IMMUTABLE (mutability must be declared from targetSdk 31)FLAG_IMMUTABLE unless mutation is genuinely needed
Deep links that act without checksadb shell am start -W -a android.intent.action.VIEW -d "yourapp://reset?token=x&next=https://evil.example" com.your.appValidate every parameter, allowlist redirect hosts, require sign-in before acting
App Links not verifiedadb shell pm get-app-links com.your.app (Android 12+)autoVerify="true" and a correct /.well-known/assetlinks.json
Unsafe WebViewaddJavascriptInterface, setAllowFileAccess(true), setAllowUniversalAccessFromFileURLs(true), or URLs loaded from intentsAllowlist origins, disable file access, expose no bridge to untrusted content
Over-broad FileProvider<root-path> or path="." in file_paths.xmlShare specific directories only

MASVS-CODE: code quality, dependencies and platform currency

CheckHow to verifyFix
Debuggable releaseapkanalyzer manifest debuggable app.apkNever set debuggable on a release build type
Outdated target APIaapt2 dump badging → targetSdkVersionMeet Google Play's current requirement
Known-vulnerable libraries./gradlew app:dependencies --configuration releaseRuntimeClasspath, then check versions against OSV or NVD (for example with OSV-Scanner on a Gradle lockfile)Upgrade, and remove libraries you don't use
Injection through local queriesrawQuery( or execSQL( built by string concatenationRoom, or bound parameters

MASVS-RESILIENCE: reverse engineering and tampering

CheckHow to verifyFix
Code not shrunk or obfuscatedClass names in the jadx output are your real package names instead of a.b.cEnable R8 for release builds (below). The Android Gradle plugin puts the mapping file in the AAB, so Play deobfuscates your crash reports
Tamper and device checks decided on the clientAn integrity check whose result only the app readsUse the Play Integrity API and verify the token on your server: appRecognitionVerdict == PLAY_RECOGNIZED, the device integrity labels and the licensing verdict. SafetyNet Attestation has been shut down

Obfuscation slows analysis. It does not hide a key.

app/build.gradle.kts
android {
    buildTypes {
        release {
            isMinifyEnabled = true
            isShrinkResources = true
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }
}

MASVS-PRIVACY: your Data Safety form

CheckHow to verifyFix
Undeclared data collectionList every data-collecting SDK in your build: analytics, ads, crash reporting, attributionMap each one to your Data Safety answers
Advertising ID added by a librarycom.google.android.gms.permission.AD_ID in the merged manifestDeclare it, or remove it with tools:node="remove" if you don't use it
Permissions you don't useThe merged manifest lists permissions a library addedtools:node="remove" (in Expo, blockedPermissions)

What an automated check covers, and what it can't

Covered from the APKNeeds dynamic or manual testing
Leaked keys, including inside React Native and Flutter bundlesAuthentication and session logic (MASVS-AUTH)
Manifest flags, exported components, cleartext and network-config settingsYour backend: Supabase RLS, Firebase rules, API authorization
Target API level, permissions that need a declarationRuntime behaviour, actual traffic, business logic
Data-collecting SDKs, vulnerable library versionsAnything a penetration tester does by attacking the running system

How TestersWiz fits: two tracks, one timeline

Before your closed test: the automated APK check

Upload your APK. It's analysed statically in an isolated environment with no internet access, never installed or run, and deleted when the scan finishes. It checks the Google Play launch checklist (target API, release build, permissions that may need a declaration, Data Safety), leaked keys, Supabase and Firebase setup, risky settings, data-collecting SDKs and known-vulnerable libraries. Your first check is free and tells you how many potential issues it found. The production-readiness report shows each one, with an OWASP MASVS control id where one applies, the fix, an AI prompt per finding, a Data Safety draft and a PDF.

During the 14 days: real testers, real evidence

Testers opt in through your Play link and file an install-proof screenshot, which a TestersWiz admin reviews. You confirm each Gmail against your own Play Console tester list. A day-3 screenshot check-in and a written feedback report (from day 12) give you material for the "about your closed test" and "production readiness" answers. Nobody is paid for installs, ratings or reviews.

What neither is: a penetration test, a certification, or a guarantee that your app or its backend is secure. For regulated apps, or anything handling payments or health data, commission a human assessment against the MASTG.

TestersWiz vs peer groups vs tester farms

TestersWizPeer groups (Reddit / Discord)Tester farms (bulk or bot accounts)
CostFree to test and to listFreePaid
Real-device evidenceInstall-proof screenshot at opt-in, reviewed by a person; a scheduled check-in; you verify each Gmail against Play ConsoleHonour system; you rarely know who actually opted inRarely offered; you can't inspect the accounts or devices
Staying opted in for 14 daysNo one can guarantee it. You recruit past 12 with no cap, see drop-outs, and trades are fate-linked with deadlines and strikesGoodwill only; drop-outs are invisible until your count fallsOften "guaranteed"; unverifiable, with no recourse beyond the vendor
Replacing drop-outsThe listing keeps recruiting for the whole windowPost again and hopeDepends on the vendor
Automated security checkStatic APK check, first one free, findings mapped to OWASP MASVSNoneNone
Feedback you can cite in the production applicationScheduled check-ins, a written report, in-app chatOccasional commentsUsually none, or generic
What's promised about approvalNothing: Google decidesNothingSome sell "guaranteed approval". No one can guarantee it
Risk to your developer accountReal people on their own Google accounts; no incentivized installs, ratings or reviewsLow, if the testers are realHighest: accounts you can't vouch for, and no real usage to describe when Google asks

Frequently asked questions

What is the Google Play 12 testers rule?

Personal Google Play developer accounts created after 13 November 2023 must run a closed test with at least 12 testers opted in for 14 continuous days before they can apply for production access. Organization accounts and older personal accounts are exempt. The number was 20 until Google lowered it to 12 in December 2024.

What happens if a tester drops out during the 14 days?

If your opted-in count falls below 12, the continuous 14-day period is broken, and you need 14 unbroken days at 12 or more before you apply. Recruit 14 to 16 testers so one or two drop-outs don't matter. On TestersWiz a listing keeps recruiting for its whole window with no cap on testers, so a replacement can join at any point.

How does Google verify if closed testers are real active users?

Google doesn't publish the signals it uses. What it does publish is the production access application, which asks how you recruited testers, how engaged they were and what feedback you received, and Google can refuse access if the testing looks insufficient. Plan for testers who genuinely install from Google Play, use the app and send feedback, because that is what you will have to describe.

Why do apps need a mobile app security audit before launching on the Play Store?

Everything inside an APK is readable by anyone who downloads it, including your closed testers, so a hardcoded secret key or a debuggable build is exposed from the first install. Issues Google checks for, such as an outdated target API level, undeclared sensitive permissions or a Data Safety form that doesn't match your SDKs, can also block your release. Fixing them before the closed test means the build your testers validate is the build you ship.

What does a mobile security audit check for?

A mobile app security assessment is usually organised around the OWASP MASVS categories: storage, cryptography, authentication, network, platform interaction, code, resilience and privacy. In practice that means leaked secrets, plaintext tokens, weak ciphers, cleartext traffic, exported components, unsafe deep links and WebViews, vulnerable libraries and missing R8 shrinking. An automated static check covers much of this from the APK; authentication, server-side logic and runtime behaviour need dynamic or manual testing.

Does TestersWiz guarantee Google Play production access?

No. Google alone decides who gets production access, so any service that guarantees approval is promising something it doesn't control. TestersWiz helps you meet the testing requirement with real testers and evidence you can cite in your application, and the security check helps you find problems before a reviewer or an attacker does.

Sources

Google's requirements change. Dates and limits on this page were checked on 27 September 2026; Google's own pages are the authority.

May we use analytics and ad measurement? Analytics (Vercel, and Ahrefs on our public pages) count page views without cookies. Ad measurement lets Google's tag on our public pages see which visits came from our Google ads, using a Google cookie. The site works the same either way. Cookie Policy · How Google uses data ·