Skip to main content

Swift SDK

See how easy it is to integrate high-performance ads into your iOS app using our lightweight SDK.

Requirements

  • iOS 14.0+
  • Swift 5.9+
  • Xcode 15+

Migration Guide

Migrating from 1.x to 2.x

A new AdsEvent.cleared event has been added. If you handle AdsEvent with an exhaustive switch statement without a default case, you must add a handler for .cleared.
// Before
switch event {
case .filled(let ads):
    self.ads = ads
// ...
}

// After
switch event {
case .filled(let ads):
    self.ads = ads
case .cleared:
    self.ads = []
// ...
}

Getting started

1. Installation

To get started, you will need to set up a publisher account to get a publisherToken and code.
Swift Package Manager and CocoaPods are two currently supported ways of integrating KontextSwiftSDK into your project. The Swift Package Manager is the simplest way to add dependencies to your iOS app. Once the package is set up, add KontextSwiftSDK to your list of dependencies.
dependencies: [
    .package(url: "https://github.com/kontextso/sdk-swift", .upToNextMajor(from: "2.0.0")) /// Update to the latest version
]
Alternatively, you can use Xcode’s UI: File > Add Package Dependencies ... and paste the URL into the search field.

CocoaPods

If you prefer using CocoaPods, add the following line to your Podfile:
pod 'KontextSwiftSDK'
You can find the Podspec here.

2. Initialize AdsProvider

Once the dependency has been added and resolved, you can import the SDK. Next, create an instance of AdsProvider — the object responsible for managing ad loading and display. This is the most important part of the library, and it uses the previously created configuration.
import KontextSwiftSDK

let character = Character(
  id: "character-12345",
  name: "John Doe",
  avatarUrl: "https://example.com/avatar.png",
  greeting: "Hello, how can I help you today?"
)

let regulatory = Regulatory(
  coppa: 0,
  // ... other regulatory properties
)

let configuration = AdsProviderConfiguration(
  publisherToken: "<publisher-token>",
  userId: "user-1234",
  conversationId: "conv-5678",
  enabledPlacementCodes: ["inlineAd"],
  character: character,
  variantId: nil,
  adServerUrl: nil,
  regulatory: regulatory,
  otherParams: ["theme": "dark"]
)

let adsProvider = AdsProvider(
  // Previously created configuration (immutable and publicly accessible if needed later)
  configuration: configuration,
  // Optional delegate for receiving events via the delegate pattern. 
  delegate: self
)
You can also observe ad-related events through the eventPublisher property, which uses Combine for event streaming.

3. Set up IFA (Identifier for Advertisers)

The SDK automatically reads and forwards the IFA with each ad request once the user has granted permission. To enable this, you need to complete a one-time setup on each platform. Apple requires a usage description before the ATT (App Tracking Transparency) prompt can be shown. Add the following to your Info.plist:
<key>NSUserTrackingUsageDescription</key>
<string>We use your advertising identifier to show you more relevant ads.</string>
Without this key your app will crash on iOS 14+. The string is displayed in the system permission dialog, so make sure it clearly explains why tracking is needed.
By default, the SDK calls ATTrackingManager.requestTrackingAuthorization automatically. To avoid App Store rejection, ensure the prompt is triggered at a natural point in your app flow (e.g. after onboarding) rather than immediately on launch.
If your app manages the ATT prompt itself, set requestTrackingAuthorization: false in AdsProviderConfiguration to prevent the SDK from showing a second prompt. You can then pass the resolved IDFA directly via the advertisingId parameter.
let configuration = AdsProviderConfiguration(
  publisherToken: "<publisher-token>",
  userId: "user-1234",
  conversationId: "conv-5678",
  enabledPlacementCodes: ["inlineAd"],
  advertisingId: resolvedIDFA, // pass the IDFA you collected yourself
  requestTrackingAuthorization: false
)
The ATT prompt requires the app to be in an active state to appear. Initializing the SDK too early (e.g. in AppDelegate.didFinishLaunchingWithOptions) may silently suppress the prompt. Initialize the SDK only after the app becomes active.

4. Set up SKAdNetwork

SKAdNetwork (SKAN) is Apple’s privacy-preserving install attribution framework. To allow DSPs to measure ad conversions on iOS, you need to add their SKAdNetwork identifiers to your Info.plist.
<key>SKAdNetworkItems</key>
<array>
  <dict>
    <key>SKAdNetworkIdentifier</key>
    <string>XXX.skadnetwork</string>
  </dict>
  <!-- Add all provided identifiers here -->
</array>
The full list of required SKAdNetwork identifiers will be provided during onboarding. Make sure to add all of them, as missing an identifier means conversions from that DSP will not be attributed.
If your app already has an existing SKAdNetworkItems array, do not replace it — append the new identifiers to the existing list to avoid breaking attribution for other ad networks you may be running.

5. Prepare messages

Adapt your message object to provide the necessary information required for ad recommendations to work. You have two options: either make it conform to MessageRepresentable and return the respective properties, or make it conform to MessageRepresentableProviding and return a MessageRepresentable as a separate object. You can use the struct AdsMessage: MessageRepresentable for this purpose.
// 1) Conform directly to MessageRepresentable
struct MyChatMessage: MessageRepresentable {
	...
	/// Unique ID of the message
	var id: String { self.uuid.uuidString }
	/// Role of the author of the message (user or assistant)
	var role: Role { self.isUser ? .user : .assistant }
	/// Content of the message
	var content: String { self.messageContent }
	/// Timestamp when the message was created
	var createdAt: Date { self.date }
	...
}

// 2) Conform to MessageRepresentableProviding
// Useful if your model has name collisions or you prefer mapping fields in one place.
struct MyChatMessage: MessageRepresentableProviding {
	...
	var message: MessageRepresentable {
		AdsMessage(
			id: self.uuid.uuidString,
			role: self.isUser ? .user : .assistant,
			content: self.messageContent,
			createdAt: self.date
		)
	...	
}
Whenever your list of messages changes, pass the updated array to the AdsProvider.
adsProvider.setMessages(messages)

6. Show your first ad

The last step is to provide a place for the ads to appear. This is done by adding an InlineAdView to your view hierarchy, right after the corresponding message. The view automatically handles loading and displaying the ad.
@State private var ads: [Advertisement] = []

ZStack {
  ForEach(messages, id: \.uuid.uuidString) { message in
    VStack {
      MyChatMessageView(message)
      if let ad = ads.first, ad.messageId == message.id {
        // Display the advertisement
        InlineAdView(ad: ad)
      }
    }
  }
}.onReceive(adsProvider.eventPublisher) { event in
   // React to adsProvider events
	switch event {
    case .filled(let newAds):
      ads = newAds
    case .cleared:
      ads = []
    case .adHeight(let newAd):
      guard let index = ads.firstIndex(where: { $0.id == newAd.id }) else {
        return
      }
      ads[index] = newAd
    default:
      break
  }	
}
For UIKit usage, use InlineAdUIView instead and refer to the ExampleUIKit app.

API documentation

AdsProvider properties

configuration
AdsProviderConfiguration
required
The configuration of the AdsProvider.
isDisabled
boolean
If set to true, ad generation will be disabled initially. It can later be enabled by calling enable().
delegate
AdsProviderDelegate
Delegate that receives ad-related updates. Called on the main thread.

AdsProviderConfiguration properties

publisherToken
string
required
Your unique publisher token.
userId
string
required
Unique identifier that remains the same for the user’s lifetime (used for retargeting and rewarded ads).
userEmail
string
Email address of the user.
conversationId
string
required
Unique ID of the conversation.
enabledPlacementCodes
array
required
Placement codes enabled for the conversation. Example: ['inlineAd'].
character
object
required
Character object used in this conversation.
advertisingId
string
The IDFA (Identifier for Advertisers) collected by your app. When provided, this value takes priority over the one automatically collected by the SDK. Use this together with requestTrackingAuthorization: false when your app manages the ATT prompt itself.
vendorId
string
The IDFV (Identifier for Vendor) collected by your app. When provided, this value takes priority over the one automatically collected by the SDK. Falls back to UIDevice.current.identifierForVendor when not set.
requestTrackingAuthorization
boolean
Whether the SDK should automatically request ATT (App Tracking Transparency) authorization. Defaults to true. Set to false if your app manages the ATT prompt itself to prevent the SDK from showing a second prompt.
variantId
string
Publisher-provided identifier for the user cohort (for A/B testing).
regulatory
object
Regulatory object used in this conversation.TCF (Transparency and Consent Framework) signals — gdpr and gdprConsent — are handled automatically by the SDK if you have a TCF-compliant CMP (Consent Management Platform) integrated in your app. You do not need to set these manually.
otherParams
dictionary
An arbitrary key-value collection of values that the publisher can send. It varies per publisher, but all publishers should provide at least the theme parameter.

InlineAdView & InlineAdUIView properties

advertisement
object
Advertisement object describing the ad.

AdsEvent types

filled

The ad is available or ads have changed.
ads
array
required
Available advertisements.

cleared

Previously displayed ads have been removed. Triggered when a new user message arrives and a fresh preload is in progress. Clear any currently displayed ads from your UI when you receive this event.

noFill

adHeight

The height of a specific ad has been updated.
ad
Advertisement
required
Advertisement whose height has changed after render.

viewed

The user has viewed the ad.

clicked

The user has clicked the ad.

renderStarted

Triggered before the first token is received.

renderCompleted

Triggered after the last token is received.

error

Triggered when an error occurs.

videoStarted

Triggered when the video playback starts.

videoCompleted

Triggered when the video playback finishes.

rewardGranted

Triggered when the user receives a reward.

event

Any other event. Payload is a dictionary.

Guides

Handling no-fill events

You get notified when the ad is not available by subscribing to the noFill event.

Sizing the ad

Especially when using UIKit, the ad inside of UITableView or UICollectionView needs to be sized properly to be displayed correctly. You get notified about ad height changes by subscribing to the adHeight event. Size changes multiple times as the ad gets rendered and ultimately stops at the final height.