Server-driven UI iOS: How Uzori Turns “Where Did My Money Go?” Into a Four‑Step SwiftUI Status Answer

Meta description: This guide explains server-driven UI iOS patterns, how to generate SwiftUI from LLM responses with the Uzori SDK UI framework, and how to…

Hourglass filled with coins symbolizing staged server-driven UI status for iOS transaction disputes.

Meta description: This guide explains server-driven UI iOS patterns, how to generate SwiftUI from LLM responses with the Uzori SDK UI framework, and how to evolve a static app into a dynamic user interface platform.

When a user asks “Where did my money go?” in your banking app, a chat bubble is the least helpful answer.

What they really need is a four-step status flow: the transaction, the dispute, the evidence, and the resolution.

This article shows how to deliver that as server-driven UI on iOS, how to generate SwiftUI from LLM output safely, and how Uzori turns that into a reusable AI interface layer for your app.

We’ll cover:

  • Core concepts of server-driven UI iOS
  • Why a dispute is a multi-step status answer, not a chat
  • Schema design for server-driven UI iOS (with runnable JSON Schema)
  • How to generate native iOS UI from LLM responses
  • Client approval flows and server-side validation
  • Performance and caching guidance
  • How Uzori’s AI UI SDK for SwiftUI fits into your stack

All examples are grounded in real-world references and public docs, with sources linked.

“Where did my money go?” is a four-step status answer

Dispute flows in financial services are structured by design.

ServiceNow’s dispute management workflow breaks a dispute into four stages: Initiate, Review, Processing, Closure.[^servicenow] Banks like Chase and Bank of America expose in-app dispute filing plus status tracking over time.[^chase-bofa]

That means your UX should answer:

  1. What happened? – show the transaction.
  2. What did I file? – show the dispute.
  3. What’s needed from me? – evidence upload, questionnaires.
  4. What’s the status? – in review, provisional credit, resolved.

A chat transcript can’t do this as well as:

  • A timeline of dispute stages
  • A detail view of the transaction and claim
  • A form for evidence and contact info
  • A status card that updates over time

Server-driven UI lets you compose these views from the backend, and AI-generated SwiftUI lets those screens build themselves in response to user intent.

What is server-driven UI on iOS?

Server-driven UI (SDUI) moves screen composition from the app binary to the server while keeping rendering native.

Teams like Q42 (PostNL), REI, and Shopify have all described this pattern:

  • Q42/PostNL: flows are assembled on the server while apps render approved components, allowing new flows without shipping an app update.[^q42]
  • REI: chose SDUI to “design for the unknown” and keep options open for changing flows without locking into client-only layouts.[^rei]
  • Shopify: used SDUI to escape static layouts and accelerate experiments; weekly app releases were too slow for iteration.[^shopify]

In the iOS context, SDUI means:

  • The server describes what to show (layout, components, actions).
  • The app renders those descriptions with native SwiftUI.
  • Only approved, typed components are allowed.

This pattern pairs naturally with modern SwiftUI, which Apple presents as the default way to declare UI and data flow for new Apple-platform apps.[^swiftui]

Why combine server-driven UI with AI in 2026?

Most iOS teams now use AI tools.

The 2025 Stack Overflow Developer Survey (49,000+ respondents) reports:

  • 84% of developers use or plan to use AI tools.
  • 69% of AI agent users say productivity improved.
  • But 46% do not trust AI accuracy, and 45% say debugging AI code is time-consuming.[^so-2025]

That trust gap is the core problem.

AI can:

  • Interpret fuzzy questions like “Where did my money go?”
  • Decide if the user needs transactions, disputes, or budgeting insights.
  • Compose the flow structure for the next screen.

But you still need:

  • Schema-constrained outputs, not free-form JSON.
  • Server-side validation of every UI screen.
  • Native SwiftUI rendering, not arbitrary remote code.

OpenAI’s Structured Outputs feature is a good example of this direction: it uses JSON Schema to force models to emit structured responses.[^openai-structured] OpenAI reports that GPT‑4o with Structured Outputs achieved strong adherence to complex schemas in their internal benchmarks, while older models struggled.[^openai-structured]

Uzori builds on these ideas for AI-generated SwiftUI: the AI composes, your server approves, and your app renders.

Schema design for server-driven UI iOS

Designing a robust schema is the backbone of a safe SDUI system.

This section includes:

  • A runnable JSON Schema for a dispute status screen
  • A sample payload an LLM might emit
  • An OpenAPI snippet that backs the actions

JSON Schema: dispute status screen (runnable example)

Below is a self-contained JSON Schema for a simplified dispute status screen.

You can copy this into a file like dispute_screen.schema.json and validate sample payloads with any JSON Schema validator.

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/schemas/dispute-screen.json",
"title": "DisputeStatusScreen",
"type": "object",
"required": ["type", "transaction", "dispute", "timeline", "actions"],
"properties": {
"type": {
"const": "disputeStatusScreen"
},
"transaction": {
"type": "object",
"required": [
"id",
"postedAt",
"merchantName",
"amount",
"currency",
"status"
],
"properties": {
"id": { "type": "string" },
"postedAt": { "type": "string", "format": "date-time" },
"merchantName": { "type": "string" },
"amount": { "type": "number" },
"currency": { "type": "string" },
"status": {
"type": "string",
"enum": ["posted", "pending", "reversed"]
}
}
},
"dispute": {
"type": "object",
"required": [
"id",
"reason",
"status",
"createdAt",
"provisionalCredit"
],
"properties": {
"id": { "type": "string" },
"reason": { "type": "string" },
"status": {
"type": "string",
"enum": [
"initiated",
"underReview",
"processing",
"closed"
]
},
"createdAt": { "type": "string", "format": "date-time" },
"provisionalCredit": {
"type": "object",
"required": ["granted", "amount"],
"properties": {
"granted": { "type": "boolean" },
"amount": { "type": "number" }
}
}
}
},
"timeline": {
"type": "array",
"items": {
"type": "object",
"required": ["stage", "label", "timestamp"],
"properties": {
"stage": {
"type": "string",
"enum": [
"initiate",
"review",
"processing",
"closure"
]
},
"label": { "type": "string" },
"timestamp": { "type": "string", "format": "date-time" },
"isCurrent": { "type": "boolean" }
}
}
},
"actions": {
"type": "array",
"items": {
"type": "object",
"required": ["id", "label", "kind"],
"properties": {
"id": { "type": "string" },
"label": { "type": "string" },
"kind": {
"type": "string",
"enum": [
"primary",
"secondary",
"link"
]
},
"actionType": {
"type": "string",
"enum": [
"createDispute",
"attachDocument",
"contactSupport"
]
},
"api": {
"type": "object",
"required": ["method", "path"],
"properties": {
"method": {
"type": "string",
"enum": ["GET", "POST"]
},
"path": { "type": "string" },
"requestSchemaId": { "type": "string" }
}
}
}
}
}
}
}

Sample AI output: dispute status screen JSON

Here is a sample payload that conforms to the schema above.

This is the kind of structure you can ask an LLM to emit via Structured Outputs or function calling.

{
"type": "disputeStatusScreen",
"transaction": {
"id": "txn_123",
"postedAt": "2026-08-29T14:32:00Z",
"merchantName": "ACME DIGITAL SERVICES",
"amount": 42.5,
"currency": "USD",
"status": "posted"
},
"dispute": {
"id": "disp_987",
"reason": "I do not recognize this transaction.",
"status": "underReview",
"createdAt": "2026-08-30T09:10:00Z",
"provisionalCredit": {
"granted": true,
"amount": 42.5
}
},
"timeline": [
{
"stage": "initiate",
"label": "Dispute submitted",
"timestamp": "2026-08-30T09:10:00Z",
"isCurrent": false
},
{
"stage": "review",
"label": "Bank is reviewing your claim",
"timestamp": "2026-08-31T12:00:00Z",
"isCurrent": true
},
{
"stage": "processing",
"label": "Card network review (pending)",
"timestamp": "2026-09-01T00:00:00Z",
"isCurrent": false
},
{
"stage": "closure",
"label": "Final decision (pending)",
"timestamp": "2026-09-15T00:00:00Z",
"isCurrent": false
}
],
"actions": [
{
"id": "attach_evidence",
"label": "Upload supporting document",
"kind": "primary",
"actionType": "attachDocument",
"api": {
"method": "POST",
"path": "/disputes/disp_987/evidence",
"requestSchemaId": "disputeEvidenceRequest"
}
},
{
"id": "contact_support",
"label": "Contact support",
"kind": "link",
"actionType": "contactSupport",
"api": {
"method": "GET",
"path": "/support/chat",
"requestSchemaId": ""
}
}
]
}

You can now validate this JSON against the schema locally, or in a server-side approval pipeline.

Backend APIs: OpenAPI snippet for disputes

Server-driven UI works best when your AI and schema sit on top of a well-typed API surface.

Here is a minimal OpenAPI 3.1 snippet for a disputes backend that matches the schema above.

openapi: 3.1.0
info:
title: Dispute API
version: 1.0.0
paths:
/transactions:
get:
operationId: listTransactions
parameters:
- in: query
name: from
schema:
type: string
format: date
- in: query
name: to
schema:
type: string
format: date
responses:
'200':
description: List of transactions
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Transaction'

/disputes:
post:
operationId: createDispute
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateDisputeRequest'
responses:
'201':
description: Dispute created
content:
application/json:
schema:
$ref: '#/components/schemas/Dispute'

/disputes/{id}/evidence:
post:
operationId: attachDocument
parameters:
- in: path
name: id
required: true
schema:
type: string
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties:
file:
type: string
format: binary
responses:
'204':
description: Evidence attached

components:
schemas:
Transaction:
type: object
properties:
id:
type: string
postedAt:
type: string
format: date-time
merchantName:
type: string
amount:
type: number
currency:
type: string
status:
type: string
enum: [posted, pending, reversed]

Dispute:
type: object
properties:
id:
type: string
reason:
type: string
status:
type: string
enum: [initiated, underReview, processing, closed]
createdAt:
type: string
format: date-time
provisionalCreditAmount:
type: number

CreateDisputeRequest:
type: object
required: [transactionId, reason]
properties:
transactionId:
type: string
reason:
type: string

In your AI orchestration layer, you can map:

  • actionType: "createDispute" → POST /disputes
  • actionType: "attachDocument" → POST /disputes/{id}/evidence
  • actionType: "contactSupport" → /support endpoints or deep links

This mapping stays on the server, not in the iOS app, keeping your client logic slim.

Generate native iOS UI from LLM responses — example workflow

To generate native iOS UI from LLM responses safely, you can follow this pattern:

  1. User intent capture
    • User types: “Where did my money go?”
    • App forwards the utterance plus context (user ID, locale) to your AI backend.
  2. LLM planning
    • LLM calls functions or tools (e.g., list transactions, fetch disputes) based on your OpenAPI spec.
    • LLM decides that the right surface is a disputeStatusScreen.
  3. Schema-constrained UI generation
    • LLM is instructed to emit JSON conforming to DisputeStatusScreen schema.
    • Use JSON Schema or OpenAI Structured Outputs with strict-style enforcement.[^openai-structured]
  4. Server validation and approval
    • Validate JSON server-side against the schema.
    • Enforce business rules (e.g., no unknown actions, no unapproved endpoints).
  5. Streaming to the app
    • Stream the approved UI description to the iOS app via SSE or WebSocket.
    • The app decodes JSON into typed Swift models and renders SwiftUI views.

Uzori automates large parts of this pipeline, particularly the last leg: turning validated JSON into SwiftUI screens and handling streaming updates.

Generate SwiftUI from LLM: approaches and tools (2026)

The phrase “generate SwiftUI from LLM” hides several different approaches.

Common patterns in 2026 include:

  1. Text-to-code (not recommended for runtime UI)
    • LLM emits SwiftUI source code.
    • Human reviews, then ships via app update.
    • Pros: maximal flexibility.
    • Cons: not safe for dynamic runtime; high trust and security risks.
  2. Schema-driven SDUI (recommended)
    • LLM emits JSON that matches a UI schema.
    • Server validates and maps to SwiftUI components.
    • Pros: safe, testable, aligns with App Store and platform constraints.
  3. Hybrid SDUI + design system
    • LLM selects from pre-approved components in your design system.
    • Server merges AI suggestions with rule-based layouts.

OpenAI explicitly calls out dynamic user interface generation as a use case for Structured Outputs.[^openai-structured]

Uzori sits squarely in the schema-driven space:

  • The Uzori engine works against your OpenAPI and your typed UI schema.
  • It streams validated SwiftUI descriptions to your app.
  • You retain full control over allowed components, actions, and endpoints.

Best tools for server-driven UI iOS development

This section compares some of the best tools for server-driven UI iOS development as of 2026 and where Uzori fits.

Uzori (SwiftUI + AI SDUI)

Focus: AI-native, schema-driven SwiftUI for iOS.

Strengths:

  • AI-driven layout with server-side validation.
  • Single-screen SDK that fits into existing SwiftUI navigation.
  • Native-only focus (SwiftUI), no web views.
  • Strong fit for AI concierges, guided setup, product explorers.

Trade-offs:

  • iOS first (no Android/web rendering today).
  • Requires well-described backend APIs (OpenAPI) for best results.

Conventional SDUI frameworks / in-house SDUI

Many teams build custom SDUI layers or use internal frameworks inspired by Q42, REI, or Shopify.[^q42][^rei][^shopify]

Strengths:

  • Fully tailored to your design system.
  • Proven pattern for A/B tests and rollout control.

Trade-offs:

  • Typically rule-based, not AI-driven.
  • Requires ongoing investment to add new component types and flows.

CopilotKit and React-based Generative UI

Tools like CopilotKit focus on web and React generative UI.[^copilotkit]

Strengths:

  • Strong fit for web dashboards and internal tools.
  • Provides a taxonomy of generative UI patterns.

Trade-offs:

  • React-centric; not a native SwiftUI SDK.
  • Requires adapters or separate stacks for iOS.

When to pick Uzori

Use Uzori when you need:

  • AI-native assistance inside your iOS app that feels like part of the app.
  • Server-driven safety but AI-composed layouts.
  • Rapid iteration on concierge flows without rewriting SwiftUI screens.

SwiftUI + Uzori SDK integration example

This is a minimal SwiftUI integration sketch.

It shows how an iOS app might decode Uzori’s approved schema and stream updates into a SwiftUI view.

import SwiftUI
import Combine
import UzoriSDK

struct DisputeStatusScreenModel: Decodable {
let type: String
let transaction: Transaction
let dispute: Dispute
let timeline: [TimelineItem]
let actions: [Action]

struct Transaction: Decodable {
let id: String
let postedAt: Date
let merchantName: String
let amount: Double
let currency: String
let status: String
}

struct Dispute: Decodable {
let id: String
let reason: String
let status: String
let createdAt: Date
let provisionalCredit: ProvisionalCredit

struct ProvisionalCredit: Decodable {
let granted: Bool
let amount: Double
}
}

struct TimelineItem: Decodable, Identifiable {
let id = UUID()
let stage: String
let label: String
let timestamp: Date
let isCurrent: Bool
}

struct Action: Decodable, Identifiable {
let id: String
let label: String
let kind: String
let actionType: String
let api: API

struct API: Decodable {
let method: String
let path: String
}
}
}

final class DisputeViewModel: ObservableObject {
@Published var screen: DisputeStatusScreenModel?

private var cancellables = Set<AnyCancellable>()
private let uzoriClient = UzoriClient()

func startSession(userQuery: String) {
uzoriClient
.streamScreen(query: userQuery, screenType: "disputeStatusScreen")
.decode(type: DisputeStatusScreenModel.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { completion in
// handle errors
}, receiveValue: { [weak self] model in
self?.screen = model
})
.store(in: &cancellables)
}

func perform(action: DisputeStatusScreenModel.Action) {
uzoriClient.performAction(apiMethod: action.api.method,
path: action.api.path)
}
}

struct DisputeStatusView: View {
@StateObject var viewModel = DisputeViewModel()

var body: some View {
Group {
if let screen = viewModel.screen {
VStack(alignment: .leading, spacing: 16) {
Text(screen.transaction.merchantName)
.font(.title2)
Text("$\(screen.transaction.amount, specifier: "%.2f") \(screen.transaction.currency)")
.font(.headline)

TimelineView(timeline: screen.timeline)

ForEach(screen.actions) { action in
Button(action.label) {
viewModel.perform(action: action)
}
}
}
.padding()
} else {
ProgressView("Loading dispute status…")
}
}
.onAppear {
viewModel.startSession(userQuery: "Where did my money go?")
}
}
}

This is pseudocode; real Uzori APIs may differ.

The important part is the integration shape:

  • A single streamScreen call subscribes to AI-generated, server-approved UI.
  • You decode into typed models and render SwiftUI like any other SDUI.

Performance considerations for server-driven UI iOS

Performance is often the biggest concern for SDUI.

Here are practical guidelines and data-informed heuristics.

Payload size and complexity

For most SDUI payloads:

  • Target 10–50 KB per screen for typical flows.
  • For complex flows or carousels, keep under 100 KB when possible.
  • Split very large flows into multi-step screens to keep decoding cheap.

On modern iPhones (A14 and later), decoding a 50 KB JSON payload into Swift structs using JSONDecoder typically completes in a few milliseconds under normal conditions.

Streaming protocol: SSE vs WebSocket

For server-driven UI iOS with AI:

  • Use Server-Sent Events (SSE) when:
    • The app mostly receives one-way updates.
    • You want simple HTTP semantics.
  • Use WebSocket when:
    • You need bi-directional, low-latency updates.
    • You anticipate multiple, concurrent AI-driven flows per user.

Uzori can operate with either approach, but WebSocket is common for conversational, multi-step flows because it aligns well with streaming LLM tokens and incremental UI updates.

Caching and reuse

To avoid re-fetching full SDUI payloads:

  • Cache component templates or schemas locally (e.g., versioned by hash).
  • Cache data-only updates separately from layout.
  • Use ETags or similar mechanisms so the server can skip sending unchanged layout.

Trade-offs:

  • More caching → faster repeat interactions, but more invalidation complexity.
  • Less caching → simpler logic, but higher bandwidth and decode overhead.

A balanced approach is to treat:

  • Layout as long-lived and cached.
  • Data as dynamic and refreshed.

Schema design for server-driven UI iOS

Schema design is where safety, flexibility, and AI ergonomics meet.

Key principles for schema design for server-driven UI iOS:

  1. Typed components only
    • Enumerate allowed views: list, detailCard, timeline, form, button.
    • Disallow arbitrary HTML or code.
  2. Separation of content and behavior
    • Content: labels, text, numbers.
    • Behavior: actions with actionType and api metadata.
  3. Versioning and evolution
    • Include a schemaVersion or $id per schema.
    • Only roll out new component types once the app supports them.
  4. AI-friendly constraints
    • Keep enums and field names descriptive, not cryptic.
    • Provide examples in your LLM prompt that match the schema.

This makes it straightforward to prompt a model:

“You must respond with JSON matching the DisputeStatusScreen schema. Never invent new fields. If unsure, omit optional sections.”

Combined with a server-side JSON Schema validator, this is the practical guardrail pattern that OpenAI recommends for Structured Outputs.[^openai-structured]

Secure iOS AI SDK privacy best practices

Privacy is not optional; it’s part of the platform contract.

Apple now requires privacy manifests for certain SDKs and App Privacy Details for app submissions.[^apple-privacy-manifest] Apple’s Human Interface Guidelines also emphasize data minimization and transparency.[^apple-hig-privacy]

For an AI UI SDK SwiftUI iOS integration, follow these secure iOS AI SDK privacy best practices:

  1. Data minimization
    • Send only the data the AI needs: transaction IDs, not full account numbers.
    • Redact PII (e.g., names, addresses) before sending to AI backends unless required.
  2. On-device handling where possible
    • Keep sensitive transformations (e.g., masking PANs) on-device.
    • Use on-device storage (Keychain, Secure Enclave) for tokens and secrets.
  3. Explicit consent and disclosures
    • Explain how AI is used in your App Privacy section.
    • Provide in-app explanations for what data is sent to AI services.
  4. Logging and PII redaction
    • Ensure server logs redact user-identifiable fields.
    • Disable verbose logging in production for dispute content.
  5. Third-party SDK manifests
    • For any SDK (including AI UI SDKs), provide a privacy manifest as Apple requires.[^apple-privacy-manifest]

How Uzori helps:

  • Uzori operates as a server-driven UI layer: you control what data is sent through it.
  • The Uzori SDK is designed to be data-sparse on-device and defer sensitive data handling to your own backend.
  • You can implement per-feature consent before enabling AI-generated interfaces.

Evolving from static app to dynamic user interface platform

Most teams don’t jump straight to full SDUI.

A practical path:

  1. Instrument a single flow
    • Choose a narrow but impactful flow, like transaction disputes.
    • Build a schema for the dispute status screen.
    • Wire it up with your OpenAPI backend and Uzori.
  2. Add AI orchestration
    • Start with deterministic SDUI.
    • Introduce AI to choose between variants of the same schema (e.g., different layouts for card vs ACH disputes).
  3. Generalize your schema
    • Extract shared components: Timeline, StatusBadge, DocumentUpload.
    • Expand Uzori’s component library accordingly.
  4. Roll out to other domains
    • Apply the same pattern to:
      • Roaming plans in telecom
      • Product discovery in retail
      • Configuration wizards in SaaS

Over time, your app becomes a dynamic user interface platform where:

  • Backend and AI decide which flows to show.
  • SwiftUI is the rendering engine.
  • Uzori is the AI interface layer binding everything together.

FAQ: server-driven UI iOS, Uzori, and AI-generated SwiftUI

1. Is server-driven UI allowed by Apple’s App Store rules?

Yes.

Server-driven UI is a well-established pattern used by companies like Netflix, Shopify, and Uber.[^netflix][^shopify][^uber] As long as you do not download executable code and you follow App Store guidelines, sending layout metadata and data from the server is permitted.

2. How does Uzori differ from a generic chat widget?

Uzori doesn’t just render chat.

It lets AI send full SwiftUI screens that are:

  • Built from your design system components.
  • Validated server-side against strict schemas.
  • Streamed into the app as native views, not web views.

The result feels like the rest of your app, not like an embedded chatbot.

3. What if the AI generates invalid UI?

With Uzori, invalid UI never reaches the client.

The server validates the AI’s JSON against your schemas and business rules.

If validation fails, you can:

  • Return a fallback deterministic layout.
  • Log and inspect failed generations.
  • Tighten prompts or schemas as needed.

4. How do I handle localization in server-driven UI?

You have two main options:

  • Server-localized strings: the backend sends localized text based on user locale.
  • Localization keys in SDUI payloads: the app resolves keys via Localizable.strings.

Uzori supports either approach; most teams start with server-localized strings for AI-generated surfaces, then introduce keys for more control.

5. Can I use Uzori with a mixed UIKit/SwiftUI app?

Yes.

SwiftUI supports incremental adoption, and Apple encourages mixing SwiftUI with UIKit where appropriate.[^swiftui]

You can embed Uzori-powered SwiftUI screens inside existing UIKit containers using UIHostingController.

If you’re exploring server-driven UI iOS, want to generate SwiftUI from LLM output safely, and need to answer “Where did my money go?” as a four-step status flow, Uzori gives you a way to ship it fast, native, and safe.

[^swiftui]: Apple, “SwiftUI,” developer documentation, accessed September 4, 2026. https://developer.apple.com/documentation/swiftui [^q42]: Q42, “Server Driven UI at PostNL,” accessed September 4, 2026. https://engineering.q42.nl/sdui-postnl-app/ [^rei]: REI Engineering, “Server Driven UI,” accessed September 4, 2026. https://engineering.rei.com/mobile/server-driven-ui.html [^shopify]: Shopify Engineering, “Server-driven UI at Shopify,” accessed September 4, 2026. [^openai-structured]: OpenAI, “Introducing Structured Outputs in the API,” blog post, August 2024. https://openai.com/index/introducing-structured-outputs-in-the-api/ [^so-2025]: Stack Overflow, “2025 Developer Survey,” press release, 2025. https://stackoverflow.co/company/press/archive/stack-overflow-2025-developer-survey/ [^servicenow]: ServiceNow, “Dispute management workflows,” Financial Services Operations docs, accessed September 4, 2026. https://www.servicenow.com/docs/r/financial-services-operations/dispute-management/dispute-management-workflows.html [^chase-bofa]: Bank of America, “How to track your claim status,” help docs; Chase, “Dispute a charge,” customer support docs, accessed September 4, 2026. [^apple-privacy-manifest]: Apple, “Adding a privacy manifest to your app or third-party SDK,” developer documentation, accessed September 4, 2026. https://developer.apple.com/documentation/bundleresources/adding-a-privacy-manifest-to-your-app-or-third-party-sdk [^apple-hig-privacy]: Apple, “Privacy,” Human Interface Guidelines, accessed September 4, 2026. https://developer.apple.com/design/human-interface-guidelines/privacy [^netflix]: Netflix Tech Blog, “Unlocking Dynamic Pages: The Evolution of Netflix’s Client-Server GraphQL APIs,” accessed September 4, 2026. https://netflixtechblog.com/unlocking-dynamic-pages-the-evolution-of-netflixs-client-server-graphql-apis-8b4631a59b39 [^uber]: Uber Engineering, “Experimentation and server-driven configurations on mobile,” accessed September 4, 2026. [^copilotkit]: CopilotKit, “Generative UI Overview,” docs, accessed September 4, 2026. https://docs.copilotkit.ai/concepts/generative-ui-overview

← All posts