Model or dataset
AIProxyTeam/AIProxySwift avatar
AIProxyTeam/AIProxySwift

AIProxySwift: Swift clients for 17 AI providers, with an optional abuse-protection backend

Swift clients for AI providers. You can make requests straight to the provider or proxied through our abuse protection backend

446 stars94 forksSwiftMIT

At a glance

What is it?
AIProxySwift is a Swift package that wraps OpenAI, Gemini, Anthropic and fourteen other provider APIs behind one set of service objects. Initialization decides whether requests go directly to the provider or through the AIProxy backend, which adds certificate pinning, DeviceCheck verification and rate limits.
Who is it for?
Adopt AIProxySwift if you ship a Swift app on iOS or macOS and want one Swift API across several providers, or if you want the AIProxy backend to hold the key instead of your binary. Skip it if your stack is on a server, if you need providers outside the seventeen listed, or if you want to self-host the protection layer, since the backend is a hosted service reached through a serviceURL from your developer dashboard.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 18 days ago.
What is it written in?
Mainly Swift, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem: provider keys in a shipped binary

A mobile app that calls an AI provider has to hold a credential somewhere. If the app talks straight to OpenAI or Anthropic, that credential lives in the binary or in a config file on the device, and anyone who extracts it can spend your account balance. The README is explicit about which side of that line it recommends: direct-to-provider requests are for prototyping and for BYOK cases, where the customer supplies their own key and the bill lands on them. Everything else is meant to go through the AIProxy backend.

The audience follows from that. This is for Swift developers building iOS, macOS or server-side Swift apps who want to call several providers without writing an HTTP client per provider, and who would rather not build and maintain a key-holding backend themselves. The README describes that backend as an alternative to "building, monitoring, and maintaining your own backend" when you ship with a personal or company API key.

The library covers seventeen providers: OpenAI, Gemini, Anthropic, Stability AI, DeepL, Together AI, Replicate, ElevenLabs, Fal, Groq, Perplexity, Mistral, EachAI, OpenRouter, DeepSeek, Fireworks AI and Brave. That list matters more than it looks. It is a fixed set, and a provider outside it means writing your own client regardless of what the rest of the package offers.

How the two request paths actually differ

There is one initialization decision and it propagates through every service object. For BYOK or prototyping you construct a service with `AIProxy.openAIDirectService(unprotectedAPIKey:)`, and the key you pass is the provider's own key. For production you construct `AIProxy.openAIService(partialKey:serviceURL:)`, and the two strings come from your AIProxy developer dashboard. The service object then exposes the same request methods either way, so the call site does not change shape when you switch paths. The README's OpenAI example shows both constructors commented out side by side, which is a fair summary of the design intent: the difference is meant to be one line.

The backend path is where the security claims live. The README lists five measures applied to protected requests: certificate pinning, DeviceCheck verification, split key encryption, per user rate limits and per IP rate limits. Split key encryption is the one worth thinking about, because it explains the `partialKey` name. Your app never holds a complete provider key, so extracting the app's copy does not yield something that can be spent directly. DeviceCheck verification ties requests to a real Apple device, which is what makes the per-user rate limit meaningful rather than trivially bypassed.

Two configuration flags affect the client side of that flow. `resolveDNSOverTLS` routes DNS resolution through Cloudflare's DNS-over-TLS, and the README recommends it. `useStableID` makes the client identifier stable, which the README ties to rate limiting usage across an App Store user's account on multiple devices. That flag has a setup cost: it needs iCloud key-value storage enabled on your target, added through Signing & Capabilities in Xcode. If you turn it on without that capability, the identifier has nowhere to persist.

Installing AIProxySwift and making a first request

In Xcode, open your project, choose File > Add Package Dependencies, and enter the package URL. The README gives the URL as `github.com/lzell/aiproxyswift` and suggests selecting the main branch as the dependency rule, or pinning specific releases if you want finer control over when the dependency updates.

CocoaPods is the other documented route. Add the pod to your Podfile and install:

ruby
pod "AIProxy"
bash
pod install

Before any request, call `AIProxy.configure` once at launch. In SwiftUI the README puts it in the app's composition root, inside the App struct's init. The five parameters control logging, body printing and the two client behaviours described above:

swift
import AIProxy

@main
struct MyApp: App {
    init() {
        AIProxy.configure(
            logLevel: .debug,
            printRequestBodies: false,
            printResponseBodies: false,
            resolveDNSOverTLS: true,
            useStableID: true
        )
    }
}

A UIKit app does the same thing in `application(_:didFinishLaunchingWithOptions:)` instead. Note that `printRequestBodies` and `printResponseBodies` exist for debugging and for contributing to the library; leaving them off in a shipped build is the sensible reading of the README's framing.

With configuration done, a first OpenAI chat completion looks like this in the README's example. The service constructor is commented out in the source, and you uncomment whichever path you are on:

swift
// BYOK or prototyping:
let openAIService = AIProxy.openAIDirectService(
    unprotectedAPIKey: "your-openai-key"
)

// Production through the AIProxy backend:
// let openAIService = AIProxy.openAIService(
//     partialKey: "partial-key-from-your-developer-dashboard",
//     serviceURL: "service-url-from-your-developer-dashboard"
// )

The request body is a typed Swift struct, not a dictionary, and the call is async. The README's example builds an `OpenAIChatCompletionRequestBody` with a system message and a user message, sets `reasoningEffort: .noReasoning`, and awaits `chatCompletionRequest(body:secondsToWait:)` with a 120-second timeout. What you should see on success is a response object whose `choices` array carries the assistant message. If you are on the backend path, you also need the AIProxy backend configured for your project; the README points to an integration video at aiproxy.com and notes this step is not required for BYOK apps.

Where AIProxySwift stops being the right choice

The provider list is the first hard boundary. Seventeen providers is broad, but it is a curated set, and the README offers no extension mechanism for adding an eighteenth without forking. If your app depends on a provider that is not listed, the package does not help you with that provider at all.

The backend path is a hosted dependency. The README describes the AIProxy backend as a service reachable through a service URL from your developer dashboard, and the integration guide is a video on aiproxy.com rather than a self-hosting document. Nothing in the README describes running that protection layer yourself. So the five security properties are properties of a service you use, not of code you control. Teams with a policy against third-party key custody, or with latency budgets that cannot absorb an extra hop, should treat this as a genuine constraint rather than a configuration detail.

There is also a platform assumption running through the design. DeviceCheck is an Apple framework, and the stable-identifier path depends on iCloud key-value storage. Both are iOS and macOS concerns. The package is written in Swift and could be used elsewhere, but the abuse-protection story is built around Apple's device attestation, so a server-side or Android deployment would be using the direct path with none of the backend benefits the README leads with.

Finally, the README does not document rollback or migration between the two paths. Switching from direct keys to the backend means changing constructors and obtaining a partial key and service URL; the README says nothing about running both in parallel or about what happens to in-flight requests during that change.

AIProxySwift compared with LiteLLM and OpenRouter

The related searches for this project pull in LiteLLM and OpenRouter, and the comparison is instructive because all three sit between an app and a provider, but at different layers.

LiteLLM is a Python proxy that presents an OpenAI-compatible HTTP interface and fans requests out to many providers. If you adopt it, your Swift app talks to a local or hosted endpoint using ordinary HTTP, and the provider translation happens outside your binary. AIProxySwift inverts that: the translation lives in Swift types inside your app, and the network hop to a protection backend is optional. The trade-off is concrete. LiteLLM keeps your Swift code free of provider-specific types and lets you add providers by editing a Python config, but you now operate a service. AIProxySwift gives you compile-time types and no service to run in the BYOK case, but provider coverage is fixed at what the package ships.

OpenRouter is a routing service: one endpoint, one key, many models, with the provider selection handled upstream. That is closer to AIProxySwift's backend path than to its direct path, except OpenRouter's value is model routing and billing aggregation, while AIProxy's stated value is keeping your key out of the binary and your bill predictable through per-user and per-IP rate limits. The README's five security measures have no equivalent in a routing service. If what you want is model choice, OpenRouter addresses that; if what you want is an app that cannot leak a spendable key, that is the problem AIProxySwift is aimed at.

Maintenance, releases and the MIT licence

The repository is not archived, and the last push was on 2026-08-28. Releases have been frequent and versioned in the 0.15x range: 0.155.0 on 2026-08-04, 0.156.0 on 2026-08-22 and 0.157.0 on 2026-08-28. The 0.x version number is worth taking literally. Semver treats anything below 1.0 as potentially breaking on minor bumps, and the README's own installation advice reflects that tension: it suggests the main branch as the dependency rule, or specific releases "if you'd like to have finer control of when your dependency gets updated."

That is a real upgrade decision, not a formality. Tracking main means you get fixes without waiting for a tag, and you also get whatever landed that week. Pinning a release means you choose when to move, and you own the work of reading the diff. The README documents how to update in both cases (right-click the package and select Update Package, or adjust the version rule in Package Dependencies), but it does not describe a deprecation policy or a compatibility guarantee between minor versions.

The licence is MIT, which permits commercial and closed-source use and requires that the copyright notice and permission notice travel with the software. That is the whole of it; the README says nothing about the AIProxy backend's own terms, which are a separate matter from the package's licence. Developers shipping a paid app should read the backend's terms independently of the MIT grant, since the two cover different things.

Contributing follows an unusual but practical pattern the README spells out: fork, clone, remove the remote package from your app, use "Add local" to point Xcode at your clone, develop against a real app, then open a PR. It keeps the library honest about what an app actually needs.

Editorial conclusion

Adopt AIProxySwift if you ship a Swift app on iOS or macOS and want one Swift API across several providers, or if you want the AIProxy backend to hold the key instead of your binary. Skip it if your stack is on a server, if you need providers outside the seventeen listed, or if you want to self-host the protection layer, since the backend is a hosted service reached through a serviceURL from your developer dashboard. Before committing, verify three things: that the provider you depend on appears in the README's list, that your AIProxy plan's rate limits match what your app will do, and that you are comfortable shipping the partialKey and serviceURL pair, which the README presents as the production configuration rather than the direct-key one.

Frequently asked questions

How do I install AIProxySwift in an Xcode project?

Choose File > Add Package Dependencies in Xcode and enter the package URL given in the README, which is github.com/lzell/aiproxyswift. The README suggests selecting the main branch as the dependency rule, or pinning specific releases for finer control over updates. CocoaPods is also supported by adding the pod named AIProxy to your Podfile and running pod install.

Does AIProxySwift send requests directly to providers or through a backend?

Both paths exist, and your initialization code decides which one is used. Constructing a service with openAIDirectService and an unprotectedAPIKey sends requests straight to the provider, which the README recommends only for prototyping and BYOK cases. Constructing it with openAIService using a partialKey and serviceURL routes requests through the AIProxy backend.

What does the AIProxy backend add to requests from AIProxySwift?

The README lists five measures applied to protected requests: certificate pinning, DeviceCheck verification, split key encryption, per user rate limits and per IP rate limits. Split key encryption is why the client holds a partialKey rather than a complete provider key. The backend is configured separately, and the README notes this step is not required for apps where customers supply their own keys.

Official sources

  1. AIProxyTeam/AIProxySwift on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Community notes

Community notes