What it is and why it matters
You send the app to review, you wait, and it comes back. Sign in with Apple is missing, or the account can't be deleted, or the sentence explaining why you ask for the camera is too vague. Every round costs you days, and often the reason was already written in your files.
Greenlight is a terminal program that does that check before you. It reads the code, the configuration files and, if you give it one, the already built app. Then it compares them with Apple's review rules and Google Play's policies. Every problem has a severity level and cites the rule it comes from. The basic check asks for no account, uploads nothing and doesn't use the network. It's made by Revyl, a company that does app testing, and the code is open on GitHub under the MIT license: it's free to use.
It's for people who publish on their own, without a team rereading Apple's rules at every release. One thing to say right away: it's a list of things to look at, not an approval stamp. It reads the files, it doesn't use the app. Section 6 covers what it can't see.
1. What it checks
The main command is called preflight, like the check before take-off. It runs five checks together, which the documentation calls scanners:
- metadata: name, version, bundle ID format (the app's identifier), icon, privacy policy link and the sentences that explain why you ask for a permission. It reads them in Info.plist or, for Expo apps, in app.json.
- codescan: 24 rules over Swift, Objective-C, React Native and Expo code. For example secret keys written in the code, Google login without Sign in with Apple, accounts you can create but not delete.
- privacy: is the privacy manifest Apple asks for (PrivacyInfo.xcprivacy) there, and is it complete? And if you use tracking SDKs, is there the ATT pop-up asking for permission to track?
- playscan: Android projects only. Google Play's rules: the Android API level to target and its deadlines, the permissions that need a declaration form, foreground services, the Play Billing version for payments.
- ipa: the already built iPhone app, the .ipa file. It checks the Info.plist keys, the launch screen, the icons, the app size and the privacy manifests of the bundled frameworks. It only runs if you pass it the file.
If the same folder holds both the iOS and the Android side, as in a Flutter or React Native app, it checks both in a single run.
2. Install it and run the first check
You install it from the terminal. On a Mac, with Homebrew, the program that installs other programs from the terminal. If you have Go instead, the language Greenlight is written in, use the second line.
brew install revylai/tap/greenlight go install github.com/RevylAI/greenlight/cmd/greenlight@latest
Then go into the project's main folder and run the check. The dot means “this folder”. It takes less than a second.
greenlight preflight .
If you've already exported the app for the App Store, add the .ipa file: that way it also checks the built app, not just the sources. For Android it's the same with --apk or --aab, the file you upload to Play. Put the path to your file in place of the example.
greenlight preflight . --ipa build.ipa greenlight preflight . --aab app-release.aab
3. How to read the result
Every problem found comes with four things: the severity level, the Apple or Google rule it comes from, the file where it was found and a suggestion on how to fix it. There are four levels:
- CRITICAL: rejection, or a failed install, is near-certain. Fix it before you submit.
- HIGH: a published deadline, a required declaration that's missing or something that breaks while the app runs.
- WARN: the reviewer will probably notice it and ask you for an explanation.
- INFO: best practice. It blocks nothing.
At the bottom there's the verdict: NOT READY if at least one CRITICAL is left, NEEDS REVIEW if some HIGH are left, GREENLIT when neither is left. GREENLIT means the check on the files passed, not that Apple will approve you.
4. Have Claude Code use it
Greenlight also comes as a Claude Code plugin. The plugin isn't the program: it's a skill, a sheet of instructions that tells Claude how to run the check, read the results, fix the code and run it again. Inside Claude Code, type:
/plugin marketplace add RevylAI/greenlight /plugin install greenlight
The plugin doesn't install the program by itself: do that first, as in step 2. Then open Claude Code in the project folder and paste:
Run greenlight preflight and fix everything until it passes. Start with the CRITICAL findings, then the HIGH ones. After each round of fixes, run the check again. If a finding looks like a false alarm to you, don't touch the code: stop and explain why.
I put the HIGH findings in on purpose. The plugin's instructions treat the job as done when no CRITICAL is left. The HIGH ones stay, though, and among them are exactly the missing Sign in with Apple and the account that can't be deleted.
When a finding isn't clear to you, have it explained before you touch anything:
Explain this Greenlight finding in plain words: [paste the line]. Tell me which Apple or Google rule it cites, which file it found it in and what's written there. Then tell me whether you think it's a real problem or a false alarm, and how I can check it myself.
And once you've worked out it's a false alarm:
This Greenlight finding is a false alarm: [paste the line]. If it comes from the code check (codescan), create or update .greenlight.yml in the main folder: lower that rule's severity or exclude only the file or folder needed, without turning off other checks. Add a comment next to it with the reason. If it comes from another check, change nothing and tell me.
5. False alarms and automatic checks
The .greenlight.yml file
It goes in the project's main folder and tunes the code check, including when it runs inside preflight. For each rule you can change the severity (info, warn or critical) or turn it off, and you can exclude folders, files or paths.
rules:
hardcoded-ipv4:
severity: info
platform-reference:
enabled: false
ignore:
- vendor
- "*.generated.ts"For a single line there's a comment you put on that line or the one above: // greenlight:ignore followed by the rule name. Without the name it silences every rule on that line. Better to write it, so the other checks stay on.
let host = "10.1.2.3" // greenlight:ignore hardcoded-ipv4
The check on every release
With --exit-code the command ends with an error if it finds a CRITICAL or a HIGH, or if one of the checks crashed: that way a half-done check never counts as a pass. Put it in your CI, the automatic checks that run on every push, GitHub Actions for example: a release with a serious problem stops on its own.
greenlight preflight . --exit-code
6. What it can't see
Greenlight reads text, it never opens the app. If the code has a “Delete account” button wired to nothing, it sees the word, the rule passes, and Apple rejects you anyway when it taps it.
Then there are false alarms. The clearest case is issue number 30 on their GitHub: in apps with no advertising at all, the Google ads rule fires because it finds “ads” inside ordinary words like loadSdk or downloads. It gives a CRITICAL without naming the file and suggests adding the ATT pop-up, which in an app that doesn't track is exactly the wrong thing. Before fixing, always look at what's really in your code.
And the code it reads is only Swift, Objective-C, React Native and Expo. Our app is built with Flutter: it doesn't read Dart code, so a Google login without Apple written in Dart goes unnoticed. It does read Info.plist, the privacy manifest, the Android manifest, the Gradle files and the built app. On Flutter, always pass it the built files, and test login and account deletion by hand.
Two optional commands aren't offline: verify tries some flows on a cloud phone and needs a Revyl account; scan --app-id checks the listing on App Store Connect and needs a login there. This guide doesn't use them.
Common mistakes
- Taking GREENLIT for an approval. It means nothing serious is left in the files, not that the app works.
- Fixing a false alarm. Before adding the ATT pop-up or changing code, look at what it really found and where.
- Checking only the sources. The permissions libraries add only show up in the built file: pass it the .ipa, .apk or .aab too.
- Trusting the green light on a Flutter app. It doesn't read Dart: you test login and account deletion yourself, on the phone.
Checklist
- Greenlight installed, on the latest version
- greenlight preflight . run in the project's main folder
- Check repeated with the built file: .ipa, .apk or .aab
- Zero CRITICAL and zero HIGH, or each one explained
- Every false alarm checked by hand and recorded in .greenlight.yml or with greenlight:ignore
- greenlight preflight . --exit-code in the CI
- Account deletion, restoring purchases and Sign in with Apple tested on the real app
Frequently asked questions
Does Greenlight send my code anywhere?
No. preflight and the other checks run on your computer, with no account and no network. Only verify and scan go online, and you only run them if you want to.
If it passes, will Apple approve it?
Not necessarily. Greenlight checks the files, while Apple tries certain flows by hand. It removes the mistakes you can see in the text; the rest you test yourself on the real app.
Do I need Claude Code to use it?
No. It's a terminal program and works on its own. The plugin is for when you want Claude to run the check, fix and run it again.