Use Cases
Prefetching for feeds
Feed-style hosts often need to know whether an ad will fill before committing layout — see prefetch for the shared model. Koah.shared.requestAd returns a one-shot KoahAdResult you can drive layout from:
struct FeedRow: View {
let item: FeedItem
@State private var result: KoahAdResult?
var body: some View {
Group {
if case .filled = result {
KoahCard(
adContext: .feed(text: item.text, source: item.source),
cacheKey: item.id
)
} else if result == nil {
ReservedSlot() // loading
}
// .noFill / .error: collapse (EmptyView)
}
.task(id: item.id) {
result = await Koah.shared.requestAd(
adContext: .feed(text: item.text, source: item.source),
cacheKey: item.id
)
}
}
}
If you don't need explicit reserve/collapse layout — just "show an ad if one's available, otherwise nothing" — skip the requestAd step entirely and call prefetchAd on first appear to warm the cache. KoahCard will render nothing on no-fill:
.task(id: item.id) {
Koah.shared.prefetchAd(
adContext: .feed(text: item.text, source: item.source),
cacheKey: item.id
)
}
| API | Use |
|---|---|
Koah.shared.requestAd(adContext:dimensions:cacheKey:) | Ask for an ad and wait for the answer. Use this when your layout depends on whether an ad fills — reserve height while it resolves, then either render the card or collapse the slot. Suspends, then returns a KoahAdResult: .filled(fromCache:), .noFill(fromCache:), or .error(message:fromCache:). |
Koah.shared.prefetchAd(adContext:dimensions:cacheKey:) | Warm the cache for a slot the user is about to see. Returns immediately with a Task<Void, Never>; the network call runs in the background. No impression fires until the ad is actually rendered. Concurrent calls for the same cacheKey share one in-flight fetch. |
Koah.shared.cancelPrefetchAd(cacheKey:) | Cancel an in-flight prefetch. Cached results are untouched. |
KoahCard(adContext:cacheKey:) | Render. Reads from the warmed cache on hit; renders nothing on no-fill. |
Impressions fire only once the rendered ad is actually displayed on screen, never during prefetch — see impressions.
Upgrading from 0.x? The legacy Koah.shared.prefetch / resolveAd /
cancelPrefetch primitives are removed in 1.0 — see the
migration guide.
Slots
Tag an ad request with a slot to break down your dashboard reporting by where the ad renders — a feed card, an in-article unit, a chat sidebar. Register your slots in the dashboard first, then pass a registered name as slot on requestAd or prefetchAd:
let result = await Koah.shared.requestAd(
adContext: .feed(text: item.text, source: item.source),
cacheKey: item.id,
slot: "in-article"
)
An unregistered slot resolves to no-fill (.noFill) and nothing
renders — register it in the dashboard before shipping. See
Slots for setup, naming rules, and reporting.