Am I on the Right Plan? Build Comparison‑First SwiftUI Screens with Uzori SDK and Server‑Driven UI (iOS)

Meta title: Uzori SDK for SwiftUI iOS — AI UI SDK for Server‑Driven UI

Cross-section of a nautilus shell symbolizing structured comparison in AI-driven SwiftUI telecom plan interfaces

Meta title & description

Meta title: Uzori SDK for SwiftUI iOS — AI UI SDK for Server‑Driven UI

Meta description: Tutorial: integrate Uzori’s iOS SDK with SwiftUI and server‑driven UI to build comparison‑first “Am I on the right plan?” flows that stay native, safe, and AI‑powered.

Telecom users rarely want a paragraph of advice; they want an answer they can compare.

This tutorial shows how to use the Uzori SDK SwiftUI iOS integration with a server‑driven UI backend to build a comparison‑first “Am I on the right plan?” flow. Instead of a chat bot dumping text, an AI agent will generate SwiftUI comparison screens that your server validates before they appear in the app.

We’ll cover:

  • Integrating Uzori SDK into a SwiftUI iOS app
  • Wiring Uzori into an existing server‑driven UI (SDUI) pipeline
  • Defining OpenAPI endpoints for current/recommended plans
  • Validating generative UI safely on the server
  • Security and privacy best practices for AI UI
  • How Uzori vs DivKit compares for server‑driven UI on iOS

This tutorial pairs well with our related UX piece, “Where did my money go? — a transaction dispute is a four‑step status answer”, which explores status‑first flows in detail.

Why “Am I on the right plan?” needs comparison‑first UI, not paragraphs

“Am I on the right plan?” is one of the most frequent telecom questions. It’s also a perfect example of why AI UX shouldn’t be a chat box pasted on top of your app.

Industry data shows why this use case matters:

  • McKinsey argues telcos should merge service and commercial outreach into a single next‑best‑experience engine, estimating that doing so can cut certain use‑case costs by up to 30%, lift B2C revenue by 2%–4%, improve satisfaction by 10%–20%, and reduce early‑life churn by as much as 30% over three years ("Why AI‑enabled customer service is key to scaling telco personalization", McKinsey & Company, June 27, 2023, https://www.mckinsey.com/industries/technology-media-and-telecommunications/our-insights/why-ai-enabled-customer-service-is-key-to-scaling-telco-personalization).
  • The same McKinsey work notes that customer experience and retention overlap by 80%–90% in some markets, so a good plan‑fit flow directly impacts churn risk (ibid).
  • ACSI reports U.S. cell phone satisfaction dropped 4% to 78/100 in 2025, a decade low ("Telecommunications Study 2025: Cell Phones and Smartwatches", American Customer Satisfaction Index, May 20, 2025, https://theacsi.com/news-and-resources/press-releases/2025/05/20/press-release-telecommunications-cell-phone-and-smartwatch-study-2025/).
  • Deloitte’s 2025 connectivity survey finds 53% of U.S. consumers are experimenting with or regularly using generative AI, 20% are regular users, and 42% of regular users say it has a "very positive" effect on their lives ("2025 Connectivity and Mobile Trends Survey", Deloitte Insights, 2025, https://www.deloitte.com/us/en/insights/industry/telecommunications/connectivity-mobile-trends-survey.html).

Users are ready for AI, but they want trust, transparency, and control. A comparison‑first, native SwiftUI flow — not a wall of AI text — is the right pattern.

Architecture overview: generative UI, server‑driven safety

We’ll build a flow where:

  1. The user asks, “Am I on the right plan?” in your iOS app.
  2. The app opens a Uzori SwiftUI screen.
  3. Uzori’s AI engine:
    • Calls your backend APIs (described via OpenAPI)
    • Compares the user’s current plan to alternatives
    • Composes a SwiftUI comparison view (cards, tables, CTA buttons)
  4. Your backend validates that UI description against a constrained schema.
  5. Only server‑approved UI is streamed into the app.

This pattern combines:

  • Generative UI: AI designs the screen layout for the specific question.
  • Server‑driven UI (SDUI): Your backend as the source of truth for what’s allowed.
  • SwiftUI: Declarative, native UI that feels like the rest of your app.

Prerequisites

To follow this tutorial, you should have:

  • An iOS app using SwiftUI (iOS 16+ recommended)
  • A backend with OpenAPI or REST endpoints for plans
  • Basic server‑driven UI experience (e.g., DivKit, homegrown SDUI, etc.)
  • An Uzori account and API key

We’ll assume your app already uses some SDUI, and we’re plugging Uzori into that pipeline.

Step 1: Add Uzori SDK to your SwiftUI iOS app

Integrating Uzori SDK into a SwiftUI iOS app

Uzori ships as a Swift Package. You integrate it as a single-screen AI UI SDK for SwiftUI iOS.

1.1 Add Uzori via Swift Package Manager

In Xcode:

  1. Go to File → Add Packages…
  2. Enter the Uzori package URL:
    • https://github.com/uzori-ai/uzori-ios-sdk.git
  3. Select the latest stable version.
  4. Add the package to your app target.

_If your org uses a package manifest, add:

.dependencies: [
.package(url: "https://github.com/uzori-ai/uzori-ios-sdk.git", from: "1.0.0")
]

1.2 Core Uzori classes and types (SDK reference)

To make this tutorial reproducible, here’s a reference of the key SDK interfaces you’ll use. Names may be simplified for clarity; check Uzori’s docs for exact signatures.

  • UzoriClient
    • Initializes the connection to Uzori’s AI engine.
    • Example: let client = UzoriClient( apiKey: "UZORI_API_KEY", endpoint: URL(string: "https://api.uzori.ai/v1")! )
  • UzoriScreen
    • A SwiftUI view that hosts Uzori’s generative UI.
    • Example: UzoriScreen( client: client, sessionId: "plan-comparison", context: [ "userId": userId, "entryPoint": "am-i-on-the-right-plan" ] )
  • UzoriScreenContext
    • A typealias for [String: Codable] used to pass initial context.
  • Generic response model (simplified): struct UzoriUIResponse: Decodable { let schemaVersion: String let screens: [UzoriScreenDescriptor] } struct UzoriScreenDescriptor: Decodable { let id: String let layout: UzoriLayout let actions: [UzoriAction] }
  • Error types:
    • UzoriError.network — connectivity issues
    • UzoriError.validationFailed — server rejected the generated UI
    • UzoriError.sessionExpired — session needs to be recreated

You typically don’t parse these manually; the SDK handles streaming and rendering. You only react to high‑level errors in your SwiftUI code.

1.3 Embed a UzoriScreen in SwiftUI

Create a container view for the plan comparison assistant:

struct PlanCheckAssistantView: View {
let userId: String
@State private var uzoriClient = UzoriClient(
apiKey: Secrets.uzoriApiKey,
endpoint: URL(string: "https://api.uzori.ai/v1")!
)

var body: some View {
UzoriScreen(
client: uzoriClient,
sessionId: "plan-comparison-")
.onAppear {
// Optional: pre‑warm session or telemetry
}
}
}

Attach PlanCheckAssistantView to your existing “Help”, “Support”, or “Account” tab.

Step 2: Define OpenAPI for plan comparison (current, recommended, change)

To let Uzori orchestrate real actions, you must expose backend endpoints. We’ll define three:

  • GET /plans/current
  • GET /plans/recommended
  • POST /plans/change

Server‑Driven UI for iOS: hooking Uzori into your SDUI backend

Uzori uses your OpenAPI document as the contract between the AI and your systems. Let’s create a minimal spec.

2.1 Minimal OpenAPI example (YAML)

openapi: 3.0.3
info:
title: Telco Plan Advisor API
version: 1.0.0
servers:
- url: https://api.example-telecom.com

paths:
/plans/current:
get:
summary: Get the customer's current mobile plan
operationId: getCurrentPlan
parameters:
- name: userId
in: query
required: true
schema:
type: string
responses:
'200':
description: Current plan information
content:
application/json:
schema:
$ref: '#/components/schemas/CurrentPlanResponse'

/plans/recommended:
get:
summary: Get recommended plans for a user
operationId: getRecommendedPlans
parameters:
- name: userId
in: query
required: true
schema:
type: string
- name: maxOptions
in: query
required: false
schema:
type: integer
default: 3
responses:
'200':
description: Recommended plan options
content:
application/json:
schema:
$ref: '#/components/schemas/RecommendedPlansResponse'

/plans/change:
post:
summary: Change the customer's mobile plan
operationId: changePlan
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ChangePlanRequest'
responses:
'200':
description: Plan change accepted
content:
application/json:
schema:
$ref: '#/components/schemas/ChangePlanResponse'
'400':
description: Invalid request
'409':
description: Plan change not allowed

components:
schemas:
Plan:
type: object
required: [id, name, monthlyCost, dataAllowanceGb, minutes, perks]
properties:
id:
type: string
name:
type: string
monthlyCost:
type: number
format: float
currency:
type: string
example: USD
dataAllowanceGb:
type: integer
minutes:
type: integer
perks:
type: array
items:
type: string

UsageSummary:
type: object
properties:
averageMonthlyDataGb:
type: number
format: float
averageMonthlyMinutes:
type: number
format: float
roamingDaysLast12Months:
type: integer

CurrentPlanResponse:
type: object
properties:
plan:
$ref: '#/components/schemas/Plan'
usage:
$ref: '#/components/schemas/UsageSummary'

RecommendedPlansResponse:
type: object
properties:
currentPlan:
$ref: '#/components/schemas/Plan'
recommendations:
type: array
items:
$ref: '#/components/schemas/Plan'

ChangePlanRequest:
type: object
required: [userId, targetPlanId]
properties:
userId:
type: string
targetPlanId:
type: string
effectiveDate:
type: string
format: date

ChangePlanResponse:
type: object
properties:
status:
type: string
enum: [accepted, pending, rejected]
message:
type: string
newPlan:
$ref: '#/components/schemas/Plan'

Use this spec both:

  • As the contract for Uzori’s AI agent
  • As part of your existing SDUI backend (for non‑AI flows too)

Step 3: Define Uzori’s UI schema and safety contract

Uzori operates inside a constrained UI schema. Your backend defines what layouts and components the AI is allowed to use.

A minimal schema for a plan comparison might support:

  • screen (root)
  • vstack, hstack
  • card
  • table
  • button
  • text, label

Example JSON UI payload from Uzori to your backend (simplified):

{
"schemaVersion": "1.0",
"screens": [
{
"id": "plan-comparison",
"layout": {
"type": "vstack",
"children": [
{ "type": "text", "style": "title", "value": "Am I on the right plan?" },
{
"type": "table",
"columns": ["Plan", "Monthly", "Data", "Roaming"],
"rows": [
["Current", "$60", "20 GB", "No"],
["Recommended", "$55", "25 GB", "Yes"]
]
},
{
"type": "button",
"id": "change-plan",
"label": "Switch to recommended",
"action": {
"type": "api_call",
"operationId": "changePlan",
"params": {
"targetPlanId": "plan_5g_plus"
}
}
}
]
}
}
]
}

Your server must validate this payload before forwarding it to the client. We’ll implement that next.

Step 4: Implement server‑side validation and fallback UI

Why server validation matters

McKinsey’s research on AI customer service agents (based on 5,000 agents) found issue resolution increased by 14% per hour and handling time dropped 9% when gen‑AI tools were used, but only when applied inside structured workflows and guardrails ("What is an AI agent?", McKinsey & Company, April 30, 2024, https://www.mckinsey.com/featured-insights/mckinsey-explainers/what-is-an-ai-agent).

Uzori’s model follows the same principle: AI composes; your server approves.

Example: TypeScript validation pipeline

Assume your backend receives AI‑generated UI at:

  • POST /uzori/ui/validate

Here is a concrete TypeScript example using zod for schema validation.

import { z } from "zod";
import { verifyUzoriSignature } from "./uzori-signature";
import { fetchCurrentPlan, fetchRecommendations } from "./plans";

// 1. Define UI schema
const ButtonActionSchema = z.object({
type: z.literal("api_call"),
operationId: z.enum(["changePlan"]),
params: z.record(z.any()).optional()
});

const ComponentSchema: z.ZodType<any> = z.lazy(() =>
z.union([
z.object({
type: z.literal("text"),
style: z.enum(["title", "body", "caption"]).optional(),
value: z.string()
}),
z.object({
type: z.literal("table"),
columns: z.array(z.string()),
rows: z.array(z.array(z.string()))
}),
z.object({
type: z.literal("button"),
id: z.string(),
label: z.string(),
action: ButtonActionSchema
}),
z.object({
type: z.enum(["vstack", "hstack"]),
children: z.array(z.lazy(() => ComponentSchema))
})
])
);

const ScreenSchema = z.object({
id: z.string(),
layout: ComponentSchema
});

const UzoriUIPayloadSchema = z.object({
schemaVersion: z.literal("1.0"),
screens: z.array(ScreenSchema)
});

// 2. Express handler
export async function validateUzoriUI(req, res) {
try {
// 2a. Verify signature/nonce (replay protection)
const signature = req.headers["x-uzori-signature"] as string;
const nonce = req.headers["x-uzori-nonce"] as string;

if (!verifyUzoriSignature(req.rawBody, signature, nonce)) {
return res.status(401).json({ error: "invalid_signature" });
}

// 2b. Parse and validate schema
const result = UzoriUIPayloadSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({
error: "schema_validation_failed",
details: result.error.issues
});
}

const payload = result.data;

// 2c. Apply business rule checks
const hasChangePlanButton = payload.screens.some((screen) =>
findButton(screen.layout, (btn) => btn.action.operationId === "changePlan")
);

if (hasChangePlanButton) {
// Example rule: require current plan and recommendations loaded
const userId = req.headers["x-user-id"] as string;
const currentPlan = await fetchCurrentPlan(userId);
const recs = await fetchRecommendations(userId);

if (!currentPlan || recs.length === 0) {
return res.status(409).json({
error: "business_rule_failed",
code: "NO_RECOMMENDATIONS"
});
}
}

// 2d. Attach server metadata or signatures if needed
const signedPayload = {
...payload,
serverSignature: signPayload(payload)
};

return res.status(200).json({
status: "approved",
ui: signedPayload
});
} catch (err) {
console.error("Uzori UI validation error", err);

// 2e. Fallback UI response
return res.status(200).json({
status: "fallback",
ui: buildFallbackPlanComparisonUI()
});
}
}

function findButton(component, predicate): any | null {
if (component.type === "button" && predicate(component)) return component;
if (component.children) {
for (const child of component.children) {
const found = findButton(child, predicate);
if (found) return found;
}
}
return null;
}

// 3. Fallback UI builder
function buildFallbackPlanComparisonUI() {
return {
schemaVersion: "1.0",
screens: [
{
id: "fallback-plan-comparison",
layout: {
type: "vstack",
children: [
{ type: "text", style: "title", value: "Plan comparison is unavailable" },
{ type: "text", style: "body", value: "You can still view your current plan and explore options below." },
// Optionally include a static link to existing SDUI comparison view
]
}
}
]
};
}

4.1 Uzori validation error codes

For consistency, define a small set of backend error codes for Uzori to react to:

  • invalid_signature — HMAC or signature mismatch
  • schema_validation_failed — UI payload not matching the contract
  • business_rule_failed — domain rules violated (e.g., plan not changeable)
  • NO_RECOMMENDATIONS — specific business rule subtype
  • fallback — your explicit fallback UI was used

Your iOS client doesn’t need to know all details; it only needs to show whatever validated UI comes back.

Step 5: Connect Uzori to your existing SDUI pipeline

Most telecoms already have server‑driven UI in some form (e.g., DivKit, custom JSON layouts). Uzori should plug in beside — not replace — that system.

Approach

  • Treat Uzori as an AI composition layer on top of your SDUI schema.
  • Reuse your existing components (cards, tables, buttons) by exposing them in Uzori’s schema.
  • Route Uzori UI payloads through the same layout renderer when possible.

Example: SwiftUI hosting existing SDUI views

If you have a ServerDrivenView that can render JSON layouts, you can embed it inside UzoriScreen or vice versa:

struct HybridPlanComparisonView: View {
let uzoriClient: UzoriClient

var body: some View {
UzoriScreen(
client: uzoriClient,
sessionId: "plan-comparison",
onFallback: { fallbackUI in
// Render fallbackUI via your existing SDUI renderer
ServerDrivenView(layout: fallbackUI)
}
)
}
}

This way, your one screen to integrate can fan out into many flows while staying aligned with your SDUI architecture.

Step 6: Design a comparison‑first “Am I on the right plan?” flow

Now that the plumbing is ready, let’s design the UX.

Flow outline

  1. Entry point
    • From Account → “Help with my plan”
    • Or a proactive banner: “Unsure if you’re on the best plan?”
  2. Question capture
    • Simple input or quick button: “Am I on the right plan?”
    • Pass this as context into UzoriScreen.
  3. Plan comparison view
    • Show side‑by‑side cards or a table:
      • Current plan
      • 1–3 recommended plans
    • Columns: monthly cost, data, minutes, roaming, perks.
  4. Actionable CTA
    • “Switch to this plan” button wired to changePlan.
    • Optional: show fees, pro‑rated amounts.
  5. Status confirmation
    • Use a status‑first pattern similar to our transaction dispute guide, e.g., four steps: request received → eligibility → scheduled date → confirmation.

SwiftUI example: static comparison stub

You can prototype the layout locally before connecting Uzori:

struct PlanComparisonStaticView: View {
struct Plan: Identifiable {
let id: String
let name: String
let price: String
let data: String
let roaming: String
}

let current = Plan(id: "current", name: "5G Essentials", price: "$60", data: "20 GB", roaming: "No")
let recommended = Plan(id: "rec1", name: "5G Plus", price: "$55", data: "25 GB", roaming: "Yes")

var body: some View {
VStack(alignment: .leading, spacing: 16) {
Text("Am I on the right plan?")
.font(.title).bold()

HStack(alignment: .top, spacing: 12) {
planCard(title: "Current", plan: current)
planCard(title: "Recommended", plan: recommended)
}

Button("Switch to recommended") {
// Wire to changePlan endpoint via Uzori later
}
.buttonStyle(.borderedProminent)

Spacer()
}
.padding()
}

func planCard(title: String, plan: Plan) -> some View {
VStack(alignment: .leading, spacing: 8) {
Text(title).font(.caption).textCase(.uppercase)
Text(plan.name).font(.headline)
Text(plan.price).font(.title3)
Text("Data: \(plan.data)")
Text("Roaming: \(plan.roaming)")
}
.padding()
.background(RoundedRectangle(cornerRadius: 12).strokeBorder())
}
}

Once the layout feels right, encode the same structure in your Uzori schema so the AI can compose variations on this pattern.

Step 7: Ethical AI & privacy best practices for iOS apps (Uzori, secure AI app architecture)

Security and privacy are non‑negotiable in telecom. Deloitte notes that consumers want AI experiences but will favor providers that show transparency, control, and data security ("2025 Connectivity and Mobile Trends Survey", Deloitte Insights, 2025, https://www.deloitte.com/us/en/insights/industry/telecommunications/connectivity-mobile-trends-survey.html).

Here are concrete best practices when using Uzori or any AI UI SDK SwiftUI iOS setup.

Data minimization & PII handling

  • Send only the minimum attributes the model needs (e.g., usage buckets, anonymized IDs).
  • Avoid raw PII (addresses, full names) in prompts; use aliases or tokens.
  • Keep PII processing on your own backend where possible.

In‑transit and at‑rest encryption

  • Use TLS 1.2+ for all app ↔ backend and backend ↔ Uzori calls.
  • Encrypt sensitive logs and state at rest using KMS‑managed keys.
  • Rotate Uzori API keys regularly and store them in secure config (e.g., Keychain / Secrets Manager).

Model access controls

  • Restrict who can configure prompts and schemas (RBAC on the Uzori admin side).
  • Use separate environments (dev, staging, prod) with distinct keys.
  • Log every change to your UI schema and OpenAPI maps.

Logging and redaction

  • Redact:
    • Phone numbers
    • Account IDs
    • Payment tokens
  • Prefer logging event types and outcome codes over raw prompts or responses.
  • If you must log UI payloads, strip user‑specific fields first.

Consent UX and regional compliance (GDPR/CCPA)

  • Provide a clear opt‑in for AI assistance in regions where required.
  • Explain what data feeds the AI (“We use your usage data and plan details to suggest better plans”).
  • Allow an easy opt‑out and a non‑AI path (e.g., a standard SDUI comparison screen).
  • For GDPR regions:
    • Establish lawful basis (often legitimate interest + clear explanation).
    • Provide data subject rights flows (access, deletion) that cover AI logs.
  • For CCPA/CPRA (California):
    • Respect “Do Not Sell or Share” preferences.
    • Classify AI telemetry correctly (analytics vs personalized offers).

Uzori’s role: Uzori is designed as a native AI interface layer. It does not require you to send arbitrary logs to third parties; you control what data flows into prompts and schemas.

Uzori vs DivKit: when to use which server‑driven UI approach

Many teams search for Uzori vs DivKit or server‑driven UI iOS frameworks/tools. They solve related but different problems.

Comparison table

Comparison table infographic showing differences between Uzori and DivKit server-driven UI frameworks for iOS

This table highlights how Uzori and DivKit differ across use cases, platforms, and how they fit into a server-driven UI architecture.

  • Primary use case — Uzori: AI‑composed, conversational SwiftUI flows; DivKit: Generic server‑driven layout rendering
  • Platforms — Uzori: iOS (SwiftUI‑first); DivKit: iOS, Android, Web (Kotlin/Swift/JS)
  • Core value — Uzori: Turn LLM intent into native SwiftUI screens; DivKit: Render JSON‑described layouts from backend
  • Generative vs static — Uzori: Generative UI : AI designs layouts; DivKit: Static SDUI : server defines all layouts
  • Safety model — Uzori: AI composes; server validates via typed schema; DivKit: Backend controls JSON; no AI in the loop
  • Offline support — Uzori: Depends on your caching strategy; DivKit: Better suited for pre‑cached layouts
  • Extensibility — Uzori: Extend schema with your components; DivKit: Extend via custom widgets/blocks
  • Licensing — Uzori: Uzori SaaS/SDK; DivKit: DivKit open‑source (Apache‑2.0)
  • Best for — Uzori: AI concierge, dynamic wizards, comparison flows; DivKit: Static content, banners, forms, non‑AI SDUI
  • Migration pattern — Uzori: Layer AI over existing SDUI; reuse components; DivKit: Good base SDUI; can feed schemas into Uzori

How to combine Uzori and DivKit

  • Use DivKit for:
    • Static promo banners
    • Marketing layouts
    • Simple forms where AI is unnecessary
  • Use Uzori for:
    • “Am I on the right plan?” comparisons
    • Guided setup wizards
    • AI concierges that orchestrate multi‑step flows

If you already have DivKit, expose its components as part of your Uzori schema so AI can compose with the same building blocks.

Uzori SDK reference (quick cheat sheet)

  • SPM URL: https://github.com/uzori-ai/uzori-ios-sdk.git
  • Key types:
    • UzoriClient(apiKey:endpoint:)
    • UzoriScreen(client:sessionId:context:onFallback:)
    • UzoriError.network, UzoriError.validationFailed, UzoriError.sessionExpired
  • Request shape (client → Uzori):
    • Includes sessionId, context (userId, entryPoint), and optional conversation history.
  • Response shape (Uzori → backend → client):
    • schemaVersion: String
    • screens: [UzoriScreenDescriptor]
    • UzoriScreenDescriptor.id: String
    • UzoriScreenDescriptor.layout: UzoriLayout (tree of typed components)
  • Validation endpoint (backend):
    • POST /uzori/ui/validate
  • Error codes (backend → Uzori):
    • invalid_signature, schema_validation_failed, business_rule_failed, fallback

This is enough to wire a test project end‑to‑end.

Putting it all together: from question to native comparison screen

To recap the minimal path:

  1. Add Uzori SDK via SPM and embed UzoriScreen in your SwiftUI app.
  2. Define OpenAPI endpoints /plans/current, /plans/recommended, /plans/change.
  3. Design a UI schema that mirrors your existing SDUI components.
  4. Implement server‑side validation with typed schemas, business rules, signature/nonce checks, and a fallback UI.
  5. Launch a pilot: hide the new flow behind a feature flag and compare to your existing plan comparison path.

You’ve now compressed weeks of UI iteration into a streaming, AI‑driven interface that designs itself, while keeping safety and structure firmly under your control.

FAQ: AI UI SDK SwiftUI iOS, Uzori, and server‑driven UI

1. How is Uzori different from just adding a chat bot to my iOS app?

Uzori doesn’t stop at text. It turns AI intent into SwiftUI screens — tables, forms, wizards — that are validated by your server. Users interact with native controls, not scroll long chat transcripts.

2. Can I use Uzori with UIKit instead of SwiftUI?

Uzori is SwiftUI‑first. You can integrate it into a UIKit app via UIHostingController, mounting UzoriScreen inside an existing navigation stack.

3. Does Uzori replace my existing server‑driven UI stack?

No. Uzori complements SDUI by adding a generative layer on top of your existing components and schemas. Use SDUI for static layouts and Uzori for dynamic, AI‑driven flows.

4. How do I test Uzori flows safely in telecom environments?

  • Start in a staging environment with anonymized data.
  • Use feature flags to limit rollout.
  • Add detailed logging for validation outcomes (but redact PII).
  • Run A/B tests comparing existing plan comparison flows to the Uzori‑driven one.

5. What if the AI suggests a plan I don’t want users to see?

Your server‑side validation step is the gatekeeper. Enforce business rules (e.g., allowed SKUs, eligibility criteria) before any UI hits the client, and fall back to a safe, static screen when rules fail.

If you’re ready to move beyond chat boxes and into AI‑native interfaces, Uzori gives your iOS team one screen to integrate and infinite flows to explore — starting with the question users ask every month: “Am I on the right plan?”

← All posts