greenlight
Know before you submit. Pre-submission compliance scanner for the Apple App Store and Google Play.
Greenlight reads your app (source code, privacy manifests, Android manifests and Gradle builds, IPA binaries, App Store Connect metadata) and checks it against Apple's Review Guidelines and Google Play's Developer Program Policies. Every finding cites the rule it comes from. No account, no uploads, no network. A full preflight on a mid-size project finishes in single-digit milliseconds.
A static scan can only prove a flow exists. greenlight verify proves it works: it runs your account-deletion, restore-purchases, and Sign in with Apple flows on a cloud device and fails the build if any of them dead-ends. That tier is powered by Revyl and needs a free account. Everything else on this page runs offline. See greenlight verify.
Install
# Homebrew (macOS)
brew install revylai/tap/greenlight
# Go
go install github.com/RevylAI/greenlight/cmd/greenlight@latest
# Build from source
git clone https://github.com/RevylAI/greenlight.git
cd greenlight && make build
# Binary at: build/greenlight
Quick start
# Everything, one command, zero uploads
greenlight preflight /path/to/your/project
# Include an IPA for binary analysis
greenlight preflight . --ipa build.ipa
# Gate CI on it
greenlight preflight . --exit-code
Severity
Four levels. The top two fail a CI gate; the bottom two are advisory.
| Level | Meaning |
|---|---|
| CRITICAL | Rejection or install failure is near-certain. Fix before you submit. |
| HIGH | A published deadline, a required declaration, or a check that fails at runtime. |
| WARN | Likely to draw reviewer attention or an information request. |
| INFO | Best practice. |
--exit-code trips on CRITICAL and HIGH, and on a scanner that crashed, so an incomplete scan never reports as a pass.
Commands
greenlight preflight [path]
Runs every applicable scanner in parallel. Android and iOS projects in one repo are both picked up, so a cross-platform app is checked against both stores in a single pass.
greenlight preflight . # scan current directory
greenlight preflight ./my-app --ipa build.ipa # with binary inspection
greenlight preflight . --format json # JSON for CI
greenlight preflight . --format sarif --output greenlight.sarif
greenlight preflight . --exit-code # non-zero on CRITICAL/HIGH
| Scanner | Checks |
|---|---|
| metadata | app.json / Info.plist: name, version, bundle ID format, icon, privacy policy URL, purpose strings |
| codescan | 24 rules over Swift, Objective-C, React Native, and Expo source |
| privacy | PrivacyInfo.xcprivacy completeness, Required Reason APIs, tracking SDKs vs ATT |
| playscan | Google Play policy, target API deadline, restricted permissions, foreground service types, Play Billing version (Android projects only) |
| ipa | Binary: Info.plist keys, launch storyboard, icons, app size, framework privacy manifests |
Adding --verify extends the same command into the runtime tier, so one invocation covers static and runtime:
greenlight preflight . --verify --build-name "My App" \
--var [email protected] --var password=secret --exit-code
--verify accepts the same targeting flags as the standalone command: --artifact, --build-name, --device-model, --os-version, --var.
greenlight codescan [path]
greenlight codescan /path/to/project
greenlight codescan . --config path/to/.greenlight.yml
24 rules, roughly 60 patterns, over Swift, Objective-C, React Native, and Expo.
CRITICAL:
- Private API usage (§2.5.1)
- Hardcoded secrets and API keys (§1.6)
- External payment for digital goods (§3.1.1)
- Dynamic code execution (§2.5.2)
- Cryptocurrency mining (§3.1.5)
- UIWebView, a removed API and a hard rejection (§2.5.1)
HIGH:
- Missing Sign in with Apple alongside social login (§4.8)
- Missing Restore Purchases with IAP (§3.1.1)
- Missing ATT with ad or tracking SDKs (§5.1.2)
- Account creation with no deletion path (§5.1.1)
- A crypto exchange or on-ramp SDK, which usually needs licensing or a legal opinion (§3.1.5(b))
WARN:
- Crypto wallet, which requires an Organization account (§3.1.5(b)), plus exchange signals in copy and references to exchange brands
- Insecure HTTP URLs (§1.6)
- Vague Info.plist purpose strings, and missing required privacy keys (§5.1.1)
- Placeholder content left in strings (§2.1)
- References to competing platforms (§2.3)
- Hardcoded IPv4 addresses (§2.5)
- WebView-only app pattern (§4.2)
- Expo config problems (§2.1)
INFO: debug logging left in production code (§2.1), and no encryption export-compliance declaration.
Rules that describe a project-level fact, such as "no account deletion anywhere", report once for the whole project rather than once per file that triggers them.
greenlight playscan [path]
greenlight playscan /path/to/project
greenlight playscan --apk app-release.apk # built artifact: merged manifest
greenlight playscan --aab app-release.aab # app bundle
greenlight playscan . --format json
greenlight playscan . --exit-code
Checks an Android app against Google Play's Developer Program Policies and its published distribution deadlines. Every finding links the policy page it comes from.
Deadlines:
- Target API level. New apps and updates must target API 36 from August 31, 2026. Apps below API 35 already lose distribution to new users on newer devices. CRITICAL / HIGH. Play runs a separate schedule for Wear OS, Android TV, Automotive, and XR, so an app declaring one of those form factors gets a WARN naming its track instead of a blocking finding on the phone schedule.
- Play Billing Library. v7 and below lose support on August 31, 2026, and there is no direct v7 to v9 upgrade path. Versions reached through a variable or a version catalog
version.refare resolved. HIGH
Restricted permissions, each of which needs an approved use case or a declaration form:
- SMS and Call Log, including the July 2026 change that drops phone-call account verification as a permitted
READ_CALL_LOGuse MANAGE_EXTERNAL_STORAGE(All files access)QUERY_ALL_PACKAGES,REQUEST_INSTALL_PACKAGESACCESS_BACKGROUND_LOCATION, which needs a declaration and a demo video- Broad photo and video access over the system Photo Picker (API 33+)
- Accessibility Service, VPN service, and device admin, which are declared as a component's
android:permissionrather than a `` - Overlays, usage stats
- Contacts, ahead of the 2026 Contact Permissions policy
Manifest and build:
- Foreground services missing the base
FOREGROUND_SERVICEpermission, or a declared type missing itsFOREGROUND_SERVICE_*permission. Both throw atstartForeground(). CRITICAL specialUseforeground services, which need a Console justificationandroid:exportedmissing on components with an intent filter (API 31+), which makes the package fail to install. CRITICALandroid:debuggable="true". CRITICALandroid:usesCleartextTraffic="true"- An ads SDK shipped without
com.google.android.gms.permission.AD_ID, which silently returns a zeroed advertising ID - Account creation without the required in-app and web deletion paths
--apk and --aab read the merged manifest, so they see permissions contributed by library manifests that a source scan structurally cannot. Every manifest and permission check above runs against a built artifact, plus the native code checks below.
The three checks that read the Gradle model (Play Billing version, ads-SDK detection, auth-SDK detection) cannot run on an archive, because a built artifact does not carry one. The scan reports that gap as a finding rather than staying silent, so a clean artifact scan is never mistaken for a clean scan of everything. Source and artifact are complementary; preflight accepts both at once:
greenlight preflight . --aab app-release.aab
Native code checks:
- 16 KB page size. Google Play requires apps targeting Android 15+ to support 16 KB memory pages. Greenlight checks ELF
LOADsegment alignment onarm64-v8alibraries, 16 KB zip alignment of uncompressed libraries, andGNU_RELROpresence. CRITICAL / HIGH - 64-bit requirement. Every 32-bit ABI must ship with its 64-bit counterpart, so
armeabi-v7awithoutarm64-v8a, or