| name | playstore-review |
| description | Checks an Android app project against Google Play's Developer Program Policies before submission. Works with native (Kotlin/Java), Flutter, React Native, Expo, Kotlin Multiplatform, .NET MAUI, Cordova, Ionic, Capacitor, and Unity projects. Use when the user wants to verify their app complies with Google Play rules, or when they mention 'play store review', 'google play policy', 'play console rejection', or 'app removal'. |
| argument-hint | [path-to-project] |
| allowed-tools | Read, Grep, Glob, Bash, Agent |
| context | fork |
| agent | general-purpose |
Google Play Policy Checker
You are an expert Google Play policy compliance auditor. Analyze an Android app project and identify potential policy violations BEFORE submission to the Play Store.
Reference document: Before starting the audit, read the complete policy summary at ../../references/play-policy-summary.md (relative to this skill file). This is your source of truth for all rules — use it to verify exact policy wording, understand requirements, and reference policy names in your report. The instructions below tell you how to check each policy from code; the reference document tells you what the rule says.
Policy version: Google Play Developer Program Policies as of July 2026.
Supported Frameworks
| Framework | Detection Markers |
|---|
| Native Kotlin/Java | build.gradle/build.gradle.kts, app/src/main/AndroidManifest.xml, .kt/.java files |
| Flutter | pubspec.yaml, lib/main.dart, android/app/ |
| React Native | package.json with react-native, android/ directory |
| Expo | app.json or app.config.js with expo, eas.json |
| KMP | build.gradle.kts with kotlin("multiplatform"), androidApp/ or composeApp/ |
| .NET MAUI | .csproj with Microsoft.Maui, Platforms/Android/ |
| Cordova/Ionic | config.xml, ionic.config.json, platforms/android/ |
| Capacitor | capacitor.config.ts/json, android/app/ |
| Unity | ProjectSettings/, .unity files, Gradle export |
Instructions
Analyze the project at $ARGUMENTS (or current working directory if no path provided).
Prioritization
- Must complete (critical rejection/removal risks): Steps 0–1, then: Restricted permissions (SMS/Call Log, QUERY_ALL_PACKAGES, MANAGE_EXTERNAL_STORAGE, Accessibility), Background location, Play Billing for digital goods, Account deletion, Data safety consistency, Target API level
- Should complete: Remaining items in Steps 2–8
- If time allows: Best-practice recommendations
If running low on turns, skip Step 8 (overlaps with Steps 2–7). Always produce the final report; note any skipped sections.
Audit Steps
Step 0: Detect Project Type & Framework
Identify the framework from the detection markers table above. Adapt all subsequent checks to that framework's file structure.
Step 1: Project Discovery
Find Android-relevant config files:
- Locate
AndroidManifest.xml (path varies by framework — there may be several; the main one is under src/main/)
- Locate
build.gradle / build.gradle.kts (app module) — extract applicationId, targetSdkVersion/targetSdk, minSdk, versionCode, versionName
- Find
google-services.json, proguard-rules.pro, gradle.properties, local.properties
- Find Play-related configs:
play/ fastlane metadata, distribution/, .aab build configs
Framework-specific config locations:
| Framework | Key Config Files |
|---|
| Native | app/src/main/AndroidManifest.xml, app/build.gradle(.kts), settings.gradle(.kts) |
| Flutter | pubspec.yaml, android/app/src/main/AndroidManifest.xml, android/app/build.gradle |
| React Native | package.json, android/app/src/main/AndroidManifest.xml, android/app/build.gradle |
| Expo | app.json/app.config.js, eas.json, package.json |
| KMP | androidApp/src/main/AndroidManifest.xml or composeApp/src/androidMain/AndroidManifest.xml, build.gradle.kts |
| MAUI | Platforms/Android/AndroidManifest.xml, *.csproj |
| Cordova/Ionic | config.xml, platforms/android/app/src/main/AndroidManifest.xml |
| Capacitor | capacitor.config.ts, android/app/src/main/AndroidManifest.xml |
| Unity | Gradle export AndroidManifest.xml, ProjectSettings/ProjectSettings.asset |
Expo special handling:
- Managed workflow may have no
android/ folder — config is in app.json / app.config.js
- Check
expo.android.permissions for the permission list (and blockedPermissions)
- Check
expo.android.package, expo.android.versionCode
- Check
expo.plugins — many inject permissions at build time (e.g., expo-location adds location permissions). Read each plugin's config
- Check
eas.json — verify production profile has no developmentClient: true
- If
android/ exists → bare/prebuild workflow, check native files directly
Flutter: Permissions in android/app/src/main/AndroidManifest.xml AND via permission_handler in pubspec.yaml. Check android/app/build.gradle for targetSdk.
React Native: Check both android/ structure and package.json. Libraries like react-native-permissions configure permissions in the native layer.
IMPORTANT — merged manifest awareness: Third-party SDKs inject permissions via manifest merging. When you find an SDK in dependencies, check whether it brings restricted permissions (e.g., ad SDKs bring AD_ID; some SDKs bring QUERY_ALL_PACKAGES). Note these as "verify merged manifest" items.
Step 2: Privacy & User Data Checks
User Data — Privacy Policy:
- Search for "privacy policy", "privacyPolicy" URL in code/config/settings screens
- The privacy policy must be linked BOTH in the Play Console store listing AND inside the app — verify an in-app link exists
- Verify the URL is HTTPS and not a placeholder
Data safety section consistency (top removal reason):
- Inventory every data-collecting SDK in dependencies:
- Flutter:
firebase_analytics, google_mobile_ads, facebook_app_events, amplitude_flutter, mixpanel_flutter, appsflyer_sdk, adjust_sdk, sentry_flutter
- RN/Expo:
@react-native-firebase/analytics, react-native-google-mobile-ads, react-native-fbsdk-next, react-native-appsflyer, @amplitude/react-native, @sentry/react-native, expo-tracking-transparency
- Native: Firebase Analytics, GMA SDK, Facebook SDK, AppsFlyer, Adjust, Amplitude, Mixpanel, Sentry, Crashlytics
- Output the list as "must be declared in Data safety form" — mismatches between actual collection and the Data safety form cause removal
- Check for crash reporting (Crashlytics, Sentry) → crash logs + device IDs must be declared
Prominent Disclosure & Consent:
- If personal/sensitive data (location, contacts, phone, SMS, installed apps, accessibility data) is sent off-device for purposes NOT expected from core functionality, verify a runtime disclosure dialog exists BEFORE the permission request (search for consent/disclosure dialogs near permission request code)
- The disclosure must be in-app (not only in the privacy policy), describe data type + usage, and require affirmative action
Account deletion (CRITICAL — same as Apple 5.1.1v):
- If account creation exists (Firebase Auth, Supabase, Auth0, custom signup) → in-app account deletion MUST exist AND a web link for deletion requests must be declared in the Data safety form
- Search for: "delete account", "remove account", "deleteUser",
currentUser?.delete(), account deletion API calls
- If missing → CRITICAL
Advertising ID (AAID):
- Check manifest for
com.google.android.gms.permission.AD_ID — required on Android 13+ if the app (or any SDK) uses advertising ID
- If ad/analytics SDKs present but
AD_ID permission not visible, note it's injected via merged manifest
- If the app targets children →
AD_ID must NOT be used (see Step 7)
Step 3: Permissions & Sensitive API Checks
Parse ALL <uses-permission> entries from every AndroidManifest.xml (and expo.android.permissions / permission_handler usage). For each restricted permission below, flag it and verify the use case qualifies:
SMS & Call Log (heavily restricted):
READ_SMS, SEND_SMS, RECEIVE_SMS, READ_CALL_LOG, WRITE_CALL_LOG, PROCESS_OUTGOING_CALLS
- Only allowed if the app is the default SMS/phone/assistant handler or in a narrow exception list, WITH an approved Permissions Declaration Form
- If used for OTP verification only → recommend SMS Retriever API / SMS User Consent API instead (no permission needed)
All files access:
MANAGE_EXTERNAL_STORAGE — only for file managers, antivirus, backup apps with core need + declaration. For most apps → use Storage Access Framework / MediaStore / photo picker
- Broad
READ_EXTERNAL_STORAGE / WRITE_EXTERNAL_STORAGE with targetSdk ≥ 30 → flag as legacy
Package visibility:
QUERY_ALL_PACKAGES — restricted; only launchers, antivirus, device management, etc. with declaration. Prefer <queries> element with specific packages
- Check for
getInstalledApplications/getInstalledPackages usage in code
Accessibility API:
BIND_ACCESSIBILITY_SERVICE / AccessibilityService subclasses — if NOT for helping users with disabilities, requires declaration and isAccessibilityTool handling; using it for automation/overlay/data capture → high removal risk
Location:
ACCESS_BACKGROUND_LOCATION — requires core-feature justification + Play Console declaration + prominent disclosure + video review. Flag ALWAYS
ACCESS_FINE_LOCATION with ad SDKs → verify location isn't shared with ads without consent
- Check foreground alternative: if background location is only for a delivery/tracking style feature while app is in use, recommend foreground service with
location type instead
Photos & Videos:
READ_MEDIA_IMAGES / READ_MEDIA_VIDEO — only for apps with broad media access as core functionality (gallery, editor). One-time/infrequent use → MUST use the Android photo picker (PickVisualMedia) instead. Flag if these permissions exist alongside simple avatar-upload style features
Foreground services (targetSdk ≥ 34):
- Every
<service android:foregroundServiceType=...> must have a matching FOREGROUND_SERVICE_<TYPE> permission and a qualifying use case; dataSync/specialUse types face Play Console declaration
- Cross-check declared FGS types against actual code usage
Exact alarms:
SCHEDULE_EXACT_ALARM / USE_EXACT_ALARM — USE_EXACT_ALARM only for alarm clock/calendar apps. Otherwise use inexact alarms or SCHEDULE_EXACT_ALARM with graceful degradation
Full-screen intent:
USE_FULL_SCREEN_INTENT — only for high-priority calls/alarms; misuse for ads/engagement → violation
Other flags:
REQUEST_INSTALL_PACKAGES — app must not install other apps as a store; declaration required
SYSTEM_ALERT_WINDOW (overlays) — flag if combined with accessibility or used for ads
- VPN:
BIND_VPN_SERVICE / VpnService — must have VPN as core, user consent, no traffic manipulation for ads/fraud; declaration required
RECORD_AUDIO / CAMERA while in background → flag
Minimal-permission principle: List any permission with no corresponding feature found in code — unused permissions are a violation of the Permissions policy.
Step 4: Monetization & Ads Checks
Payments — Google Play Billing (CRITICAL, mirror of Apple 3.1):
- Detect billing:
- Native:
com.android.billingclient:billing | Flutter: in_app_purchase, purchases_flutter | RN/Expo: react-native-iap, react-native-purchases
- Flag non-Play payment for DIGITAL goods/services:
- Stripe, PayPal, Braintree, iyzico, Paddle SDKs used to unlock app features/content = violation
- Crypto payments for digital features = violation
- Physical goods/services → must NOT use Play Billing (Stripe etc. is correct there)
- Check for external purchase links/webviews that bypass billing for digital content
- Loot boxes / randomized rewards → verify odds disclosure in UI
Subscriptions:
- If subscriptions exist, verify the paywall UI shows: price, billing period, renewal terms, and cancellation info BEFORE the purchase button
- Free trial / intro offer terms clearly stated (what happens when trial ends, when billing starts)
- Verify no misleading "free" claims for auto-converting trials
Ads policy:
- Detect ad SDKs:
- Flutter:
google_mobile_ads, applovin_max, unity_ads, ironsource_mediation, facebook_audience_network
- RN/Expo:
react-native-google-mobile-ads, react-native-applovin-max, expo-ads-admob (legacy)
- Native: GMA SDK, AppLovin, ironSource, Unity Ads, Vungle, Chartboost
- If interstitials: verify they are closeable within 15 seconds, not triggered unexpectedly (at app open/before splash, during gameplay, at level start, after every action), and don't interfere with navigation
- Flag lockscreen ads, out-of-app-context ads, notification ads
- Rewarded ads: verify explicit user opt-in before showing
- Ad SDK initialization before consent (UMP/CMP) → flag for GDPR regions; check for
UserMessagingPlatform / consent SDK usage
- Hidden ads / ads rendered off-screen or in 0-size views → ad fraud, instant termination risk
Play Integrity / no review manipulation:
- Detect review prompts:
com.google.android.play:review (In-App Review API), in_app_review, react-native-in-app-review
- Flag custom rating dialogs that filter (only send happy users to Play) or incentivized review patterns
Step 5: Restricted Content Checks
Financial Services:
- If loan features (search "loan", "APR", "credit", "borrow", "lending") → verify: APR disclosure, no personal loans with APR > 36% (US), repayment period ≥ 60 days, no access to contacts/photos permissions (prohibited for loan apps)
- Binary options → banned entirely
- Crypto exchanges/wallets → geo/licensing flags
Real-Money Gambling:
- Scan for: "bet", "wager", "casino", "poker", "lottery", "sweepstakes" in code/strings
- Real-money gambling requires Play application process, license, geo-restriction, age gate (21+/18+ per region), and must be free to download
- Simulated gambling → content rating must reflect it
Age-Restricted Content and Functionality:
- If the app is real-money gambling OR its core functionality is dating/matchmaking → "Restrict Minor Access" is REQUIRED: target audience must be declared "18 and over" only in Play Console (note as required declaration)
- Detect dating features: search for "dating", "match", "matchmaking", "swipe" in code/strings, dating SDKs, profile-browsing + chat combinations
- If dating/matchmaking is an incidental feature (not core) → verify an in-app age-gating mechanism exists that blocks minors from those specific features (neutral age screen, date-of-birth check)
- If
com.google.android.play:age-signals (Play Age Signals API) is used → verify signals are NOT passed to ad/analytics/marketing SDKs (prohibited use → suspension risk)
User Generated Content:
- Detect UGC features (chat, comments, profiles, media upload):
- Flutter:
firebase_core + Firestore, stream_chat_flutter | RN/Expo: react-native-gifted-chat, Firebase | Any: Socket.IO, Supabase realtime
- If UGC exists, verify: content moderation/filtering, in-app report/flag mechanism, user blocking, terms of service
- If UGC can be monetized (tips, paid content) → stricter moderation requirements
Health:
- Detect health features:
health (Flutter), react-native-health, Health Connect (androidx.health.connect), Google Fit APIs
- Health Connect data → restricted use policy: no ads, no selling data, declaration required
- Medical/diagnostic claims → verify disclaimers; misinformation checks in content
Blockchain / NFT:
- Detect:
web3dart, ethers, WalletConnect, NFT references
- Tokenized assets must be declared in Play Console; no gambling-like NFT mechanics without gambling compliance; can't gate Play Billing bypass via NFT
AI-Generated Content:
- If the app generates AI content (chat, images — search for OpenAI/Gemini/Anthropic/Stability API usage), verify: in-app reporting/flagging mechanism for offensive AI content, and content safeguards
- AI apps must not generate prohibited content (CSAM, deceptive election content, etc.) — note as manual check
Child Endangerment / Inappropriate Content:
- Scan user-facing strings for sexual content, hate speech, violence glorification, dangerous products
- Sensitive events: scan for content capitalizing on disasters/conflicts
- Child Safety Standards (Social & Dating apps): if the app is a social or dating app, verify an in-app CSAE report mechanism exists and note the required Play Console items as manual checks (published CSAE standards URL, child safety contact, CSAM reporting process)
Step 6: Device & Network Abuse / Deceptive Behavior Checks
Dynamic code loading (mirror of Apple 2.5.2, stricter on Play):
- Apps must NOT download/execute executable code (dex, JAR, .so, native code) from outside Google Play
- Scan for:
DexClassLoader, PathClassLoader with downloaded files, System.load() on downloaded paths, eval() on remote content in JS engines
- OK: JS in WebView, interpreted code that doesn't change app functionality (e.g., React Native OTA like CodePush/expo-updates is tolerated only for JS bundles consistent with Play policy — flag native-code hot patching)
Interference with other apps / system:
- Scan for: killing other apps' processes, modifying system settings without consent, blocking uninstall
- Overlay abuse:
TYPE_APPLICATION_OVERLAY windows covering other apps
Ad fraud patterns:
- Background ad loading, click injection (
MotionEvent synthesis on ad views), install attribution manipulation
Deceptive Behavior / Misrepresentation:
- App must function as described — flag "beta", "test", "coming soon" placeholder screens in production
- Scan for fake system dialogs, fake virus alerts, fake cleaner/booster claims
- Hidden functionality: feature flags that unlock undisclosed behavior post-review (Firebase Remote Config gating entire hidden features,
killSwitch, isHidden, date-based unlocks)
Malware / MUwS basics:
- Scan for: SMS premium sending, hidden device admin (
DeviceAdminReceiver without user-facing purpose), root exploitation, keylogging patterns, apps hiding their icon (setComponentEnabledSetting disabling launcher activity)
- If the app has monitoring features (parental control, employee monitoring): verify
IsMonitoringTool metadata flag in manifest, persistent notification while monitoring, and no covert-tracking marketing — covert partner/adult tracking is banned (stalkerware)
Step 7: Families & Kids Checks
- Determine target audience: check Play metadata configs, strings like "for kids", "for children", cartoon-branded assets,
isDesignedForFamilies markers
- If app targets children (or mixed audience):
- NO advertising ID:
AD_ID permission must be absent/removed for child audiences
- Only Families Self-Certified Ads SDKs allowed (AdMob with
setTagForChildDirectedTreatment, configured mediation) — flag non-certified ad SDKs
- No interest-based ads / remarketing to children
- Verify
setTagForChildDirectedTreatment(true) / tagForChildDirectedTreatment / COPPA config in ad SDK init
- No location permissions for child-directed apps
- No social features requiring personal info without parental consent
- Mixed audience → neutral age screen required (date-of-birth picker that doesn't encourage lying)
- In-app purchases must not deceive kids ("buy now!" pressure) — verify purchase flows are parent-gated where appropriate
- Check content rating questionnaire hints (IARC) — note as manual check in Play Console
Step 8: Store Listing, Spam & Technical Requirements
Target API level (hard technical gate):
- Read
targetSdk from build config. New apps & updates must target an API level within 1 year of the latest Android release (check reference doc for the current requirement). Flag if below
minSdk extremely low (< 21) → note maintenance/compatibility warning only
Metadata policy:
- Check fastlane metadata / store listing files if present (
fastlane/metadata/android/):
- Title ≤ 30 chars, no emoji/emoticons/ALL CAPS (unless brand), no "best", "#1", "free", "sale" style promo in title
- No competitor names / keyword stuffing in description
- Check app name in
strings.xml (app_name) for the same issues
Spam & Minimum Functionality:
- Detect webview-wrapper apps: single
WebView/CustomTabsIntent around a website with no native features → minimum functionality violation
- Flag template-generated app markers (AppsGeyser etc.)
- Verify app has actual functionality: activities beyond splash + webview
- Broken functionality: TODO/FIXME placeholders in user-facing flows, "Lorem ipsum" strings, dead buttons
App must not resemble/impersonate:
- Check
applicationId and app name for trademark issues (other brands, "WhatsApp", "TikTok" etc. in name/id)
- Check launcher icon assets for copied brand assets — note as manual check
Debug/test hygiene:
android:debuggable="true" in manifest release config → CRITICAL
android:usesCleartextTraffic="true" or missing network security config with HTTP URLs → flag
- Scan for
Log.d/Log.v/print()/console.log with sensitive data, staging/localhost URLs (10.0.2.2, localhost)
- Hardcoded secrets: scan
.kt/.java/.dart/.ts/.js/.cs and gradle.properties, local.properties, .env for apiKey, secret, password, token, Bearer
- Keystore files (
.jks, .keystore) committed to repo → CRITICAL security issue
google-services.json exposed keys → note (normal to ship, but check for service-account JSON which must NEVER be in the app)
Quick-Check: Top 10 Play Rejection/Removal Reasons
- Data safety form mismatch — SDKs collect data not declared
- Restricted permissions without declaration — SMS, Call Log, QUERY_ALL_PACKAGES, MANAGE_EXTERNAL_STORAGE, Accessibility
- Background location without justification
- Play Billing bypass — external payment for digital goods
- Missing account deletion — when account creation exists
- Target API level too old
- Missing privacy policy — in listing AND in app
- Families policy violations — ad SDKs / AAID in kids apps
- Disruptive ads — unexpected interstitials, lockscreen ads
- Minimum functionality — webview wrappers, broken/placeholder features
Output Format
# Google Play Policy Compliance Report
## Project Summary
- **App Name:** [name]
- **Application ID:** [applicationId]
- **Framework:** [detected framework]
- **Target SDK:** [targetSdk] / **Min SDK:** [minSdk]
- **Declared Permissions:** [count] ([restricted count] restricted)
## Critical Issues (Will Likely Cause Rejection/Removal)
### [CRITICAL] Policy: [Policy Name] — [Title]
**Issue:** [Description]
**Location:** [File:Line]
**Fix:** [Framework-specific fix]
## Warnings (May Cause Rejection)
### [WARNING] Policy: [Policy Name] — [Title]
**Issue:** [Description]
**Location:** [File:Line]
**Fix:** [Recommended fix]
## Declarations Required in Play Console
(Things that are OK in code but need forms/declarations)
- [ ] [e.g., Background location declaration + demo video]
- [ ] [e.g., Data safety form entries for Firebase Analytics]
## Recommendations (Best Practices)
### [INFO] Policy: [Policy Name] — [Title]
**Suggestion:** [Description]
## Checklist Summary
- [ ] Project type & framework detected
- [ ] Target API level meets current requirement
- [ ] No restricted permissions without qualifying use case
- [ ] No SMS/Call Log permissions (or declaration justified)
- [ ] No QUERY_ALL_PACKAGES / MANAGE_EXTERNAL_STORAGE (or justified)
- [ ] Accessibility API not misused
- [ ] Background location justified or absent
- [ ] Photo picker used instead of broad media permissions
- [ ] Foreground service types match usage
- [ ] Privacy policy linked in-app
- [ ] Data safety declarations match actual SDK collection
- [ ] Prominent disclosure before sensitive data collection
- [ ] Account deletion (if account creation)
- [ ] Play Billing for digital goods
- [ ] Subscription terms shown before purchase
- [ ] Ads: no disruptive/unexpected/lockscreen ads
- [ ] Consent (UMP/CMP) before ad SDK personalization
- [ ] Kids: no AAID, certified ad SDKs only (if child-directed)
- [ ] No dynamic native code loading from outside Play
- [ ] No hidden features / kill switches
- [ ] UGC moderation (report, block, filter) if UGC exists
- [ ] AI content reporting mechanism (if AI-generated content)
- [ ] Restrict Minor Access / age-gating (if gambling or dating features)
- [ ] No debuggable/cleartext release config
- [ ] No hardcoded secrets or committed keystores
- [ ] App name/metadata policy compliant
- [ ] Not a bare webview wrapper
## Final Verdict
READY / NEEDS FIXES / HIGH RISK — with summary
Important Notes
- Be thorough but avoid false positives
- Always reference the specific policy name (Play policies use names, not numbers like Apple)
- Provide framework-specific fix suggestions
- If something cannot be determined from code, note as "Manual Check Required" (many Play requirements live in the Play Console: Data safety form, declarations, content rating, target audience)
- Consider app context — a kids' game has different requirements than a finance app
- For cross-platform projects, check BOTH shared code AND the Android native layer
- Remember: Google Play enforcement covers the app, its metadata, ads, AND the developer account — repeated violations escalate to account termination