Google Play Submission Checks
Use this skill to validate everything before submitting a release to Google Play, reducing rejections and failed edits.
Preconditions
- Auth configured (
gplay auth loginorGPLAY_SERVICE_ACCOUNTenv var). - Package name known (
--packageorGPLAY_PACKAGE). - AAB/APK built and signed.
- Service account has at least "Release Manager" permission.
Prefer the First-Class Commands
The CLI has canonical, purpose-built commands. Reach for these before hand-scripting individual validators:
-
gplay validate --package <pkg>— the canonical release-readiness report. Combines local artifact/metadata/screenshot/release-note checks with remote track and listing state and Console-only follow-up items. Use--bundle,--listings-dir,--screenshots-dir,--track, and--strict(treat warnings as failures) to scope it.bashgplay validate \ --package com.example.app \ --bundle app-release.aab \ --track production \ --strict -
gplay preflight --file <app.aab>— offline AAB/APK compliance and hygiene. Fully decodesAndroidManifest.xml(binary AXML for APKs, aapt2 protobuf for App Bundles) and runs nine scanners:manifest,permissions,native_libs,metadata,secrets,billing,privacy,policy,size. No API calls and no credentials. Exit codes: 0 clean, 1 findings at/above--fail-on.bashgplay preflight --file app-release.aab --max-size 150M --fail-on warning # Validate the store listing in the same pass gplay preflight --file app-release.aab --listings-dir ./metadata --fail-on error # Narrow the gate gplay preflight --file app-release.aab --only manifest,permissions,native_libsSee the
gplay-preflightskill for what each scanner catches, how to read the findings, and CI gating patterns. -
gplay checks upload— Google Checks compliance analysis as a CI gate. Use--severity-threshold PRIORITYto fail the pipeline on high-priority failed checks before release.bashgplay checks upload \ --account "$CHECKS_ACCOUNT" \ --app "$CHECKS_APP" \ --binary app-release.aab \ --binary-type ANDROID_AAB \ --severity-threshold PRIORITY -
gplay publish track --strict— preflight + publish in one step. Builds the readiness report, stops on blocking issues (and warnings with--strict), then runs the release workflow only if preflight passes.bashgplay publish track \ --package com.example.app \ --track production \ --bundle app-release.aab \ --release-notes @release-notes.json \ --strict
The detailed per-artifact checks below remain useful for narrowing down a failure or for CI steps that gate on one concern at a time.
Pre-submission Checklist
1. Validate Bundle Integrity
bashgplay validate bundle --file app-release.aab
Checks:
- File exists and is readable
- File has
.aabextension - Valid ZIP archive structure
- Contains required bundle components (manifest, resources, dex)
If using APK instead:
bashgplay validate bundle --file app-release.apk
2. Validate Store Listing Metadata
bashgplay validate listing --dir ./metadata
Checks:
- Title: max 30 characters
- Short description: max 80 characters
- Full description: max 4000 characters
- Required fields present
- Valid UTF-8 encoding
Validate a specific locale:
bashgplay validate listing --dir ./metadata --locale en-US
For JSON format metadata:
bashgplay validate listing --dir ./metadata --format json
3. Validate Screenshots
bashgplay validate screenshots --dir ./metadata
Checks:
- Minimum 2 screenshots per device type
- Maximum 8 screenshots per device type
- Valid image formats (PNG, JPEG)
- Files are readable
Validate for a specific locale:
bashgplay validate screenshots --dir ./metadata --locale en-US
4. Verify Existing Listings on Play Store
Compare local metadata against what is live:
bashgplay sync diff-listings \ --package com.example.app \ --dir ./metadata
Check all configured locales:
bashEDIT_ID=$(gplay edits create --package com.example.app | jq -r '.id') gplay listings list --package com.example.app --edit $EDIT_ID --output table
5. Data Safety Declaration
Ensure the data safety form is complete. Missing or inaccurate data safety declarations are a common rejection reason.
bashgplay data-safety update \ --package com.example.app \ --json @data-safety.json
6. Version Code Check
The version code must be strictly higher than all previous releases on every track. Check current track status:
bashgplay tracks list --package com.example.app --output table
Get details for a specific track:
bashEDIT_ID=$(gplay edits create --package com.example.app | jq -r '.id') gplay tracks get --package com.example.app --edit $EDIT_ID --track production --output table
7. Deobfuscation / Mapping File
Upload ProGuard/R8 mapping files so crash reports in Play Console are readable.
This command is edit-scoped (needs --edit) and the version flag is
--apk-version, not --version-code:
bashEDIT_ID=$(gplay edits create --package com.example.app | jq -r '.id') gplay deobfuscation upload \ --package com.example.app \ --edit $EDIT_ID \ --apk-version 42 \ --file mapping.txt gplay edits commit --package com.example.app --edit $EDIT_ID
Without mapping files, crash stack traces in Android Vitals will be obfuscated and unusable.
8. Dry Run the Release
The safest pre-submission check. Performs the full release pipeline without committing:
bashgplay release \ --package com.example.app \ --track production \ --bundle app-release.aab \ --release-notes @release-notes.json \ --dry-run
This will:
- Create an edit
- Upload the bundle
- Configure the track
- Validate the edit (catches API-level errors)
- Discard the edit without committing
If the dry run succeeds, the real release will succeed.
9. Edit Validation (Manual Sequence)
When using the manual edit workflow, always validate before committing:
bashEDIT_ID=$(gplay edits create --package com.example.app | jq -r '.id') # ... upload bundle, update tracks, etc. ... # Validate the edit (catches all server-side issues) gplay edits validate --package com.example.app --edit $EDIT_ID # Only commit if validation passes gplay edits commit --package com.example.app --edit $EDIT_ID
Content Policy Compliance
Target API Level
Google Play requires apps to target a recent Android API level, and raises the floor roughly every August to "latest release minus one". Both new apps and updates are affected; builds below the floor are rejected at upload.
Check the build without guessing at the current number:
bash# The policy scanner reports targetSdkVersion against Play's floor gplay preflight --file app-release.aab --only policy # Override the floor if Google's annual bump landed before a gplay release gplay preflight --file app-release.aab --only policy --min-target-sdk 36
Fix it in build.gradle / build.gradle.kts:
android { defaultConfig { targetSdk = 35 // set to Play's current floor or higher } }
Do not tell the user a specific required API level from memory — read it from
the policy scanner output or from Play's published requirement.
Permissions Declarations
Sensitive permissions require justification in the Play Console:
ACCESS_FINE_LOCATION/ACCESS_BACKGROUND_LOCATIONREAD_CONTACTS,READ_CALL_LOG,READ_SMSCAMERA,RECORD_AUDIOREQUEST_INSTALL_PACKAGESQUERY_ALL_PACKAGES
Remove any permissions your app does not actually need. Unused sensitive permissions are a top rejection reason.
Data Safety Form
All apps must have a complete data safety section. Common data types to declare:
- Personal info (name, email, phone)
- Location (approximate, precise)
- Financial info (purchase history)
- App activity (in-app search, other user-generated content)
- Device identifiers (advertising ID)
App Content Ratings
Ensure your content rating questionnaire is completed in Play Console. Missing ratings block distribution.
Screenshot Requirements by Device Type
| Device Type | Image Type | Min | Max | Min Resolution |
|---|---|---|---|---|
| Phone | phoneScreenshots | 2 | 8 | 320px (min side) |
| 7-inch Tablet | sevenInchScreenshots | 0 | 8 | 320px (min side) |
| 10-inch Tablet | tenInchScreenshots | 0 | 8 | 320px (min side) |
| Android TV | tvScreenshots | 0 | 8 | 1280x720 |
| Wear OS | wearScreenshots | 0 | 8 | 320px (min side) |
Additional image assets:
| Asset | Type | Required |
|---|---|---|
| Feature Graphic | featureGraphic | Yes (for featuring) |
| Promo Graphic | promoGraphic | No |
| Icon | icon | Set via Play Console |
| TV Banner | tvBanner | Required for TV apps |
Common Rejection Reasons and Fixes
1. "Version code already exists"
Cause: The version code in your bundle matches an existing release.
Fix: Increment versionCode in build.gradle and rebuild.
2. "APK/Bundle targets an SDK below the required level"
Cause: targetSdkVersion is too low.
Fix: Update targetSdkVersion to 34 or higher and rebuild.
3. "Data safety form incomplete"
Cause: The data safety declaration is missing or incomplete. Fix: Complete the data safety form in Play Console or update via CLI:
bashgplay data-safety update --package com.example.app --json @data-safety.json
4. "Screenshots missing for required device type"
Cause: Phone screenshots are required for all apps. Fix: Add at least 2 phone screenshots:
bashEDIT_ID=$(gplay edits create --package com.example.app | jq -r '.id') gplay images upload \ --package com.example.app \ --edit $EDIT_ID \ --locale en-US \ --type phoneScreenshots \ --file screenshot1.png
5. "Release notes missing for default locale"
Cause: No "What's New" text for the default language. Fix: Include release notes in the release command:
bashgplay release \ --package com.example.app \ --track production \ --bundle app.aab \ --release-notes '{"en-US": "Bug fixes and improvements"}'
6. "Signing key mismatch"
Cause: The bundle is signed with a different key than what Play Console expects. Fix: Use the same upload key configured in Play App Signing. Check your keystore configuration.
7. "Deobfuscation file too large"
Cause: Mapping file exceeds 300 MB limit. Fix: Strip unused mappings or compress the file.
Pre-launch Report
Google Play runs automated tests on your app before review (pre-launch report). Common issues surfaced:
- Crashes on launch: App crashes on one or more test devices
- Security vulnerabilities: Known CVEs in dependencies
- Accessibility issues: Missing content descriptions, small touch targets
- Performance warnings: Slow startup, excessive wake locks
Check pre-launch reports in Play Console after uploading to any track. Address critical issues before promoting to production.
Full Pre-submission Pipeline
bash#!/bin/bash # pre-submission-checks.sh PACKAGE="com.example.app" BUNDLE="app-release.aab" METADATA_DIR="./metadata" RELEASE_NOTES="release-notes.json" MAPPING="app/build/outputs/mapping/release/mapping.txt" echo "=== Step 1: Validate bundle ===" gplay validate bundle --file "$BUNDLE" --output table echo "=== Step 2: Validate listings ===" gplay validate listing --dir "$METADATA_DIR" --output table echo "=== Step 3: Validate screenshots ===" gplay validate screenshots --dir "$METADATA_DIR" --output table echo "=== Step 4: Diff listings against Play Store ===" gplay sync diff-listings --package "$PACKAGE" --dir "$METADATA_DIR" --output table echo "=== Step 5: Dry run release ===" gplay release \ --package "$PACKAGE" \ --track production \ --bundle "$BUNDLE" \ --release-notes "@$RELEASE_NOTES" \ --listings-dir "$METADATA_DIR" \ --screenshots-dir "$METADATA_DIR" \ --dry-run \ --output table echo "=== Step 6: Upload mapping file (edit-scoped) ===" EDIT_ID=$(gplay edits create --package "$PACKAGE" | jq -r '.id') gplay deobfuscation upload \ --package "$PACKAGE" \ --edit "$EDIT_ID" \ --apk-version 42 \ --file "$MAPPING" gplay edits commit --package "$PACKAGE" --edit "$EDIT_ID" echo "=== All checks passed. Ready to release. ==="
CI/CD Integration
Add these checks to your CI pipeline to catch issues before they reach Play Console:
yaml# GitHub Actions example - name: Offline preflight (compliance + secret scan) run: gplay preflight --file app/build/outputs/bundle/release/app-release.aab --fail-on error - name: Checks compliance gate run: | gplay checks upload \ --account ${{ secrets.CHECKS_ACCOUNT }} \ --app ${{ secrets.CHECKS_APP }} \ --binary app/build/outputs/bundle/release/app-release.aab \ --binary-type ANDROID_AAB \ --severity-threshold PRIORITY - name: Canonical readiness report run: | gplay validate \ --package ${{ secrets.PACKAGE_NAME }} \ --bundle app/build/outputs/bundle/release/app-release.aab \ --track internal \ --strict env: GPLAY_SERVICE_ACCOUNT: ${{ secrets.GPLAY_SERVICE_ACCOUNT_PATH }}
Agent Behavior
- Prefer the first-class commands:
gplay validate(readiness report),gplay preflight(offline),gplay checks upload(Checks gate), andgplay publish track --strict(preflight + publish) over hand-scripting. - Always run
gplay validatebefore attempting a release. - Use
--dry-run(orpublish track --strict) as the final gate before real releases. gplay deobfuscation uploadis edit-scoped: use--editand--apk-version(not--version-code), then commit the edit.- Always confirm exact flags with
--helpbefore running commands. - Use
--output tablefor human-readable validation output. - When multiple validation steps fail, report all failures together rather than stopping at the first one.
- Check version code conflicts by listing tracks before releasing.
- Remind the user about data safety declarations if they have not mentioned them.
Notes
gplay validatecommands run locally and do not require API calls.gplay release --dry-runcreates a real edit session but discards it after validation.gplay edits validateis the server-side equivalent, catching issues that local validation cannot.- Always use
--helpto verify flags for the exact command. - Use
--output tablefor human-readable output; default is JSON.

