Swift SDK
Official Swift SDK for TruthMark invisible watermarking on iOS, macOS, and server-side Swift.
Installation
Swift Package Manager (Package.swift)
dependencies: [
.package(url: "https://github.com/truthmark/sdk-swift", from: "1.0.0")
]Quick Example
import TruthMarkSDK
let client = TruthMarkClient(config: .init(
apiKey: "tm_live_your_key",
baseURL: "https://truthmark-api.onrender.com"
))
// Encode
let result = try await client.encode(
imagePath: "image.png",
message: "Copyright 2025"
)
print("Download: \(result.downloadUrl)")
print("PSNR: \(String(format: "%.1f", result.metadata.psnr)) dB")
// Decode
let decoded = try await client.decode(imagePath: "watermarked.png")
if decoded.found {
print("Message: \(decoded.message ?? "")")
print("Confidence: \(String(format: "%.1f", decoded.confidence * 100))%")
}API Reference
TruthMarkClient(config:)
Create a new client with configuration.
struct TruthMarkConfig {
let apiKey: String
let baseURL: String?
let timeout: TimeInterval?
}encode(imagePath:message:) async throws
Embed an invisible watermark. Returns EncodeResult.
decode(imagePath:) async throws
Extract watermark. Returns DecodeResult.
Error Handling
do {
let result = try await client.encode(imagePath: path, message: msg)
} catch let error as TruthMarkError {
switch error {
case .unauthorized:
print("Invalid API key")
case .rateLimited(let retryAfter):
print("Rate limited. Retry after \(retryAfter)s")
case .payloadTooLarge:
print("Image too large (max 20MB)")
case .apiError(let code, let message):
print("Error \(code): \(message)")
}
} catch {
print("Network error: \(error.localizedDescription)")
}Advanced Examples
SwiftUI Image Picker
import SwiftUI
import PhotosUI
import TruthMarkSDK
struct WatermarkView: View {
@State private var selectedItem: PhotosPickerItem?
@State private var resultURL: String?
@State private var isProcessing = false
let client = TruthMarkClient(config: .init(
apiKey: ProcessInfo.processInfo.environment["TRUTHMARK_API_KEY"] ?? ""
))
var body: some View {
VStack(spacing: 20) {
PhotosPicker("Select Image", selection: $selectedItem)
if isProcessing { ProgressView() }
if let url = resultURL { Text("Done: \(url)") }
}
.onChange(of: selectedItem) { _, item in
guard let item else { return }
Task { await processImage(item) }
}
}
func processImage(_ item: PhotosPickerItem) async {
isProcessing = true
defer { isProcessing = false }
guard let data = try? await item.loadTransferable(type: Data.self) else { return }
let result = try? await client.encode(imageData: data, message: "© 2025")
resultURL = result?.downloadUrl
}
}Vapor Server Route
import Vapor
import TruthMarkSDK
func routes(_ app: Application) throws {
let client = TruthMarkClient(config: .init(
apiKey: Environment.get("TRUTHMARK_API_KEY")!
))
app.post("watermark") { req async throws -> EncodeResult in
let file = try req.content.decode(FileUpload.self)
return try await client.encode(
imageData: file.data,
message: file.message
)
}
}Best Practices
Use async/await throughout
All SDK methods are async — use structured concurrency with Swift's native async/await.
Store keys in Keychain (iOS) or env vars (server)
Never hardcode API keys in your app bundle.
Don't ship API keys in client apps
For iOS apps, proxy through your backend to protect keys.