App Store

    Why did Apple reject my app for Guideline 2.3.1 hidden features?

    App Store Connect Resolution Center in 2026 showing a Guideline 2.3.1 rejection for hidden, dormant, or undocumented features, with the Notes for Review field highlighted below the build metadata row

    A developer submits a build to App Store Connect, the App Review email arrives within a day, and the only line that matters reads 'Guideline 2.3.1 Performance Accurate Metadata.' No screenshot. No timestamp on which screen tripped the reviewer. The wording 'hidden, dormant, or undocumented features' lands without context, and the reader is left guessing whether the trigger was a code-push SDK, a debug menu, or a feature flag that hid one tab on the home screen.

    Short answer

    Guideline 2.3.1 is the part of Apple's App Review Guidelines that bans hidden, dormant, or undocumented features and requires that all new functionality be described with specificity in the Notes for Review section of App Store Connect. Apple's own examples include hidden switches that route to gambling content, debug menus shipped to production, and remote update mechanisms that swap binary behavior after approval. A short, honest rewrite of Notes for Review and a clean removal of the flagged behavior resolves most cases.

    What you should know

    • The rule covers three states, not one. Apple groups hidden, dormant, and undocumented features together; a feature behind a remote flag counts even when the toggle is off at review time.
    • Notes for Review is the documented exit. Apple's wording singles out that field by name; the reviewer reads it before opening the binary.
    • Generic Notes are explicitly rejected. The Guidelines state that generic descriptions count as no description; 'various improvements' fails the floor.
    • Code-push, OTA bundles, and JavaScript hot updates are the high-frequency triggers. Multiple GitHub issues, including microsoft/code-push #841, document rejection under 2.3.1 tied to remote update SDKs.
    • iOS antivirus and malware scanner claims are an Apple-listed example of misleading marketing. The guideline text cites them directly, which is unusual for App Review.
    • Repeat 2.3.1 violations carry the developer-account penalty. Subsection (b) names removal from the Apple Developer Program as a possible outcome.
    • The fix is rarely a technical rebuild. Most 2.3.1 rejections clear with a rewritten Notes for Review entry, a debug menu strip, and a fresh build under an incremented CFBundleVersion.

    What does Apple mean by 'hidden features' under Guideline 2.3.1?

    The text of Guideline 2.3.1 reads, in the first subsection, that an app must not include 'any hidden, dormant, or undocumented features' and that 'your app's functionality should be clear to end users and App Review.' Three categories sit inside that sentence and each carries a different operational definition.

    A hidden feature is one the reviewer cannot reach from the default UI path. A debug menu reachable only by a long press on the version string is hidden. A dormant feature is one the binary contains but the runtime does not expose; an unfinished payment flow controlled by a server flag set to false is dormant. An undocumented feature is one present in both binary and UI but absent from the App Store description and from the Notes for Review field; an in-app purchase tier visible only to logged-in users on a Wednesday is undocumented in practice.

    The discussion thread Section 2.3.1 of the App Store Review Guidelines on the Apple Developer Forums shows that Apple has applied this rule for years to feature flags that hide age-rated content, to silent SDK behavior, and to a class of remote-control loops that change app behavior after the build clears review. The reviewer reads the binary in its shipped state; the surface visible at review time is the surface evaluated.

    Which features actually trigger a 2.3.1 rejection in practice?

    Four families show up repeatedly in rejection threads, vendor postmortems, and GitHub issues tagged with the guideline.

    The first is remote update or code-push SDKs that swap JavaScript bundles, Swift code, or asset packs after approval. The microsoft/code-push issue #841 records a 2.3.1 rejection on a React Native build that integrated CodePush 7.1.0; the developer's fix was to remove the SDK entirely and resubmit. Apple's review note read only 'the app contains hidden features,' without naming the SDK by class, which is consistent with the vague reviewer wording most teams receive.

    The second is debug menus, internal tooling, and developer panels left active in the production target. A debug screen reachable from a long-press, a shake gesture, or an undocumented URL scheme falls inside the hidden bucket whether or not the developer treats it as a real feature.

    The third is feature flags that gate central functionality. Reviewers cannot evaluate what they cannot see; if the only path to a paid tier, a chat surface, or a content library lives behind a server flag flipped to off during review, the build risks rejection even when the code itself is clean.

    The fourth is misleading marketing copy. The Guideline names 'iOS-based virus and malware scanners' as a class of features that App Review treats as functionally false on the iOS sandbox. Promising what the platform does not allow is treated the same as hiding what the binary does.

    Vibe-coded apps built with Claude Code, Cursor, or similar agentic IDEs are over-represented here. The generated codebase often ships a debug route, a feature flag bundle, or a remote config SDK that the developer did not consciously add. A static review of the compiled IPA against the App Store metadata closes that gap before submission. PTKD.com (https://ptkd.com) is one of the platforms that runs that pre-submission scan against OWASP MASVS-aligned checks on the IPA artifact.

    How does the Notes for Review field protect you from 2.3.1?

    Notes for Review is the documented exit from 2.3.1, and Apple's wording singles out the field by name. The guideline language requires that all new features, functionality, and product changes be described with specificity in the Notes for Review section of App Store Connect, with the explicit warning that generic descriptions will be rejected and that features must be accessible for review.

    Three habits raise the odds Notes for Review clears the bar. Name each new feature in plain language, including features behind a server flag that you intend to activate later. Provide a demo account that exposes every gated surface; the Apple Developer Forums thread referenced above contains specific guidance from longtime members on supplying a back-door method for reviewers when a feature is dormant. Describe code-push or remote configuration explicitly, including the rules that decide what the SDK is allowed to change.

    Generic text fails. 'Bug fixes and performance improvements' cleared review in 2014 and stopped clearing review around the 2.3 rewrite. A line that names the actual subsystem touched, the user-visible change, and any gating behavior is the form that maps to how reviewers read the field.

    What should you do after the rejection email arrives?

    The first move is to read the Resolution Center message in App Store Connect, not the email. The email is a notification; the Resolution Center is where Apple posts follow-up notes and screenshots when one is attached. A reviewer occasionally pastes a frame from inside the app that shows the surface they tripped over, and that frame is the cheapest evidence available.

    The second move is to inventory the binary for the three categories above. A short audit of the production target settings, the active SDKs, and any flag-controlled screens covers the high-frequency triggers. Strip debug routes from the release configuration. Disable code-push for App Store builds or split the release into a clean target. Confirm that every screen reachable on first launch is described somewhere in the App Store metadata or Notes for Review.

    The third move is to use the Reply option in the Resolution Center before resubmitting if the trigger is ambiguous. A direct question to App Review, written calmly, often returns a one-line clarification within 24 to 48 hours. The Reply path is documented on Apple's App Review process page and does not count against future submissions.

    A resubmission then carries a rewritten Notes for Review, a fresh CFBundleVersion, and a target that no longer includes the flagged behavior. The same build under the same identifiers is rejected as a duplicate.

    Which actions actually clear a 2.3.1 rejection?

    ActionWhat it changesWhat it does not change
    Strip debug menus and developer routes from the release targetRemoves the most common 2.3.1 trigger in vibe-coded and React Native appsA second rejection if remote-update SDKs remain
    Remove or gate code-push and OTA-update SDKs for the release configurationCloses the dormant-feature category Apple flagged in code-push issue #841The need to document any remaining server flags
    Rewrite Notes for Review with feature-by-feature specificityDirectly addresses the guideline's named requirementAn underlying feature that is still hidden in the UI
    Provide a demo account exposing every gated surfaceGives the reviewer the back-door method longtime developers describeAn app whose marketing copy oversells platform capability
    Reply in the Resolution Center asking which screen tripped 2.3.1Often returns a one-line clarification within 24 to 48 hoursThe need to ship a new binary if a feature was actually hidden
    Resubmit under an incremented CFBundleVersionRoutes the artifact into a fresh review passThe risk of the same trigger if the audit was incomplete

    What to watch out for

    The first trap is treating 2.3.1 as a single-issue rejection. The guideline covers three classes and Apple's reviewer email rarely names which class fired. A debug menu and a code-push SDK on the same build can both fail under the same wording, and clearing one without auditing the other lands a second rejection on the resubmission.

    The second trap is reading 'hidden' as malicious. Apple's text in subsection (b) calls out egregious or repeated behavior as grounds for developer-account removal, but most 2.3.1 first-time rejections sit far from that bar. The escalation language is real, and the right response treats the rejection as build hygiene.

    The third trap is rewriting marketing copy in App Store Connect to match a banned promise instead of rebuilding the feature. The Guideline lists 'iOS-based virus and malware scanners' because the iOS sandbox does not allow that functionality. Rewriting copy without changing the underlying claim does not clear the rejection.

    The fourth trap is the myth that feature flags are forbidden. They are not. The published forum guidance from longtime developers is clear: feature flags are acceptable when the core app experience is accurately reflected at review time and when Notes for Review describes them. The line Apple draws sits between flags as a release-management tool and flags as a way to hide content from review.

    Key takeaways

    • Treat the Notes for Review field as the primary lever; Guideline 2.3.1 names it explicitly, and most rejections clear with a rewrite that names every feature and every flag.
    • Strip debug menus, developer routes, and remote-update SDKs from the release target before the first submission; the same build re-uploaded under the same identifiers is rejected as a duplicate.
    • Use the Resolution Center Reply option to ask which screen tripped 2.3.1 when the email is vague; documented reviewer replies often return a one-line clarification within 24 to 48 hours.
    • For vibe-coded and no-code builds, run a static read of the IPA against the public metadata before submission; PTKD.com (https://ptkd.com) is one of the platforms that performs that OWASP MASVS-aligned scan on the compiled artifact and flags debug routes and remote-update SDKs before the reviewer does.
    • #app-store-rejection
    • #guideline-2-3-1
    • #hidden-features
    • #app-store-connect
    • #notes-for-review
    • #code-push
    • #vibe-coded-apps

    Frequently asked questions

    Does Apple always cite Guideline 2.3.1 by number in the rejection email?
    Most rejection notes name the guideline by number and short title, 'Guideline 2.3.1 Performance Accurate Metadata,' in the Resolution Center message. The text rarely identifies which screen or SDK triggered the reviewer. Replying in the Resolution Center with a direct question about which surface the reviewer flagged is the documented path to a clarification; one-line replies within 24 to 48 hours are common on first submissions.
    Are feature flags allowed under Guideline 2.3.1?
    Yes, when the core app experience at review time is accurately reflected and when Notes for Review describes the flag's purpose and gated behavior. Apple Developer Forums guidance from longtime members frames acceptable flag use as a release-management tool. Flags that gate central functionality, paid tiers, or content-rating-sensitive surfaces during review carry the highest rejection risk under this guideline.
    Will removing code-push or OTA SDKs fix every 2.3.1 rejection?
    No. Remote-update SDKs are one of four common triggers, not the only one. Debug menus, dormant features behind server flags, and misleading marketing copy all fire under the same guideline. The Resolution Center wording rarely names the trigger, so a clean audit of the release target, the active SDKs, and the App Store metadata is safer than removing one SDK and resubmitting blind.
    Does Guideline 2.3.1 apply to TestFlight builds as well as App Store submissions?
    Yes. Beta App Review evaluates TestFlight builds against the same App Review Guidelines that gate App Store submissions, and 2.3.1 sits inside that scope. Hidden debug menus, undocumented features, and remote-update SDKs trigger the same rejection on a TestFlight build as on a production submission. The Notes for Review field exists on TestFlight builds for the same reason.
    How long does a clean 2.3.1 resubmission take to clear review?
    Once the binary, Notes for Review, and metadata are aligned, the resubmission enters the standard App Review queue. Apple does not publish target times, and third-party trackers report median windows of roughly 24 to 48 hours in 2026. A second rejection under the same guideline sits in undocumented territory and signals that the original audit missed a category.

    Keep reading

    Scan your app in minutes

    Upload an APK, AAB, or IPA. PTKD returns an OWASP-aligned report with copy-paste fixes.

    Try PTKD free