How to add ElevenLabs text to speech to an iOS app
What ElevenLabs does for an iOS app
ElevenLabs gives an app high quality voices for narration, reading articles aloud, voicing an assistant, or accessibility. You send text and a voice id, and it returns spoken audio you can play immediately or cache. Compared with the built-in AVSpeechSynthesizer, ElevenLabs sounds far more natural and offers a large voice library, at the cost of a network call and per-character pricing. The integration work is keeping the key off the device and managing audio playback, including handling longer text where streaming feels more responsive than waiting for the whole file.
Adding ElevenLabs with AppFlight
The ElevenLabs key is a backend secret, never a client key, because it can spend on your account. In AppFlight you add the key, and it lands in the backend secrets of your own Supabase, not in the binary. AppFlight generates a Supabase edge function that takes text from the app, calls the ElevenLabs text-to-speech endpoint with the key and a voice id, and returns the audio. The app calls that function and plays the result. This is the client versus backend split applied to AI voice: the key stays server-side.
A SwiftUI example
The app sends text to your backend and plays the audio it returns:
import AVFoundation
final class Speaker {
private var player: AVAudioPlayer?
func speak(_ text: String) async throws {
var request = URLRequest(
url: URL(string: "https://your-project.supabase.co/functions/v1/speak")!
)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONEncoder().encode(["text": text])
let (data, _) = try await URLSession.shared.data(for: request)
player = try AVAudioPlayer(data: data)
player?.play()
}
}
The backend function holds the secret. In outline, it reads ELEVENLABS_API_KEY from the environment, sends a POST to https://api.elevenlabs.io/v1/text-to-speech/{voice_id} with the xi-api-key header and the text in the body, and streams the returned MP3 back to the app. The key never reaches the device.
Alternatives
Apple's AVSpeechSynthesizer runs fully on device with no key, no network, and no cost, so it is the right pick when robotic-but-free speech is acceptable or you need offline playback. OpenAI also offers a text-to-speech endpoint that follows the same backend pattern if you already use it. ElevenLabs is the strongest choice when voice quality and a large, customizable voice library matter most.
FAQ
Can the ElevenLabs API key go in the app?
No. The xi-api-key is a secret tied to your account and usage, and a binary can be unpacked, so the key belongs on a backend. The app calls your server, and the server adds the key when it calls ElevenLabs.
What does the API return and how do I play it?
A request to the text-to-speech endpoint returns audio, MP3 by default. Your backend passes those bytes back to the app, and you play them with AVAudioPlayer or stream them with AVPlayer for longer text.
Do I need a specific voice?
Yes. Each request targets a voice_id from the ElevenLabs voice library or one you create. You pick the voice on the backend or pass an id through, and you choose a model and output format in the request body.