iOS SDK
Integrate Klero feedback, roadmap, changelog, surveys, and widgets into your iOS app.
Requirements
- iOS 13.0+
- Swift 5.7+
- Xcode 14.0+
Installation
Swift Package Manager
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/klero-ai/klero-ios.git", from: "0.1.0")
]Or in Xcode: File > Add Package Dependencies and enter https://github.com/klero-ai/klero-ios.git.
Quick Start
Any Module with KleroEmbedView
KleroEmbedView is the generic embed view that supports all Klero module types.
import KleroSDK
let config = KleroConfig(projectSlug: "myproject")
// Feedback board
let feedback = KleroEmbedView(config: config, embedType: .feedback)
// Roadmap
let roadmap = KleroEmbedView(config: config, embedType: .roadmap)
// Changelog
let changelog = KleroEmbedView(config: config, embedType: .changelog)
// Widget (floating button with panel)
let widget = KleroEmbedView(config: config, embedType: .widget)Add to your view hierarchy:
feedback.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(feedback)
NSLayoutConstraint.activate([
feedback.topAnchor.constraint(equalTo: view.topAnchor),
feedback.leadingAnchor.constraint(equalTo: view.leadingAnchor),
feedback.trailingAnchor.constraint(equalTo: view.trailingAnchor),
feedback.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])Survey with KleroSurvey
For surveys, use the dedicated KleroSurvey view which provides survey-specific event callbacks:
import KleroSDK
let config = KleroConfig(projectSlug: "myproject")
let survey = KleroSurvey(config: config, surveyUlid: "01ABC123...")
survey.delegate = self
view.addSubview(survey)Implement KleroSurveyDelegate:
extension ViewController: KleroSurveyDelegate {
func kleroSurveyDidComplete(surveyUlid: String, responseUlid: String, answers: [String: Any]) {
print("Completed: \(responseUlid)")
}
func kleroSurveyDidClose(surveyUlid: String, completed: Bool) {
print("Closed, completed: \(completed)")
}
func kleroSurveyDidError(surveyUlid: String, error: String) {
print("Error: \(error)")
}
}SwiftUI Integration
KleroEmbedView in SwiftUI
import SwiftUI
import KleroSDK
struct KleroEmbedSwiftUI: UIViewRepresentable {
let projectSlug: String
let embedType: KleroEmbedType
var customerToken: String?
var embedConfig: [String: Any] = [:]
func makeUIView(context: Context) -> KleroEmbedView {
let config = KleroConfig(
projectSlug: projectSlug,
customerToken: customerToken
)
return KleroEmbedView(config: config, embedType: embedType, embedConfig: embedConfig)
}
func updateUIView(_ uiView: KleroEmbedView, context: Context) {}
}
// Usage
struct FeedbackScreen: View {
var body: some View {
KleroEmbedSwiftUI(projectSlug: "myproject", embedType: .feedback)
}
}KleroSurvey in SwiftUI
struct KleroSurveySwiftUI: UIViewRepresentable {
let projectSlug: String
let surveyUlid: String
var customerToken: String?
var onComplete: ((String, String, [String: Any]) -> Void)?
func makeUIView(context: Context) -> KleroSurvey {
let config = KleroConfig(projectSlug: projectSlug, customerToken: customerToken)
let survey = KleroSurvey(config: config, surveyUlid: surveyUlid)
survey.delegate = context.coordinator
return survey
}
func updateUIView(_ uiView: KleroSurvey, context: Context) {}
func makeCoordinator() -> Coordinator { Coordinator(self) }
class Coordinator: NSObject, KleroSurveyDelegate {
let parent: KleroSurveySwiftUI
init(_ parent: KleroSurveySwiftUI) { self.parent = parent }
func kleroSurveyDidComplete(surveyUlid: String, responseUlid: String, answers: [String: Any]) {
parent.onComplete?(surveyUlid, responseUlid, answers)
}
func kleroSurveyDidClose(surveyUlid: String, completed: Bool) {}
func kleroSurveyDidError(surveyUlid: String, error: String) {}
}
}Authentication
Pass a customer token to identify logged-in users:
let config = KleroConfig(
projectSlug: "myproject",
customerToken: "your-jwt-token"
)See the Authentication Guide for token generation.
Custom Base URL
For self-hosted or custom domain setups:
let config = KleroConfig(
projectSlug: "myproject",
baseUrl: "https://feedback.mycompany.com"
)Widget Touch Passthrough
KleroEmbedView with .widget type automatically handles touch passthrough. When the widget panel is closed, only the trigger button area receives touches — all other touches pass through to views behind. When the panel is open, the entire view captures touches.
API Reference
KleroConfig
| Property | Type | Required | Description |
|---|---|---|---|
projectSlug | String | Yes | Your Klero project slug |
baseUrl | String? | No | Custom base URL |
customerToken | String? | No | JWT token for user identification |
KleroEmbedType
| Case | Description |
|---|---|
.feedback | Feedback board |
.roadmap | Product roadmap |
.changelog | Changelog / release notes |
.widget | Floating widget with panel |
.survey | Survey form |
KleroEmbedView
| Method | Description |
|---|---|
init(config:embedType:embedConfig:) | Create an embed view |
reload() | Reload the embed |
KleroSurvey
| Method | Description |
|---|---|
init(config:surveyUlid:) | Create a survey view |
open(surveyUlid:) | Open the survey |
close() | Close the survey |
reload() | Reload the survey |
KleroSurveyDelegate
| Method | Description |
|---|---|
kleroSurveyDidComplete(surveyUlid:responseUlid:answers:) | Survey completed |
kleroSurveyDidClose(surveyUlid:completed:) | Survey closed |
kleroSurveyDidError(surveyUlid:error:) | Survey failed to load |