Install to Claude Code
npx -y skills add https://github.com/tamtom/gplay-cli-skills --skill gplay-submission-checksDescription
gplay submission checks
SKILL.md
---
name: gplay-submission-checks
description: Pre-submission validation for Google Play releases covering metadata, screenshots, bundle integrity, data safety, and policy compliance. Use when preparing a release to avoid rejections and catch issues before submitting.
---
# 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 login` or `GPLAY_SERVICE_ACCOUNT` env var).
- Package name known (`--package` or `GPLAY_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.
```bash
gplay validate \
--package com.example.app \
--bundle app-release.aab \
--track production \
--strict
```
- **`gplay preflight --file <app.aab>`** — offline AAB/APK compliance and
hygiene: manifest presence, bundle/dex size, native-lib coverage, debuggable
and testOnly flags, cleartext traffic, dangerous permissions, and a secret
scan (API keys / private keys). No API calls. Exit codes: 0 clean, 1 findings
at/above `--fail-on`.
```bash
gplay preflight --file app-release.aab --max-size 150M --fail-on warning
```
- **`gplay checks upload`** — Google Checks compliance analysis as a CI gate.
Use `--severity-threshold PRIORITY` to fail the pipeline on high-priority
failed checks before release.
```bash
gplay 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.
```bash
gplay 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
```bash
gplay validate bundle --file app-release.aab
```
Checks:
- File exists and is readable
- File has `.aab` extension
- Valid ZIP archive structure
- Contains required bundle components (manifest, resources, dex)
If using APK instead:
```bash
gplay validate bundle --file app-release.apk
```
### 2. Validate Store Listing Metadata
```bash
gplay 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:
```bash
gplay validate listing --dir ./metadata --locale en-US
```
For JSON format metadata:
```bash
gplay validate listing --dir ./metadata --format json
```
### 3. Validate Screenshots
```bash
gplay 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:
```bash
gplay validate screenshots --dir ./metadata --locale en-US
```
### 4. Verify Existing Listings on Play Store
Compare local metadata against what is live:
```bash
gplay sync diff-listings \
--package com.example.app \
--dir ./metadata
```
Check all configured locales:
```bash
EDIT_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.
```bash
gplay 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:
```bash
gplay tracks list --package com.example.app --output table
```
Get details for a specific track:
```bash
EDIT_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`:
```bash
EDIT_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:
```bash
gplay 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:
```bash
EDIT_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. As of 2025:
- New apps: must target API level 34 (Android 14) or higher
- App updates: must target API level 34 or higher
Check your `build.gradle` or `build.gradle.kts`:
```
android {
defaultConfig {
targetSdkVersion 34 // or targetSdk = 34
}
}
```
Builds targeting older API levels will be rejected by the Play Console.
### Permissions Declarations
Sensitive permissions require justification in the Play Console:
- `ACCESS_FINE_LOCATION` / `ACCESS_BACKGROUND_LOCATION`
- `READ_CONTACTS`, `READ_CALL_LOG`, `READ_SMS`
- `CAMERA`, `RECORD_AUDIO`
- `REQUEST_INSTALL_PACKAGES`
- `QUERY_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:
```bash
gplay 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:
```bash
EDIT_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:
```bash
gplay 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), and
`gplay publish track --strict` (preflight + publish) over hand-scripting.
- Always run `gplay validate` before attempting a release.
- Use `--dry-run` (or `publish track --strict`) as the final gate before real releases.
- `gplay deobfuscation upload` is edit-scoped: use `--edit` and `--apk-version`
(not `--version-code`), then commit the edit.
- Always confirm exact flags with `--help` before running commands.
- Use `--output table` for 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 validate` commands run locally and do not require API calls.
- `gplay release --dry-run` creates a real edit session but discards it after validation.
- `gplay edits validate` is the server-side equivalent, catching issues that local validation cannot.
- Always use `--help` to verify flags for the exact command.
- Use `--output table` for human-readable output; default is JSON.
