Unlimited multilingual TTS for web and Node.js at a predictable low cost
Cheap TTS combines an intelligent voice API with efficient SDK runtimes to deliver natural audio with unlimited generation. Get language-aware text processing, curated voices, and fast repeat performance through one simple integration.
Browser quickstart
Activate a paid plan, create a project, register your browser origins, then initialize the package with its publishable key.
Install the public package from npm.
npm install @cheap-tts/browser-sdk
import { CheapTts } from "@cheap-tts/browser-sdk";
const tts = new CheapTts({
publishableKey: "pk_live_your_project",
});
const result = await tts.synthesize({
text: "Xin chào từ Cheap TTS.",
voice: "vi-entertainment",
});
audio.src = URL.createObjectURL(result.audio);
await audio.play();
Open the live browser example →
pk_test_local against http://localhost:5173. Dashboard keys only work on origins trusted for their project.Generate voice in your backend
Cheap TTS gives backend applications unlimited generation, the complete curated voice catalog, and a language-aware pipeline at a predictable low cost. Reusable local assets keep repeat generation efficient and fast.
Install the public package from npm.
npm install @cheap-tts/node
import { CheapTts } from "@cheap-tts/node";
const tts = new CheapTts({
secretKey: process.env.CHEAP_TTS_SECRET_KEY,
});
const result = await tts.synthesize({
text: "Xin chào từ Cheap TTS.",
voice: "vi-entertainment",
});
await result.save("./audio.wav");
await tts.destroy();
sk_live_... key in Dashboard and store it in an environment variable. Never expose this key in browser code or a public repository.Warm up a voice
Call loadVoice() when a worker starts so the first generation request is ready sooner. The SDK automatically manages reusable voice assets in its local cache.
await tts.loadVoice({
voice: "en-narration",
onProgress: ({ progress }) => console.log(progress),
});
Node API reference
| Method | Returns | Purpose |
|---|---|---|
tts.voices() | CheapTtsVoice[] | List the enabled voice catalog. |
tts.loadVoice(options) | CheapTtsVoice | Prepare one voice before generation. |
tts.synthesize(options) | { audio, seconds, voice, save } | Generate a WAV as a Node.js Buffer. |
tts.clearCache() | void | Remove SDK-managed local voice assets. |
tts.destroy() | void | Release the active voice runtime. |
Discover voices
Use stable voice IDs to select a language, voice style, and use case.
const voices = await tts.voices();
// Filter the curated voices for one language
const vietnamese = voices.filter((voice) => voice.language === "vi");
| Voice ID | Language | Use case |
|---|---|---|
vi-entertainment | Vietnamese | Entertainment |
vi-commentary | Vietnamese | Commentary |
en-narration | English | Narration |
en-review | English | Review |
+99 more curated voices across 41 more languagesUnlock all voices | ||
Show browser progress
Preload the selected voice before enabling generation. The SDK handles voice loading and reuses it on later visits when browser storage is available.
await tts.loadVoice({
voice: "en-narration",
onProgress: ({ progress }) => {
console.log(progress); // 0..1, or null
},
});
await tts.synthesize({
text,
voice: "en-narration",
rate: 1.1,
onProgress: ({ stage, progress }) => {
console.log(stage, progress); // 0..1, or null
},
});
Browser API reference
new CheapTts(options)
| Option | Type | Description |
|---|---|---|
publishableKey | string | Required browser-safe project key. |
apiBase | string | Optional API base URL. Defaults to Cheap TTS production. |
workerUrl | string | Optional custom URL for the packaged module worker. |
vendorBase | string | Optional custom URL for WASM runtime files. |
tts.voices()
Returns the enabled voice catalog as { id, name, language, useCase }[].
tts.synthesize(options)
Returns { audio, arrayBuffer, seconds, voice }. audio is a browser-ready audio/wav Blob.
tts.destroy()
Terminates the worker and rejects active jobs. Call this when permanently unmounting the integration.
Browser access security
A publishable key is expected to be visible in frontend code. It is not a secret and does not grant access by itself.
- The key is accepted only from origins trusted for your project.
- An active paid subscription is checked when sessions are created and text is prepared.
- The SDK exchanges it for a signed, short-lived browser session.
- Text preparation requires that session and is rate limited.
- Never place a Node or server secret key in browser code.
Common errors
| Message | What to check |
|---|---|
| Publishable key or origin is not allowed | Register the exact scheme and domain used by the app. |
| Invalid server key | Use an active sk_live_... key from Dashboard only in a Node.js environment. |
| Active subscription is required | Choose a paid plan in Dashboard, or update the payment method if the subscription is past due. |
| Invalid or expired browser session | Retry the request; the SDK automatically refreshes normal sessions. |
| Voice loading failed | Check network access and available browser storage. |
| Unknown voice | Use a current ID returned by tts.voices(). |
Ready to add multilingual voice?
Choose a plan, create an API project, and ship with the full voice catalog.