Guideline 2.5.2: downloading executable code

A Guideline 2.5.2 rejection means the reviewer concluded your app downloads and runs code. Sometimes that is literally true: a downloaded framework, a script payload. Sometimes it is an over-the-air JavaScript bundle you believed was allowed, and the reviewer read it differently.

The short version: your app must be self-contained in its bundle, and may not download, install or execute code that changes its features.

How it is usually worded

The header arrives as Guideline 2.5.2 - Performance - Software Requirements, and the body is normally close to:

  • "Your app installs or launches executable code, which is not permitted on the App Store."
  • "We found that your app downloads code in order to change its features or functionality after review."

What it actually means

The guideline asks that apps be self-contained in their bundles, that they not read or write outside the designated container, and that they not download, install or execute code that changes features or functionality. It excepts educational apps that teach or test executable code, provided the code serves no other purpose and its source is completely viewable and editable by the user.

The part developers actually rely on is not in the review guidelines at all. It is in the Apple Developer Program License Agreement, which permits interpreted code when all scripts and interpreters are packaged in the app, and excepts code downloaded and run by Apple's built-in WebKit framework or JavaScriptCore, provided it does not change the app's primary purpose by adding features inconsistent with its advertised purpose as submitted.

Read the two documents together and the line becomes visible. Native code, never. Interpreted code running in JavaScriptCore or WebKit, permitted, as long as it does not change what the app is.

What is clearly not allowed

  • Downloading a native binary, dynamic library or framework and loading it. dlopen on a downloaded .dylib is the textbook violation.
  • Shipping your own interpreter and downloading programs for it to run, where those programs add features.
  • A payload that turns your app into a different product after approval, in any language.
  • Code that modifies other apps, or reaching outside your container.

What is generally accepted

  • Content. Text, images, video, JSON, ML model weights, level and map data. Data is not code, even when it is large.
  • Remote configuration. Flags that switch between paths already in your shipped binary. Disclose them anyway; see 2.3.1.
  • Web content in a web view. Your site, rendered by WebKit.
  • JavaScript bundle updates in React Native, Expo or Cordova-style apps, when the bundle runs in JavaScriptCore and keeps the app doing the same thing. This is why CodePush and Expo Updates exist and why thousands of shipped apps use them.

That last one needs care. The review guidelines do not say over-the-air JavaScript updates are fine. The licence agreement permits interpreted code under conditions, developers rely on that, and reviewers overwhelmingly accept it. That is not a guarantee, and anyone describing it as a documented allowance is overstating.

Why it triggers

  • A code-push SDK the reviewer noticed, in a build where a fresh install downloaded a bundle before the app was usable.
  • Downloaded bundles that add screens. An update that introduced a whole feature after approval breaches the licence condition rather than meeting it.
  • A bundled interpreter plus downloadable scripts. Lua, Python and JavaScript engines running user or server-supplied programs, or a plugin marketplace where third parties supply the logic.
  • Mini apps, chatbots, plug-ins and emulators handled outside their own rules, which sit under a separate guideline with its own conditions.

How to fix it, in order

  1. Ask what they found, if they did not say. "Could you confirm which component was identified as downloading executable code?" You cannot fix a mechanism you have not identified.
  2. Delete any native download path. No downloaded binaries, libraries or frameworks. There is no version of this you can argue.
  3. Ship the reviewed build complete. A first launch that must fetch a bundle before it works is the pattern that draws attention. Bundle the current JavaScript in the binary.
  4. Constrain over-the-air updates to fixes. Bug fixes, copy, styling. No new features, no new payment paths, no change of purpose. If a change would need a new App Store description, it needs a new submission.
  5. Move volatile logic to the server and render the result. A server computing an answer is not the app executing downloaded code, and a script that can become a declarative payload interpreted by shipped code should.
  6. Say what you do in Review Notes before it becomes a rejection. One sentence about JavaScript bundles running in JavaScriptCore, for fixes only, costs nothing.

What to send back

Thank you for the review. The app does not download or execute native code. It is built with React Native, and the JavaScript in build 74 is bundled inside the binary; the app is fully functional on first launch with no network fetch required. We do use an over-the-air mechanism for JavaScript fixes, which runs in JavaScriptCore, restricted to bug fixes and copy corrections. It cannot add features, screens or payment paths, and does not change the app's purpose as described on our product page. All feature changes go through App Review as a new build. The plug-in loader that could fetch third-party modules has been removed.

Keep the reply factual and narrow. Do not quote the licence agreement at the reviewer, and do not argue that everyone does this. Name your mechanism, name the engine, state the limit you hold yourself to.

When it is really a different guideline

  • Features present but concealed rather than downloaded is 2.3.1.
  • Payments taken outside In-App Purchase through a downloaded flow is 3.1.1.

AppSubmit records what each build contained and which release notes went with it, so an over-the-air change traces back to the approved build. Tagging releases honestly does the same job.

Source: Apple, App Store Review Guidelines, 2.5.2 (https://developer.apple.com/app-store/review/guidelines/#software-requirements), and the Apple Developer Program License Agreement

Related: apple-guideline-2-3-1-hidden-features, apple-guideline-2-5-4-background-modes

Last reviewed 2026-08-17. Apple and Google change their rules without notice, so check anything decision-critical against their live documentation.