Quickstart
Add body scanning to your iOS app: capture, on-device measurement, and the full member experience — results, history, trends, sharing. Your member's measurements are computed on their phone and stay there.
1. Install the SDK
In Xcode: File → Add Package Dependencies, paste the package URL, pick the latest version. Requires iOS 17; your app builds and runs in the Simulator, and real scans need a Face ID iPhone.
https://github.com/Visualize-KK/visualize-sdk2. Get your keys
The portal issues a key pair per app. The publishable key pk_live_… ships in your app. The secret key sk_live_… stays on your server — it is shown once at issuance and never again.
Team ID.Bundle ID; if the portal values don't match your built app, every scan is refused with an attestation error — and the message won't point at the bundle, so it's a hard one to guess. Copy both straight from Xcode's Signing & Capabilities.3. Mint a session token on your server
Your backend exchanges the secret key for a short-lived session token per member action. host_user_ref is your own stable ID for the member — it is also how billing counts a monthly active user, so keep it consistent.
curl https://api.visualizeme.ai/v1/sessions \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{"host_user_ref": "user_842"}'
# 201
# {"session_token": "vst_...", "expires_at": "2026-09-16T12:15:00Z"}4. Present the scanner
Configure once at launch, then present the member home — it handles preparation, the scan flow, results, history, and trends. The token provider closure is called once per preparation and once per scan; mint a fresh token from your backend each time.
import VisualizeSDK
// At launch. The key can live in Info.plist instead (VZPublishableKey).
await Visualize.configure(
.init(publishableKey: "pk_live_..."),
engine: AVIXScanEngine())
// Wherever your UI offers scanning:
Visualize.presentHome(from: viewController) {
try await myBackend.mintSessionToken() // your server, step 3
}The first scan on a device downloads the ~180 MB model bundle, once — cached, resumable, Wi-Fi by default, updated over the air. Details and the prepare() call that moves the wait into onboarding: Scanning → Preparation and the model download.
Prefer your own results UI? Call Visualize.startScan(sessionToken:presentingFrom:) directly — it returns a ScanResult with the measurements. See Scanning.
5. Receive scan outcomes
Set a webhook URL on your app in the portal and your backend receives a signed scan.completed event for every scan — the verified record you can bill and build on. See Webhooks.
Configuration
The SDK reads these from your app's Info.plist — set them from your xcconfig so nothing lives in source. The publishable key is required and has two homes: pass it in code, or set it here and configure with .fromHostConfiguration(). The other two only override defaults.
| Key | Meaning |
|---|---|
VZPublishableKey | Your pk_live_…, so it stays out of source. Alternative to passing it in code. |
VZEnvironment | production (the default), staging, or development. |
VZAPIBaseURL | An explicit API host, overriding VZEnvironment. Set it only if your onboarding instructions say so — pilot integrations receive a host here; removing the key returns the app to production. |
<key>VZPublishableKey</key>
<string>$(VZ_PUBLISHABLE_KEY)</string>
<!-- Required — capture uses the front TrueDepth camera. -->
<key>NSCameraUsageDescription</key>
<string>Scanning uses the front camera to measure your body.</string>VZ_PUBLISHABLE_KEY = pk_live_...Then configuring at launch needs no values in code at all:
try await Visualize.configureFromHostConfiguration(engine: AVIXScanEngine())Nothing set means production. An app shipped with no configuration reaches the real service rather than failing quietly.
Runnable samples
Two working samples — a minimal iOS app and a one-file Docker backend — take you from zero to a scan. The Run the samples guide walks through both, step by step.