Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.kontext.so/llms.txt

Use this file to discover all available pages before exploring further.

This is the 5-minute integration walkthrough. Before you start, make sure you’ve completed Installation.

1. Create a session

The entry point is KontextAds.createSession(_:), which returns a Session you’ll use for the rest of the conversation lifecycle.
import KontextSwiftSDK

let session = KontextAds.createSession(SessionOptions(
    publisherToken: "<your-publisher-token>",
    userId: "user-1234",
    conversationId: "conv-5678",
    character: Character(
        id: "character-1234",
        name: "John Doe",
        avatarUrl: URL(string: "https://example.com/avatar.png")!,
        greeting: "Hello, how can I help you today?"
    ),
    advertisingId: nil, // optional — pass an IDFA you collected manually (SDK auto-collects when nil)
    vendorId: nil, // optional — pass an IDFV you collected manually (SDK auto-collects when nil)
    onEvent: { event in
        // Handle ad lifecycle events
        print("[kontext] \(event.name)")
    }
))
The session keeps userId, conversationId, and publisherToken fixed for its lifetime. Recreate the session when any of those change (e.g. when the user starts a new chat).
Session is @MainActor — call its methods from the main actor (default in SwiftUI views and @MainActor-isolated view controllers).

2. Feed conversation messages

Add every message to the session as it appears. User messages trigger a debounced preload in the background; assistant messages let the SDK link the matched ad to the corresponding placement.
session.addMessage(Message(
    id: "msg-1",
    role: .user,
    content: "Hello, how are you?",
    createdAt: Date()
))

session.addMessage(Message(
    id: "msg-2",
    role: .assistant,
    content: "I am good, thank you!",
    createdAt: Date()
))
addMessage returns synchronously. The preload result is delivered later via the onEvent callback (.filled, .noFill, .error, …) — not via a return value.

3. Render the ad

Use session.createAd(messageId:) to obtain an Ad for an assistant message, then render it with InlineAdUIView. createAd is idempotent: calling it repeatedly with the same messageId returns the same Ad. Cache the returned instance so view-controller / cell reuse doesn’t recreate it.
let ad = session.createAd("msg-2")
let adView = InlineAdUIView(ad: ad)
adView.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(adView)

// Inside a UITableView/UICollectionView cell, observe the height for proper sizing.
adView.onHeightChange = { [weak self] height in
    self?.updateRowHeight(height)
}

4. Tear down

Call destroy() when the conversation ends or the view disappears. Idempotent and required to cancel pending network requests and release web view resources.
session.destroy()

Observing events

Two equivalent ways to consume AdEvents — pick whichever fits your codebase.

onEvent callback

let session = KontextAds.createSession(SessionOptions(
    publisherToken: "...",
    userId: "...",
    conversationId: "...",
    onEvent: { event in
        switch event {
        case .filled(let data):
            print("ad filled: \(data.bidId) revenue=\(data.revenue ?? 0)")
        case .clicked(let data):
            print("clicked: \(data.url)")
        default: break
        }
    }
))

Combine publisher

import Combine

var cancellables: Set<AnyCancellable> = []

session.eventPublisher
    .sink { event in
        print("event: \(event.name)")
    }
    .store(in: &cancellables)
Both deliver the same events on the main thread. The complete event list lives in the API reference.