SDK Documentation
Cuti-E provides native SDKs for iOS and Android that let you collect user feedback directly in your mobile app. The SDKs handle creating conversations, sending messages, and receiving push notifications - all with minimal code.
Getting Started: You need an App ID from the Admin Dashboard.
Go to Settings → Apps to create your app and get your App ID.
Quick Start
Choose your platform to get started in under 5 minutes:
1. Add the Package
In Xcode, go to File → Add Package Dependencies and enter:
https://github.com/cuti-e/ios-sdk
2. Configure the SDK
import CutiE
// In AppDelegate or @main App
CutiE.shared.configure(appId: "app_your_app_id_here")
3. Show Feedback Form
import SwiftUI
import CutiE
struct ContentView: View {
@State private var showFeedback = false
var body: some View {
Button("Send Feedback") {
showFeedback = true
}
.sheet(isPresented: $showFeedback) {
CutiEFeedbackView { conversationId in
print("Submitted: \(conversationId)")
}
}
}
}
The feedback form allows users to submit bug reports, feature requests, and general feedback.
1. Add the Dependency
In your settings.gradle.kts, add JitPack:
dependencyResolutionManagement {
repositories {
maven { url = uri("https://jitpack.io") }
}
}
Then add the dependency in build.gradle.kts:
dependencies {
implementation("com.github.Stig-Johnny.cutie:cutie:1.0.0")
}
2. Configure the SDK
import com.cutie.sdk.CutiE
// In your Application class
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
CutiE.getInstance(this).configure(
appId = "app_your_app_id_here"
)
}
}
3. Show Feedback Form
import com.cutie.sdk.CutiEFeedbackView
@Composable
fun MyScreen() {
var showFeedback by remember { mutableStateOf(false) }
Button(onClick = { showFeedback = true }) {
Text("Send Feedback")
}
if (showFeedback) {
CutiEFeedbackView(
onDismiss = { showFeedback = false },
onSuccess = { conversationId ->
println("Submitted: $conversationId")
}
)
}
}
Configuration Options
| Option | Type | Description |
|---|---|---|
appId |
String | Your App ID from the admin dashboard (required) |
apiURL |
String | API endpoint (default: production server) |
Testing: Use the sandbox environment for development:
apiURL: "https://cutie-worker-sandbox.invotekas.workers.dev"
iOS Installation
Swift Package Manager
Add Cuti-E to your project using Xcode:
- File → Add Package Dependencies...
- Enter:
https://github.com/cuti-e/ios-sdk - Choose version or branch
- Add to your target
Manual Installation
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/cuti-e/ios-sdk.git", from: "1.0.104")
],
targets: [
.target(
name: "YourTarget",
dependencies: ["CutiE"]
)
]
Requirements
- iOS 15.0+ / macOS 12.0+
- Swift 5.9+
- Xcode 15.0+
iOS Basic Usage
Create a Conversation (Callback)
CutiE.shared.createConversation(
category: .bug,
message: "The app crashes when I tap save",
title: "Crash on Save"
) { result in
switch result {
case .success(let conversationId):
print("Created: \(conversationId)")
case .failure(let error):
print("Error: \(error.localizedDescription)")
}
}
List Conversations (iOS 15+)
// Using async/await
let conversations = try await CutiE.shared.getConversations()
for conv in conversations {
print("\(conv.title ?? "Untitled") - \(conv.status)")
}
Send a Message (iOS 15+)
// Using async/await
let message = try await CutiE.shared.sendMessage(
conversationId: "conv_abc123",
message: "Thanks for the help!"
)
iOS Feedback View
The SDK includes a ready-to-use SwiftUI feedback form:
import SwiftUI
import CutiE
struct SettingsView: View {
@State private var showFeedback = false
var body: some View {
List {
Button("Send Feedback") {
showFeedback = true
}
}
.sheet(isPresented: $showFeedback) {
CutiEFeedbackView { conversationId in
// Called when feedback is submitted
print("Created conversation: \(conversationId)")
}
}
}
}
iOS In-app Inbox
Let users view their feedback conversations and admin replies directly in your app (iOS 15+).
The inbox shows all conversations and allows users to continue chatting with support.
UX Best Practice: Add an inbox icon to your navigation bar so users can easily access their feedback from anywhere in your app. Don't bury it deep in Settings!
Recommended: Navigation Bar Icon with Badge
Add a persistent inbox icon with an unread message badge in your main view's navigation bar:
import SwiftUI
import CutiE
struct MainView: View {
@State private var showInbox = false
@State private var showFeedback = false
@State private var unreadCount = 0
var body: some View {
NavigationView {
YourContentView()
.navigationTitle("Home")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
HStack(spacing: 16) {
// Inbox button with badge
Button { showInbox = true } label: {
ZStack(alignment: .topTrailing) {
Image(systemName: "tray.full")
if unreadCount > 0 {
Text(unreadCount > 99 ? "99+" : "\(unreadCount)")
.font(.system(size: 10, weight: .bold))
.foregroundColor(.white)
.padding(.horizontal, 5)
.padding(.vertical, 2)
.background(Color.red)
.clipShape(Capsule())
.offset(x: 8, y: -8)
}
}
}
// Submit feedback button
Button { showFeedback = true } label: {
Image(systemName: "exclamationmark.bubble")
}
}
}
}
.sheet(isPresented: $showInbox) {
CutiEInboxView()
}
.sheet(isPresented: $showFeedback) {
CutiEFeedbackView { _ in }
}
.task {
await loadUnreadCount()
}
}
}
private func loadUnreadCount() async {
guard CutiE.shared.isConfigured else { return }
do {
unreadCount = try await CutiE.shared.getUnreadCount()
} catch {
print("Failed to load unread count: \(error)")
}
}
}
Alternative: Settings Menu
struct SettingsView: View {
@State private var showInbox = false
var body: some View {
List {
Button("My Feedback") {
showInbox = true
}
}
.sheet(isPresented: $showInbox) {
CutiEInboxView()
}
}
}
UIKit Integration
// Present inbox modally from any view controller
CutiE.shared.showInbox()
// Or from a specific view controller
CutiE.shared.showInbox(from: viewController)
Async/Await API
// Get all conversations
let conversations = try await CutiE.shared.getConversations()
// Get single conversation with messages
let conversation = try await CutiE.shared.getConversation(id: "conv_abc123")
// Send a reply
let message = try await CutiE.shared.sendMessage(
conversationId: "conv_abc123",
message: "Thanks for the help!"
)
// Get unread message count (for badge display)
let unreadCount = try await CutiE.shared.getUnreadCount()
Android Installation
Gradle (via JitPack)
Add JitPack to your root settings.gradle.kts:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}
Add the dependency to your app's build.gradle.kts:
dependencies {
implementation("com.github.Stig-Johnny.cutie:cutie:1.0.0")
}
Requirements
- Android 7.0 (API 24) or higher
- Kotlin 1.9+
- Gradle 8.0+
Android Basic Usage
Create a Conversation
CutiE.getInstance(context).createConversation(
category = ConversationCategory.BUG,
message = "The app crashes when I tap save",
title = "Crash on Save"
) { result ->
result.onSuccess { conversation ->
println("Created: ${conversation.id}")
}.onFailure { error ->
println("Error: ${error.message}")
}
}
List Conversations
CutiE.getInstance(context).listConversations { result ->
result.onSuccess { conversations ->
conversations.forEach { conv ->
println("${conv.title} - ${conv.status}")
}
}
}
Send a Message
CutiE.getInstance(context).sendMessage(
message = "Thanks for the help!",
conversationID = "conv_abc123"
) { result ->
// Handle result
}
Android Feedback View
The SDK includes a Jetpack Compose feedback form:
import com.cutie.sdk.CutiEFeedbackView
@Composable
fun SettingsScreen() {
var showFeedback by remember { mutableStateOf(false) }
Button(onClick = { showFeedback = true }) {
Text("Send Feedback")
}
if (showFeedback) {
Dialog(onDismissRequest = { showFeedback = false }) {
Surface(shape = MaterialTheme.shapes.large) {
CutiEFeedbackView(
onDismiss = { showFeedback = false },
onSuccess = { conversationId ->
println("Created: $conversationId")
}
)
}
}
}
}
Android In-app Inbox
Let users view their feedback conversations and admin replies directly in your app.
The inbox shows all conversations and allows users to continue chatting with support.
UX Best Practice: Add an inbox icon to your navigation bar so users can easily access their feedback from anywhere in your app. Don't bury it deep in Settings!
Basic Usage
import com.cutie.sdk.views.CutiEInboxView
import com.cutie.sdk.views.CutiEConversationView
@Composable
fun SettingsScreen() {
var showInbox by remember { mutableStateOf(false) }
var selectedConversation by remember { mutableStateOf<Conversation?>(null) }
Button(onClick = { showInbox = true }) {
Text("My Feedback")
}
if (showInbox) {
Dialog(
onDismissRequest = { showInbox = false },
properties = DialogProperties(usePlatformDefaultWidth = false)
) {
Surface(
modifier = Modifier.fillMaxSize(),
shape = MaterialTheme.shapes.large
) {
CutiEInboxView(
onDismiss = { showInbox = false },
onConversationSelected = { conversation ->
selectedConversation = conversation
}
)
}
}
}
// Show conversation detail when selected
selectedConversation?.let { conversation ->
Dialog(
onDismissRequest = { selectedConversation = null },
properties = DialogProperties(usePlatformDefaultWidth = false)
) {
Surface(
modifier = Modifier.fillMaxSize(),
shape = MaterialTheme.shapes.large
) {
CutiEConversationView(
conversationId = conversation.conversationId,
onDismiss = { selectedConversation = null }
)
}
}
}
}
Navigation Bar with Badge
Add an inbox icon with unread count badge to your app bar:
@Composable
fun MainScreen() {
var showInbox by remember { mutableStateOf(false) }
var unreadCount by remember { mutableStateOf(0) }
// Load unread count on launch
LaunchedEffect(Unit) {
CutiE.instance?.getUnreadCount { result ->
result.onSuccess { unreadCount = it }
}
}
Scaffold(
topBar = {
TopAppBar(
title = { Text("My App") },
actions = {
// Inbox button with badge
IconButton(onClick = { showInbox = true }) {
BadgedBox(
badge = {
if (unreadCount > 0) {
Badge { Text(unreadCount.toString()) }
}
}
) {
Icon(Icons.Default.Inbox, "Feedback Inbox")
}
}
}
)
}
) { padding ->
// Your content here
}
// Show inbox dialog
if (showInbox) {
// ... same as above
}
}
Callback API
// List all conversations
CutiE.instance?.listConversations { result ->
result.onSuccess { conversations ->
conversations.forEach { println("${it.title} - ${it.status}") }
}
result.onFailure { error ->
println("Error: ${error.message}")
}
}
// Get single conversation with messages
CutiE.instance?.getConversation(conversationId) { result ->
result.onSuccess { conversation ->
conversation.messages?.forEach { println(it.message) }
}
}
// Send a reply
CutiE.instance?.sendMessage(conversationId, "Thanks!") { result ->
result.onSuccess { message -> println("Sent: ${message.messageId}") }
}
// Get unread count for badge
CutiE.instance?.getUnreadCount { result ->
result.onSuccess { count -> updateBadge(count) }
}
Feedback App SDK (CutiELink)
CutiELink is a lightweight SDK for connecting your app to the standalone Cuti-E Feedback App. Instead of embedding a full feedback form in your app, users can manage all their feedback in the dedicated Feedback App.
Two Integration Options:
1. CutiE SDK (above) - Full feedback form embedded in your app
2. CutiELink SDK (this section) - Links to standalone Feedback App
How It Works
- User taps "Open in Feedback App" button in your app
- CutiELink generates a secure magic link token via API
- The Cuti-E Feedback App opens via deep link
- User is automatically linked and can manage feedback
Installation
Add CutiELink via Swift Package Manager:
// Package.swift
dependencies: [
.package(url: "https://github.com/cuti-e/ios-link-sdk.git", from: "1.0.0")
]
Or in Xcode: File → Add Package Dependencies and paste the URL.
Info.plist Setup
Add the Cuti-E URL scheme to your Info.plist to detect if the Feedback App is installed:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>cutie</string>
</array>
Usage
1. Configure at App Launch
import CutiELink
@main
struct MyApp: App {
init() {
CutiELink.configure(appId: "app_your_app_id_here")
}
// ...
}
2. Add "Open in Feedback App" Button
import CutiELink
struct SettingsView: View {
var body: some View {
Button("Open in Feedback App") {
Task {
do {
try await CutiELink.openFeedbackApp()
} catch {
print("Error: \(error)")
}
}
}
}
}
That's it - just two steps!
Optional: Check if Feedback App is Installed
if CutiELink.isFeedbackAppInstalled {
// Show "Open in Feedback App" button
} else {
// Show fallback or prompt to install
}
Sandbox Testing: For development, call CutiELink.useSandbox()
after configure() to use the sandbox API.
Conversation API
Categories
| Category | Description |
|---|---|
bug | Bug reports |
feature | Feature requests |
question | Questions |
feedback | General feedback |
other | Other |
Statuses
| Status | Description |
|---|---|
open | New, unassigned |
in_progress | Being worked on |
waiting_user | Waiting for user response |
waiting_admin | Waiting for admin response |
resolved | Issue resolved |
closed | Conversation closed |
Message API
Sender Types
| Type | Description |
|---|---|
user | Message from app user |
admin | Message from support admin |
system | Automated system message |
Push Notifications
Users receive push notifications when admins reply to their feedback.
Important: Push notifications require setup in three places: Xcode, Apple Developer Portal, and the Admin Dashboard. See the complete setup guide for step-by-step instructions.
iOS (APNs)
import UserNotifications
import CutiE
// 1. Request permission (in app startup)
CutiE.shared.pushNotifications.requestPermission { granted in
print("Push notifications \(granted ? "enabled" : "denied")")
}
// 2. In AppDelegate, forward the device token to CutiE
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
CutiE.shared.pushNotifications.didRegisterForRemoteNotifications(withDeviceToken: deviceToken)
}
func application(_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error) {
CutiE.shared.pushNotifications.didFailToRegisterForRemoteNotifications(withError: error)
}
// 3. Clear badge when app becomes active (SwiftUI)
@Environment(\.scenePhase) private var scenePhase
.onChange(of: scenePhase) { newPhase in
if newPhase == .active {
CutiE.shared.pushNotifications.clearBadgeCount()
}
}
Push Notification Setup Screenshots
For detailed setup instructions with screenshots, see the iOS SDK Push Notifications Guide.
Enable Push Notifications capability in Xcode
Create APNs key in Apple Developer Portal
Configure APNs in Cuti-E Admin Dashboard
Android (FCM)
import com.google.firebase.messaging.FirebaseMessaging
import com.cutie.sdk.CutiE
FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
if (task.isSuccessful) {
CutiE.getInstance(context).registerPushToken(task.result) { result ->
result.onSuccess {
println("Push token registered")
}
}
}
}
Need help? Email us at [email protected] or check out the full SDK code on GitHub.