Get the Pillow SDK running in your iOS app in a few minutes.
Prerequisites
iOS 16.0+
A publishable API key — see Apps and API keys to create one
A study set to live mode — copy its ID from the Integration tab
Installation
In Xcode, go to File > Add Package Dependencies and enter the repository URL:
https://github.com/trypillow/pillow-ios-sdk.git
Select version 0.1.3 or later, then add PillowSDK to your target.
You only need to add the Swift Package and import PillowSDK in your app code. Do not copy any SDK source files into your project.
Initialize the SDK
Call initialize() once at app startup, typically in your AppDelegate or app entry point:
import PillowSDK
PillowSDK.shared. initialize ( publishableKey : "pk_live_..." )
Initialize the SDK once during app startup and avoid calling it repeatedly from view code.
Present your first study
Show a study to the user by calling present(study:):
PillowSDK.shared. present (
study : PillowStudy ( id : "your-study-id-here" )
)
The study opens as a modal overlay. The user can complete the conversation and dismiss it when done.
Enable microphone (optional)
If your study uses voice input, add the microphone usage description to your Info.plist:
< key >NSMicrophoneUsageDescription</ key >
< string >This app uses the microphone for voice-based research conversations.</ string >
If you skip this step, the microphone button won’t appear in studies that support voice input.
Full example (SwiftUI)
import SwiftUI
import PillowSDK
@main
struct MyApp : App {
init () {
PillowSDK.shared. initialize ( publishableKey : "pk_live_..." )
PillowSDK.shared. setExternalId ( externalId : "user_123" )
PillowSDK.shared. setUserProperty ( key : "plan" , stringValue : "pro" )
}
var body: some Scene {
WindowGroup {
ContentView ()
}
}
}
struct ContentView : View {
@State private var studyCoordinator: StudyPresentationCoordinator ?
@State private var statusMessage = "Ready"
var body: some View {
VStack ( spacing : 16 ) {
Text (statusMessage)
Button ( "Start feedback" ) {
presentStudy ()
}
}
}
private func presentStudy () {
let coordinator = StudyPresentationCoordinator (
onPresented : { study in
statusMessage = "Study \(study. id ) is on screen"
},
onFinished : { study in
statusMessage = "Study \(study. id ) finished"
studyCoordinator = nil
},
onFailed : { study, error in
statusMessage = "Failed to load \(study. id ) : \(error. localizedDescription ) "
studyCoordinator = nil
}
)
studyCoordinator = coordinator
PillowSDK.shared. present (
study : PillowStudy ( id : "your-study-id-here" ),
delegate : coordinator
)
}
}
private final class StudyPresentationCoordinator : PillowStudyDelegate {
private let onPresented: (PillowStudy) -> Void
private let onFinished: (PillowStudy) -> Void
private let onFailed: (PillowStudy, Error ) -> Void
init (
onPresented : @escaping (PillowStudy) -> Void = { _ in },
onFinished : @escaping (PillowStudy) -> Void = { _ in },
onFailed : @escaping (PillowStudy, Error ) -> Void = { _ , _ in }
) {
self .onPresented = onPresented
self .onFinished = onFinished
self .onFailed = onFailed
}
func studyDidPresent ( _ study: PillowStudy) {
Task { @MainActor in
onPresented (study)
}
}
func studyDidFinish ( _ study: PillowStudy) {
Task { @MainActor in
onFinished (study)
}
}
func studyDidFailToLoad ( _ study: PillowStudy, error : Error ) {
Task { @MainActor in
onFailed (study, error)
}
}
}
If you do not need lifecycle callbacks, you can call present(study:) directly without a delegate.
Full example (UIKit)
import UIKit
import PillowSDK
class ViewController : UIViewController {
override func viewDidLoad () {
super . viewDidLoad ()
PillowSDK.shared. initialize ( publishableKey : "pk_live_..." )
PillowSDK.shared. setExternalId ( externalId : "user_123" )
}
@IBAction func startStudy () {
PillowSDK.shared. present (
study : PillowStudy ( id : "your-study-id-here" )
)
}
}
What’s next?
Identify users Set external IDs and user properties.
Present studies Control when and how studies appear.
Session management Handle logout and session lifecycle.