Reference
Theme properties, fonts, card options, configuration, and size constants for the Koah iOS SDK.
Theme properties
Set these on a KoahTheme applied via .koahTheme(_:).
| Property | Type | Default | Description |
|---|---|---|---|
colorScheme | KoahColorScheme | .auto | .light / .dark / .auto (follow device) |
accentColor | Color? | nil → #0D0D0D | CTA button and accent color. Text-on-accent is computed automatically for contrast — never expose it. |
font | KoahFont? | nil (inherits from app) | Typeface, optional uniform weight override, and optional Font.Design. Sizes are SDK-locked per element. |
cornerRadius | CGFloat | 19 | Card corner radius. |
Text colors, spacing, and component-level radii are derived internally from these inputs and are not publicly configurable. KoahColorScheme.auto resolves at render time via SwiftUI's \.colorScheme environment, so flipping the device theme re-resolves naturally.
Fonts
KoahFont gives explicit control over typeface, weight, and Font.Design while keeping per-element font sizes locked by the SDK:
// System font (default San Francisco)
.koahTheme(KoahTheme(font: .system(weight: .regular)))
// System font with a design variant
.koahTheme(KoahTheme(font: .system(weight: .medium, design: .rounded)))
// Custom font shipped with your app
.koahTheme(KoahTheme(font: .custom("Inter", weight: .regular)))
Migrating from 0.6.x? KoahTheme.fontFamily: Font? is replaced with
KoahTheme.font: KoahFont?. fontFamily: yourFont becomes font: .custom("YourFont", weight: .regular) (or .system(weight:design:) for a
system face).
Card sizing
Bound each axis of a KoahCard with the width and height parameters, both KoahAxisSize?:
KoahCard(
adContext: .conversation(question: q, answer: a),
width: .fill,
height: .range(max: 420),
cacheKey: "msg-1"
)
| Value | Behavior |
|---|---|
nil (omit) | Unbounded — the card wraps its content within the parent's own bounds, keeping the most formats in play. |
.fixed(320) | Force the axis to an exact size in points. |
.range(min:max:) | Wrap content within bounds; min is a floor, max a pure ceiling. .range(max:) / .range(min:) set a single bound. |
.fill | Fill the parent's available space along this axis. Requires the parent to bound that axis — traps at layout on a scroll axis. |
An ad is never shown clipped — if the slot turns out too short for the format the server picked, it renders nothing and .slotTooSmall fires once. Leaving axes unbounded allows more ad formats, improving fill.
Migrating from 0.9.x? KoahAdOptions and KoahAdSize are removed, and
overrideMaxWidth / overrideMaxHeight are deprecated in 0.10 and removed
in 1.0 — map them to
width: .range(max:) / height: .range(max:). Koah.shared.configure's
debug: flag is now logLevel:, KoahAdResult is a three-case enum instead
of a filled flag, and preview requests are spelled
requestPreviewAd(previewFormat:cacheKey:). For the full 0.x → 1.0 upgrade
path, see the migration guide.
Presentation and performance
Starting with 1.1.0, server-controlled presentation on iOS lets us test and refine ad experiences faster. Keep using the existing KoahCard API; no additional integration step is needed.
Image caching improves performance automatically, with no additional configuration.
Event handling
The onEvent callback on KoahCard reports ad lifecycle events. Handle the cases your surface cares about:
KoahCard(
adContext: .conversation(question: q, answer: a),
cacheKey: messageId,
onEvent: { event in
switch event {
case .noAdFill: break // no inventory
case .adServed: break // ad delivered
case .impressionTracked: break // impression accepted by Koah
case .adViewed: break // 50% visible for 1 second
case .adClicked: break // user tapped
case .inAppBrowserClosed: break // in-app browser dismissed
case .slotTooSmall: break // ad can't fit the slot; nothing renders
default: break
}
}
)
Configuration
Pass these to Koah.shared.configure:
Koah.shared.configure(
publisherId: "your-publisher-id", // Required
baseUrl: "https://staging.koahlabs.app", // Optional — defaults to production
logLevel: .debug // Optional — defaults to .none
)
| Parameter | Type | Default | Description |
|---|---|---|---|
publisherId | String | — | Required. From your publisher dashboard. |
baseUrl | String | production | Override for staging or local environments. |
logLevel | KoahLogLevel | .none | Logging verbosity: .none / .error / .warning / .info / .debug. |
Sample ads
The KoahSampleAd family renders a representative ad with no network fetch — for SwiftUI previews, demo galleries, and snapshot tests. Construct one by hand or use the ready-made specimens, then pass it to KoahCard(sample:):
KoahCard(sample: .poll, cacheKey: "preview", koah: .preview)
Specimens: .card, .image, .poll, .expandable. Sample-backed cards never call the network and never report impressions.
Age range buckets
Available KoahAgeRange buckets for visitor attributes:
.under13 is accepted for compatibility but ignored by SDK versions later than 0.10.0 — see Children's privacy.
Gender and income values
Available values for visitor attributes:
| Attribute | Type | Values |
|---|---|---|
| Gender | KoahGender | .male / .female / .unknown |
| Income | KoahIncomeBracket | .under50k / .income50kTo100k / .income100kTo150k / .income150kTo200k / .income200kPlus / .unknown |
Brackets are annual household income in thousands of USD. .unknown clears the locally stored value.