Skip to content

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:

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.

swift
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:

swift
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:

swift
import KleroSDK

let config = KleroConfig(projectSlug: "myproject")
let survey = KleroSurvey(config: config, surveyUlid: "01ABC123...")
survey.delegate = self

view.addSubview(survey)

Implement KleroSurveyDelegate:

swift
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 ​

swift
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 ​

swift
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:

swift
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:

swift
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 ​

PropertyTypeRequiredDescription
projectSlugStringYesYour Klero project slug
baseUrlString?NoCustom base URL
customerTokenString?NoJWT token for user identification

KleroEmbedType ​

CaseDescription
.feedbackFeedback board
.roadmapProduct roadmap
.changelogChangelog / release notes
.widgetFloating widget with panel
.surveySurvey form

KleroEmbedView ​

MethodDescription
init(config:embedType:embedConfig:)Create an embed view
reload()Reload the embed

KleroSurvey ​

MethodDescription
init(config:surveyUlid:)Create a survey view
open(surveyUlid:)Open the survey
close()Close the survey
reload()Reload the survey

KleroSurveyDelegate ​

MethodDescription
kleroSurveyDidComplete(surveyUlid:responseUlid:answers:)Survey completed
kleroSurveyDidClose(surveyUlid:completed:)Survey closed
kleroSurveyDidError(surveyUlid:error:)Survey failed to load

Customer Feedback Management