A lightweight iOS SDK for collecting user feedback. You build your own form — the SDK handles submission (enriched with device metadata) and fetching the public feedback list.
- Min iOS: 15.0
- Package: Swift Package Manager
- License: MIT
In Xcode: File → Add Package Dependencies, enter the repository URL, and add FeedbackJar to your target.
Or in Package.swift:
dependencies: [
.package(url: "https://github.com/feedbackjar/swift-sdk", from: "1.0.0"),
],
targets: [
.target(name: "MyApp", dependencies: ["FeedbackJar"]),
]Configure once before use — typically in AppDelegate or your SwiftUI App.init. You need your widget ID from the FeedbackJar dashboard.
import FeedbackJar
@main
struct MyApp: App {
init() {
FeedbackJar.configure(widgetId: "your-widget-id")
}
}Submissions are anonymous. Each submission automatically carries device metadata (iOS version, device model, screen size, app version, locale).
let result = await FeedbackJar.shared.submit(userText)
switch result {
case .success(let response):
print("Submitted: \(response.postId) (\(response.type))")
case .failure(let error):
print("Failed: \(error)")
}Safe to call from the main thread — the network call runs off the main thread.
FeedbackJar.shared.submit(userText) { result in
switch result {
case .success(let response): // show success state
case .failure(let error): // show error state
}
}Note: the server applies rate limiting (5 submissions per 15 minutes per IP). Handle the failure case in your UI.
Fetch the public feedback feed for your organization. Supports pagination via a cursor.
let result = await FeedbackJar.shared.listFeedback(limit: 20)
if case .success(let page) = result {
for post in page.posts {
print("\(post.title) — \(post.upvotes) upvotes, \(post.status)")
}
// page.nextCursor is non-nil when more pages exist
}var cursor: String? = nil
func loadNextPage() async {
let result = await FeedbackJar.shared.listFeedback(limit: 20, cursor: cursor)
if case .success(let page) = result {
render(page.posts)
cursor = page.nextCursor
}
}FeedbackJar.shared.listFeedback(limit: 20) { result in
if case .success(let page) = result { /* ... */ }
}| Method | Description |
|---|---|
configure(widgetId:) |
Configure the SDK. Call once before anything else. |
submit(_ content:) async -> Result<FeedbackResponse, Error> |
Submit anonymous feedback. |
submit(_ content:, completion:) |
Callback variant, main-thread safe. |
listFeedback(boardId:limit:cursor:) async -> Result<FeedbackListResult, Error> |
List public feedback. limit is clamped to 1–50. |
listFeedback(boardId:limit:cursor:completion:) |
Callback variant. |
public struct FeedbackResponse {
let postId: String
let title: String // AI-generated title for the submission
let type: String // e.g. FEEDBACK, BUG, FEATURE_REQUEST
let boardId: String
}public struct FeedbackPost {
let id: String
let title: String
let content: String
let type: String
let status: String // OPEN, IN_PROGRESS, COMPLETED, ...
let slug: String
let boardId: String
let voteCount: Int
let commentCount: Int
let upvotes: Int
let authorName: String?
let createdAt: String // ISO-8601
let updatedAt: String // ISO-8601
}public struct FeedbackListResult {
let posts: [FeedbackPost]
let nextCursor: String? // nil when there are no more pages
}- Only anonymous submission is supported in this version — no user identity or email is sent.
- Private boards and non-public posts are never returned by
listFeedback. - All methods return a Swift
Result; nothing throws on network/HTTP errors. - No dependencies beyond the Swift standard library and
Foundation/UIKit.