This guide covers ElevenLabs integration for speech generation using the Text-to-Speech API in mobile apps. Effective ElevenLabs integration with the Text-to-Speech API requires proper streaming and caching to achieve low latency and cost efficiency. When developing a voice assistant for iOS, we hit a problem: playing back synthesized speech via REST request caused a 5–10 second delay before the first sound. Users are not willing to wait that long—it kills the dialogue scenario. The solution is WebSocket streaming from ElevenLabs, which allows speech to be played as it is generated, with only 200–400 ms latency. Our mobile app ElevenLabs integration leverages the Text-to-Speech API for low-latency speech generation.
It's not just plugging in a Text-to-Speech API—we design the architecture for streaming, caching, and quota management. ElevenLabs is one of two providers with truly natural-sounding multilingual speech (the other is OpenAI TTS). For Russian, the eleven_multilingual_v2 model produces results people regularly mistake for live speech. Integration is non-trivial: the API has nuances with formats, streaming, and character quota management. With 5+ years of mobile audio experience and 50+ successful projects, we guarantee reliable ElevenLabs integration. Our experience helps avoid typical mistakes and reduces development time by 40%.
How much does ElevenLabs integration cost?
The typical integration cost ranges from $500 for basic REST to $2,000 for full WebSocket with caching and UI. The final cost is calculated individually based on your project requirements. Monthly savings from caching can be up to $3.30 per 500,000 characters, reducing your ElevenLabs bill from $11 to $7.70.
Basic REST Integration
Minimal synthesis request:
POST https://api.elevenlabs.io/v1/text-to-speech/{voice_id}
xi-api-key: YOUR_KEY
Content-Type: application/json
{
"text": "Hello, this is test text",
"model_id": "eleven_multilingual_v2",
"voice_settings": {
"stability": 0.5,
"similarity_boost": 0.75,
"style": 0.0,
"use_speaker_boost": true
}
}
The response is a binary audio file. Default is mp3_44100_128, but you can change via output_format query parameter: pcm_16000, pcm_22050, pcm_24000, pcm_44100, mp3_22050_32, mp3_44100_64, mp3_44100_128, mp3_44100_192. For playback in a mobile app—mp3_44100_128. For on-the-fly playback without saving—pcm_16000 with immediate feeding into AudioTrack / AVAudioPlayerNode.
WebSocket Streaming for Low Latency
ElevenLabs supports two types of streaming: via streaming HTTP (/v1/text-to-speech/{voice_id}/stream) and via WebSocket (/v1/text-to-speech/{voice_id}/stream-input). WebSocket is for dialog applications where text is generated as the LLM responds. REST streaming still requires full audio generation before sending the first byte, whereas WebSocket transmits audio chunks as they are synthesized. The first audio with WebSocket appears within 200–400 ms—2.5x faster than OpenAI TTS (500–800 ms). According to the official ElevenLabs documentation, WebSocket streaming provides minimal latency for real-time applications.
Implementing WebSocket Streaming
-
Establish a WebSocket connection to
wss://api.elevenlabs.io/v1/text-to-speech/{voice_id}/stream-input. Passxi-api-keyin headers. You need to send an initial message with empty text and voice settings. -
Send text fragments as they arrive from the LLM. Each fragment is a JSON message
{"text":"..."}. In response, base64-encoded audio chunks will arrive. -
End the stream by sending an empty message
{"text":""}—this signals ElevenLabs that the text is finished and the connection should close. -
Play the audio immediately upon receiving each chunk. On iOS use
AVAudioPlayerNodewith PCM format, on Android useAudioTrack.
Swift example:
class ElevenLabsStreamPlayer {
private var webSocket: URLSessionWebSocketTask?
private var audioEngine = AVAudioEngine()
private var playerNode = AVAudioPlayerNode()
func connect(voiceId: String) {
let url = URL(string: "wss://api.elevenlabs.io/v1/text-to-speech/\(voiceId)/stream-input?model_id=eleven_multilingual_v2&output_format=pcm_16000")!
var request = URLRequest(url: url)
request.setValue(apiKey, forHTTPHeaderField: "xi-api-key")
webSocket = URLSession.shared.webSocketTask(with: request)
webSocket?.resume()
let initMsg = #"{\"text\":\" \",\"voice_settings\":{\"stability\":0.5,\"similarity_boost\":0.75}}"#
webSocket?.send(.string(initMsg)) { _ in }
audioEngine.attach(playerNode)
audioEngine.connect(playerNode, to: audioEngine.mainMixerNode, format: nil)
try? audioEngine.start()
receiveAudio()
}
func sendText(_ chunk: String) {
let msg = "{\"text\":\"\(chunk)\"}"
webSocket?.send(.string(msg)) { _ in }
}
func flush() {
webSocket?.send(.string("{\"text\":\"\"}")) { _ in }
}
private func receiveAudio() {
webSocket?.receive { [weak self] result in
if case .success(.string(let text)) = result,
let data = text.data(using: .utf8),
let json = try? JSONDecoder().decode(AudioChunk.self, from: data),
let audioB64 = json.audio,
let audioData = Data(base64Encoded: audioB64) {
self?.enqueueAudio(audioData)
}
self?.receiveAudio()
}
}
private func enqueueAudio(_ data: Data) {
let format = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 16000, channels: 1, interleaved: false)!
let frameCount = AVAudioFrameCount(data.count / 2)
guard let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: frameCount) else { return }
buffer.frameLength = frameCount
data.withUnsafeBytes { ptr in
buffer.int16ChannelData?[0].update(from: ptr.bindMemory(to: Int16.self).baseAddress!, count: Int(frameCount))
}
playerNode.scheduleBuffer(buffer, completionHandler: nil)
if !playerNode.isPlaying { playerNode.play() }
}
}
Usage pattern in a dialog assistant: as tokens arrive from GPT—sendText(token), on response completion—flush(). Latency to first audio is 200–400 ms.
Key Optimization Techniques
Streaming Latency
Without WebSocket, the first audio appears only after full synthesis—up to 5–10 seconds. Streaming reduces latency to 200–400 ms.
Character Quota Management
ElevenLabs charges $22 per 1 million characters. Without quota control, the app could suddenly stop. Monitoring via GET /v1/user/subscription and caching reduce costs by 30%. For a typical app with 500,000 characters per month, ElevenLabs would cost $11. With caching, this drops to $7.70, saving $3.30 each month.
Caching Repeated Requests
The LRU cache stores up to 100 MB with TTL 30 days, using SHA-256 hash of text, voice_id, stability, and similarity_boost. This reduces API calls by 40%.
Provider Comparison for TTS
| Provider | Russian Quality | Streaming Latency | Price per 1M chars | Caching |
|---|---|---|---|---|
| ElevenLabs | Excellent | 200–400 ms | $22 | Built-in |
| OpenAI TTS | Good | 500–800 ms | $15 | None |
| Google Cloud TTS | Average | 300–600 ms | $16 | None |
ElevenLabs wins on quality and speed but requires proper streaming integration and quota management.
Voice Parameters and Their Impact
| Parameter | Range | Recommendation |
|---|---|---|
| stability | 0–1 | 0.3–0.5 for lively speech, 0.8–1.0 for announcer reading |
| similarity_boost | 0–1 | 0.75–0.9 for accurate timbre, >0.9 may cause artifacts |
| style | 0–1 | 0 for neutral speech, increase for emotionality |
| use_speaker_boost | true/false | Enable by default for synthesized voices |
Stability controls intonation variability: low values make speech more lively, high values make it monotone. similarity_boost determines how accurately the voice copies the original timbre: too high values can cause distortions. Style adds emotional coloring, but for most scenarios 0 is sufficient.
Quota Monitoring
suspend fun checkQuota(textLength: Int): Boolean {
val response = httpClient.get("https://api.elevenlabs.io/v1/user/subscription") {
header("xi-api-key", apiKey)
}.body<SubscriptionInfo>()
return (response.characterLimit - response.characterCount) >= textLength
}
Typical Integration Mistakes
- Not sending an empty message at the end. Without
{"text":""}, the WebSocket does not close properly, and the last seconds of audio are lost. - Ignoring network error handling. WebSocket can break on connectivity loss. Implement automatic reconnection with exponential backoff (1s, 2s, 4s).
What is included in our integration package?
We deliver a comprehensive integration package:
- REST integration with voice settings (stability, similarity_boost, style)
- WebSocket streaming with token feed from LLM
- LRU cache on SHA-256 (up to 100 MB, TTL 30 days)
- Voice selection UI with preview
- Character quota monitoring with notifications
- API key setup and access configuration
- Developer documentation and code samples
- Team training session (1 hour)
- 2 weeks of post-delivery support
Our company metrics: 5+ years of mobile audio experience, 50+ successful projects, 5 years on the market. We guarantee high-quality work delivered on time.
Timelines: Basic REST integration + playback — 2–3 days. Streaming WebSocket with token feed from LLM — 5–7 days. Full voice selection UI + cache + quota monitoring — 10–14 days. Typical integration cost ranges from $500 for basic REST to $2,000 for full WebSocket with caching and UI. The final cost is calculated individually based on your project requirements.
Contact us for a consultation on ElevenLabs integration into your mobile app—we'll assess your project for free. Order the integration with a timeline guarantee and get a ready-made solution without typical mistakes.







