Skip to content
Flow-UILive
On this page

App Store Guideline 2.5.2 and declarative JSON

A JSON page that picks among widgets already in the binary is data. Downloaded executable code is not. Keep the payload declarative.

Ayush MishraPublished 3 min read

A JSON page that picks among widgets already in the binary is data. Downloaded executable code is not. Keep the payload declarative. This is not legal advice. Read Apple's Guideline 2.5.2 yourself, and read current App Review notes. Public explainers (RevenueCat, small-team SDUI posts) are the industry pattern this article points at, not a promise that your binary will be approved.

What teams are afraid of#

2.5.2 is the rule people summarise as "no downloaded code". Interpreters, plugins, and eval belong in that fear. SDUI looks adjacent because the UI arrived after the binary. The distinction reviewers care about, in public writing, is whether you downloaded instructions the CPU runs or documents your already-shipped views know how to show.

Declarative JSON: { "type": "title_block", "data": { "title": { "text": "Hello" } } }. The app already contains TitleBlockWidget. The server chose it.

Not declarative: a string you eval, a bitcode blob you load as a plugin, a JavaScript engine running UI logic you did not ship.

RegistryNotInterpreter.swiftswift
let registry = WidgetRegistry()
FlowWidgets.register(on: registry)
registry.register(OrderCardWidget.self)

The registry is a compile-time set of Swift types plus a runtime lookup table. It is not a language VM.

swift
registry.register(PromoCardWidget.self)

What this article will not do#

It will not promise approval.

It will not describe hiding features from review.

It will not quote Apple's legal text as if this site were Apple.

If your product depends on a specific Review outcome, talk to Apple and to counsel.

Keep the payload boring on purpose#

  • Widget type strings that map to registered Swift views
  • Atoms: text, color, image, font
  • Layout: padding, margin, corners, gradients
  • Actions as data: toast, sheet, api, deeplink, dismiss, refresh
  • Opaque tracking objects forwarded to your sink

Avoid:

  • A script field
  • A native_code URL
  • A general purpose expression language in JSON that your client interprets as program logic

If you need logic, put it on the server and send the resulting page. That is the point of SDUI.

New widgets still need a binary#

Guideline anxiety sometimes makes teams over-correct: they put every possible widget in 1.0 so they never ship again. That binary is huge and still incomplete.

Ship widgets you need. Unknown types skip on old versions. When you need a new type, ship it. Rearranging known types is the data deploy. That split is also the honest product claim, independent of Review.

Feature flags are not a disguise#

Flags that toggle compiled views are normal. Downloading a whole feature the binary cannot perform is a different story. Do not use this article as a recipe for the second thing.

What reviewers can actually inspect#

They can inspect the binary for a JavaScriptCore UI engine you pointed at downloaded source. They can inspect network logs for a page of JSON. Those are different artefacts. Keep them different in the architecture so the story stays simple if someone asks.

Your PageLoader returning JSON is the boring artefact. A second channel that downloads .dylib files is not this article's subject and should not ride along "because we already have SDUI".

WebViews and 2.5.2#

Web content has its own Review history. A WebView that loads your help site is a different product than SDUI. Mixing "we are just JSON" with "we also run downloaded JS as the page" is how the story gets unclear. Pick a renderer per surface.

The Flow-UI mark: two nodes joined through a filled centre

Questions this article should close#

Does using Flow-UI guarantee approval?#

No. Nothing on this site is a Review guarantee.

Can we ship a widget catalogue so large we never need another binary?#

You can try. You will still miss a type. Unknown widgets skip. Plan for releases.

Declarative JSON plus compiled widgets is the SDUI posture. Executable downloads are not. Read Apple for the rule; keep the payload boring so the posture stays true.

More on the blog.

Read the source

Flow-UI is MIT licensed. The schema, renderer and starter widgets live on GitHub.

GitHub

Get started with Flow-UI

Install the Swift package, register a widget, and render a page from JSON.

Get started