Our app's screens aren't hard-coded into the app. Each screen is described by a JSON document our servers compose on every request — the client reads it and renders fully native UI. We change what users see in minutes, with no app-store release and no waiting on review queues.
The server returns an ordered list of sections. Each section says what it is, what it looks like, where its data lives, and what happens on tap. The client maps each entry to a native component — every key below controls the highlighted region on the phone.
Two tiers: a light "blueprint" call describes the screen; each section then loads its own data feed independently, so one slow feed never blocks the page.
Server assembles the section list per user — platform, app version, and account state (a brand-new user gets a different home than a power user).
One small JSON payload. Sections carry their own data URLs, refresh intervals, and tap actions.
Clients check the payload against a strict schema. Anything unrecognized is skipped safely — old app versions never break.
Each section type maps to a fully native component on iOS, Android, and web. No webviews — real native performance.
The payload isn't one static file — it's assembled per request from three signals. This is where server-driven UI stops being a rendering trick and becomes a product lever.
A first-time listener with no connected service gets an onboarding-focused home; an active listener gets the full feed — same app binary, different blueprint.
iOS, Android, and web each receive layouts tuned to their conventions from the same section catalog — one definition, three idiomatic renderings.
Payloads are version-gated: newer builds get newer layouts, older builds keep receiving the layout they understand. Nothing in the wild ever breaks.
Everything on the left ships live, to every installed app, the moment we update the server. Honest boundary: brand-new component types still ride a normal release.
A server-driven interface is only as good as its behavior when things go wrong. Resilience is designed in at every layer.
Every section caches on-device with its own server-set refresh interval. On network failure, the client serves the last good version — the app opens instantly, even offline.
Each section loads from its own endpoint. A slow "trending" feed can't block "now playing" — sections stream in as they arrive, skeletons first.
Every payload is schema-checked on device before render. Malformed or unknown content is dropped, never crashed on — a bad deploy degrades a section, not the app.
All copy ships with a version number. Clients re-download strings only when the version bumps — translations update fleet-wide in one server change, near-zero bandwidth cost.
Whole screens — a new feature tab, a seasonal recap, a campaign page — are defined as JSON files on the server, assembled from the existing component catalog. Shipping one is a config change.
A force-update gate lives in the same config: when an app version must retire, the server can require an upgrade — the fleet never fragments beyond what we support.
Server-driven UI is the architecture behind some of the most-iterated consumer apps in the world — Airbnb, Lyft, and Spotify each built internal SDUI platforms to escape the app-store release cycle. It's typically a scale-stage investment; we built it into the foundation, so every product decision from day one compounds at server speed.
UI experiments, seasonal campaigns, and fixes go out in hours, not the 1–2 week app-store cycle. Iteration speed compounds.
A single server-side definition drives iOS, Android, and web simultaneously — consistent product, one place to change it.
Because the server composes each screen per user, segmentation and A/B testing are a payload change, not an engineering project.
Strict client-side validation plus forward compatibility: unknown content is ignored, never crashed on. Every app version in the wild stays stable.
The server sends data, not code. Every component is compiled, signed, reviewed native code — the JSON just arranges it. Same category as any content API.
Each new component ships once through the store, then joins the server-side building-block catalog forever. The platform gets more expressive with every release.