Build with AI

I replaced a paid voice subscription with Gemini TTS for two brands. Here is where it broke

The Vibe Gate·September 20, 2026·9 min read

I used to treat voiceover as a line item. Two brands, one Arabic and one English, both shipping short video on a schedule, both needing a narrator who never gets sick of reading forty seconds of copy. For a while that meant a subscription, and the subscription meant I rationed clips: is this short worth burning credits on?

Since early August every second of narration on both brands has come out of Gemini's text-to-speech models, and my spend on voice is zero. That part is easy to write and easy to oversell, so here is the other half — the three places it broke on me, what each one cost, and the one job I still pay a vendor for.

Disclosure: the ElevenLabs link below is an affiliate link — if you subscribe through it I earn a commission at no extra cost to you. I'm leaving it in a post that is mostly about not needing it, because there is exactly one job in my pipeline where the free path failed twice and the paid one worked. Prices and limits here were checked against the official pages on September 19, 2026, and they're all linked at the bottom.

What I actually replaced

Not a workflow, a habit. The old loop was: write the script, open a web app, paste, generate, download, rename, drag into the edit. Fine once. Miserable at four shorts a week across two languages.

The new loop is a script that takes a text file and returns audio files. Gemini's TTS models are plain API calls — text in, audio out, nothing else in the response. You get raw PCM at 24kHz, 16-bit, which you wrap as WAV and convert with ffmpeg. Google documents three models that do this: Gemini 3.1 Flash TTS Preview, 2.5 Flash Preview TTS, and 2.5 Pro Preview TTS. The first two are free on the free tier. The Pro one isn't free at all, which surprised me and is worth knowing before you build around it.

The thing that makes it usable for a second language is that Arabic isn't a footnote. The docs list Arabic among 100-plus supported languages and variants, under the plain code ar. No regional split, no separate endpoint, no "beta for non-English." That single fact is why I could collapse two pipelines into one.

The voices, and why I picked the boring ones

There are 30 prebuilt voices, each with a one-word character note in the docs — Bright for Zephyr, Warm for Sulafat, and so on. I use Charon for Arabic and Rasalgethi for English. Both are labeled Informative.

That match is deliberate and it's the only piece of taste in this whole setup. A viewer who watches an English clip and then an Arabic one shouldn't feel the narrator change personality. Picking two voices with the same documented character got me closer to that than picking the two best voices would have.

You can also steer delivery with a plain-English instruction in the prompt — Google's own example is "Say in a spooky whisper." It works. It also caused my third problem, below.

Break one: ten requests a day

Google's rate-limit page doesn't publish free-tier numbers anymore. It tells you limits depend on your tier and sends you to your own AI Studio dashboard. Mine displayed roughly 15 requests per day. The number that actually governs my work is different: when I hit the wall, the rejection payload carried quotaValue: 10, scoped to the model name.

So: ten requests per day, per model, counted separately. The "separately" is the useful half. The evening 3.1 died on me at sentence five of a short, I switched the script to 2.5, and it finished on that model's own untouched quota. Rule I'd pass on: when you switch models mid-job, regenerate every line on the new one. Two models in one narration is audible — not as a glitch, as a person who changed mood halfway through.

The tighter constraint day to day is three requests per minute. My script spaces calls 22 seconds apart and retries automatically on a 429. And a small trap worth naming: a burst of quick test calls trips the per-minute limit and throws a red banner that reads like you're done for the day. You're not. It clears in a minute.

The day that actually hurt was August 8. I sat down to build a narration and found both models' daily quotas already spent before I'd generated anything — most likely by my own scheduled jobs running earlier. 3.1 refused the first call, 2.5 gave me five sentences and quit. Free tiers don't reserve capacity for you just because you planned your evening around them.

Break two: no timestamps, at all

This is the one that would have stopped the project if I'd found it later.

The response contains audio and nothing else. No sentence marks, no word timings, no metadata — the docs don't mention timing information anywhere, and there is no flag to turn it on. If you're building video that cuts on narration, timings are the thing you actually need; the audio is almost incidental.

What I do instead is mechanical: one sentence per request, measure each file's duration with ffprobe, build a marks file by accumulating offsets plus a fixed gap between lines, then concatenate with ffmpeg. The output is a timings file in the same shape that other engines hand you for free.

There's an accidental benefit. Every line is its own file, so cutting a sentence after hearing the rough mix means deleting a file and re-concatenating — no regeneration, no quota spent. That single property has saved me more requests than any optimization I planned.

Break three: a name it won't say

My Arabic brand's name carries a vowel mark that changes how it's pronounced. On 3.1 the model gets it wrong even when the word is written with full diacritics. Add a style instruction telling it how to pronounce the name and it says it correctly — and inserts a noticeable pause right before it, as if bracing for the word. On 2.5 it's pronounced correctly with no pause, but the voice quality is a step down.

Correct pronunciation or no pause, pick one. I didn't solve it; I routed around it. The narration never says the name. The line became "our corner" instead of "the X corner," and the wordmark sits on screen at that exact moment. The tradeoff disappears and the branding still lands — through the eye instead of the ear.

I'm writing it down because it's still open, and because it's the kind of failure you won't find in a model card. Style prompting is real control, with a real timing cost attached.

Count characters before you generate

When every request is rationed, a re-run is expensive. So I measure first. On a real short I clocked Charon reading Arabic at about 9.5 characters per second on 3.1, and about 10.6 on 2.5. My working rule: seconds ≈ characters ÷ 10, plus a fraction of a second per gap.

The rule exists because I ignored it once. A 628-character script aimed at a 50-second short came back at 66 seconds. Rewritten to 413 characters, it came back at 39. That correction cost real requests out of a daily allowance of ten — which is the whole argument for doing arithmetic on your script before you spend a call on it.

Where I still pay

My ladder is fixed: Gemini first, Amazon Polly second, ElevenLabs third. I only step down when something is genuinely blocked.

Polly handles two cases: long episodes of forty-odd sentences, which are impossible against ten daily requests, and days when both Gemini quotas are gone. It has no per-minute friction, its neural voices are $16 per million characters with a million free per month for the first year, and — relevant to my second problem — it returns real speech marks. Its newer generative voices cost $30 per million and the free allowance drops to 100,000 characters a month, listed for speech requests rather than speech marks, so they don't solve the timing problem the cheaper tier does.

One Polly rule I learned by breaking it: wrap every English product name inside an Arabic sentence in an SSML <lang xml:lang="en-US"> tag. AWS lists full support for that tag on neural voices. Skip it and the engine transliterates brand names phonetically, which is the single most obvious tell that a voice is synthetic.

And the paid step: Saudi colloquial Arabic. I tested Polly on it twice, once without diacritics and once with light diacritics and a Gulf locale code. Both were rejected as distorted — not marginal, unusable. That's the job ElevenLabs does in my stack, and it's the only recurring cost.

Their free plan is worth reading carefully before you count on it: 10,000 credits a month, and no commercial license. Commercial use starts at Starter, $6/month for 30,000 credits; Creator is $22 for 121,000 (half off the first month); Pro is $99 for 600,000. If you're monetizing the output, the free tier isn't a cheaper option — it's the wrong option.

What it would cost if the free ride ended

Worth knowing, because free tiers move. Paid rates for 3.1 are $1 per million input tokens and $20 per million audio output tokens; 2.5 Flash is half that. I measured one 5.5-second clip at 25 text tokens and 184 audio tokens — roughly 34 audio tokens per second of speech.

Run the arithmetic and 3.1 lands near four cents a minute. A 40-second short: under three cents. A three-minute explainer: about twelve.

Which reframes the whole exercise. I didn't switch to save money — at those rates there's barely money to save. I switched because an API call fits inside a script and a web app doesn't, and because rationing clips against a credit balance was quietly shaping what I made. The daily cap replaced that with a different constraint, but it's an honest one: it limits how many requests I make, not which ideas are worth trying.

If you're deciding: take the free path for standard-register narration in either language, budget an afternoon for the timing plumbing, and keep a paid account for dialect and voice cloning. That's the whole map, including the parts that broke.

Sources

Facts and prices checked September 20, 2026:

Get the next guide, first.

One email when a new build log or review ships. No noise, ever.