Claude API Swift SDK: iOS Integration Guide
Anthropic does not publish an official Swift SDK for Claude, so "claude api swift sdk ios integration" searches usually lead to the same answer: you build a thin networking layer on top of URLSession and Claude's REST/SSE API, using Codable models for requests and responses. There's no package to import Claude — you're writing roughly 150-300 lines of Swift that wrap HTTP calls, which is genuinely manageable and gives you full control over retries, streaming, and error handling.
The second thing every iOS developer needs to know before writing a single line of networking code: you cannot ship a Claude API key inside an iOS app bundle. Anyone can extract it from the binary with basic reverse-engineering tools, and then your usage bill belongs to a stranger. This changes the integration architecture — you either need your own backend to hold the key, or a hosted proxy layer designed for exactly this, like SubToAPI, that issues scoped application keys instead of your raw provider credentials.
Why there's no first-party Swift SDK
Anthropic maintains official SDKs for Python and TypeScript/JavaScript. Mobile platforms are left to the community and to HTTP clients. This isn't unusual — most AI providers prioritize server-side languages because the intended architecture is: mobile/web client → your backend → provider API. Calling Claude directly from an iOS app, even if you solved the key-exposure problem, also means every user hits Anthropic's API with your account's full key, with no per-user tracking, rate limiting, or seat management.
That's the real reason "integration" for iOS is less about missing Swift bindings and more about architecture. You have three realistic options:
- Your own backend. Build a small server (Node, Swift on server-side, whatever) that holds the key and forwards requests.
- A proxy/API gateway service. Something like SubToAPI sits between your app and Claude, issuing you an application key (
sub_live_...) you can use from a trusted environment, with usage metadata and streaming support already built. - Skip it entirely and call Claude from a backend you already run, treating the iOS app as a pure client.
Whichever you choose, the Swift-side code is almost identical: an HTTPClient struct, Codable message models, and an async/await call. The difference is just which base URL and key you use.
Building the networking layer
Here's a minimal, production-shaped Swift client using async/await and URLSession:
import Foundation
struct ClaudeMessage: Codable {
let role: String
let content: String
}
struct ClaudeRequest: Codable {
let model: String
let max_tokens: Int
let messages: [ClaudeMessage]
}
struct ClaudeResponseContent: Codable {
let type: String
let text: String?
}
struct ClaudeResponse: Codable {
let id: String
let content: [ClaudeResponseContent]
}
final class ClaudeClient {
private let baseURL: URL
private let apiKey: String
init(baseURL: URL, apiKey: String) {
self.baseURL = baseURL
self.apiKey = apiKey
}
func send(prompt: String, model: String = "claude-sonnet-4") async throws -> String {
var request = URLRequest(url: baseURL.appendingPathComponent("messages"))
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
let body = ClaudeRequest(
model: model,
max_tokens: 1024,
messages: [ClaudeMessage(role: "user", content: prompt)]
)
request.httpBody = try JSONEncoder().encode(body)
let (data, response) = try await URLSession.shared.data(for: request)
guard let http = response as? HTTPURLResponse, http.statusCode == 200 else {
throw URLError(.badServerResponse)
}
let decoded = try JSONDecoder().decode(ClaudeResponse.self, from: data)
return decoded.content.first?.text ?? ""
}
}
If you're wiring this against SubToAPI, baseURL becomes https://api.subtoapi.app/v1, and apiKey is your sub_live_... application key, kept in a Secrets.plist excluded from source control or injected at build time — never hardcoded, and ideally fetched from your backend at runtime rather than bundled at all. See /docs/quickstart for the full request shape and /docs/messages for the message/content schema this client decodes.
Handling streaming in Swift
Claude's streaming responses use server-sent events. URLSession doesn't parse SSE natively, but you can consume the byte stream directly with URLSession.bytes(for:):
func streamResponse(prompt: String) async throws -> AsyncStream<String> {
var request = URLRequest(url: baseURL.appendingPathComponent("messages"))
request.httpMethod = "POST"
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body = """
{"model":"claude-sonnet-4","max_tokens":1024,"stream":true,
"messages":[{"role":"user","content":"\(prompt)"}]}
"""
request.httpBody = body.data(using: .utf8)
let (bytes, _) = try await URLSession.shared.bytes(for: request)
return AsyncStream { continuation in
Task {
for try await line in bytes.lines {
if line.hasPrefix("data: ") {
let payload = line.dropFirst(6)
if let data = payload.data(using: .utf8),
let json = try? JSONDecoder().decode(ClaudeResponseContent.self, from: data),
let text = json.text {
continuation.yield(text)
}
}
}
continuation.finish()
}
}
}
Each data: line is a JSON chunk; you accumulate text deltas and append them to a @Published string that drives your chat UI in real time. This pattern works whether the base URL points at Anthropic directly (server-side only) or at a proxy like SubToAPI, which exposes the same streaming contract — details in /docs/streaming.
Tool use and structured output from Swift
If your iOS app needs Claude to call functions (fetch weather, query a local database, trigger an app action), the request body gains a tools array and the response includes tool_use content blocks you decode the same way as text blocks, just with an extra input dictionary. The Swift-side pattern doesn't change — you're still decoding ClaudeResponseContent, just with more cases in the type field. Full schema at /docs/tools.
Practical recommendation
For a shipping iOS app, don't point URLSession at Anthropic's API directly from the client. Route through a backend or a gateway that gives you per-device or per-user API keys, usage visibility, and the ability to rotate a compromised key without an App Store update. SubToAPI's Solo plan (€9) covers single-developer apps; Team and Scale plans add seats if you're building with a group. Check /pricing for the breakdown, or start with the free trial at /signup and swap baseURL in the client above.
Questions
Is there an official Claude Swift SDK? No. Anthropic ships Python and TypeScript SDKs only. iOS integration means writing your own URLSession-based client with Codable models, as shown above.
Can I call the Claude API directly from an iOS app? Not safely with your real API key — it can be extracted from the app binary. Use a backend or a proxy service that issues scoped keys instead.
How do I handle streaming responses in SwiftUI? Use URLSession.bytes(for:) to read the SSE stream line by line, parse data: lines as JSON, and feed text deltas into an AsyncStream or @Published property that updates your chat view incrementally.