Why a Text‑to‑Speech SaaS?
Voice AI is no longer a niche hobby—businesses are adding audio to blogs, e‑learning platforms, and customer‑support bots every day. Building a Text‑to‑Speech (TTS) SaaS gives you a product you can monetize via subscription, per‑minute usage, or even a free tier with limits.
In this guide you’ll see how to:
- Wire up the ElevenLabs API for high‑quality neural speech and voice cloning.
- Wrap the API in a simple Node.js/Express service that accepts plain text and returns an MP3 file.
- Deploy the whole thing on Bluehost, the affordable hosting platform that makes Node.js apps feel like static sites.
Let’s dive in—no deep‑learning background required, just a bit of JavaScript and a willingness to experiment.
1. Set Up Your Project
# Create a fresh folder
mkdir tts-saas && cd tts-saas
# Initialise npm and install dependencies
npm init -y
npm install express dotenv node-fetch@2
- express – our HTTP server.
- dotenv – keep API keys out of source control.
- node-fetch – simple wrapper for making HTTP calls to ElevenLabs.
Create a .env file (add this to .gitignore later) and paste your ElevenLabs API key:
ELEVENLABS_API_KEY=YOUR_ELEVENLABS_API_KEY
You can obtain a key by signing up at ElevenLabs. Their free tier already gives you several thousand characters per month, which is perfect for prototyping.
2. The Core TTS Route
Create index.js and add the following code:
require('dotenv').config();
const express = require('express');
const fetch = require('node-fetch');
const app = express();
app.use(express.json());
const ELEVENLABS_API = 'https://api.elevenlabs.io/v1/text-to-speech';
const VOICE_ID = 'EXAVITQu4vr4xnSDxMaL'; // default “Rachel” voice – replace with your cloned voice ID
app.post('/synthesize', async (req, res) => {
const { text, voiceId } = req.body;
if (!text) return res.status(400).json({ error: 'Missing `text` field' });
try {
const response = await fetch(`${ELEVENLABS_API}/${voiceId || VOICE_ID}`, {
method: 'POST',
headers: {
'xi-api-key': process.env.ELEVENLABS_API_KEY,
'Content-Type': 'application/json',
Accept: 'audio/mpeg',
},
body: JSON.stringify({
text,
model_id: 'eleven_monolingual_v1',
voice_settings: { stability: 0.75, similarity_boost: 0.85 },
}),
});
if (!response.ok) {
const err = await response.json();
return res.status(response.status).json(err);
}
// Stream the MP3 straight back to the client
res.set('Content-Type', 'audio/mpeg');
response.body.pipe(res);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`🚀 TTS service listening on ${PORT}`));
How It Works
- The route expects a JSON body with a
textfield (and optionally avoiceIdif you’ve cloned a custom voice). - We forward the request to ElevenLabs, ask for an MP3 (
Accept: audio/mpeg), and pipe the response directly to the client. - Errors from the ElevenLabs API surface as proper HTTP status codes, making debugging easy.
Tip: If you’ve created a custom voice clone on ElevenLabs, replace
VOICE_IDwith the clone’s ID or pass it in the request body. Voice cloning works the same way—just a different identifier.
3. Testing Locally with cURL
Run the server:
node index.js
Then fire a quick request:
curl -X POST http://localhost:3000/synthesize \
-H "Content-Type: application/json" \
-d '{"text":"Hello, developer! This is your new TTS API."}' \
--output hello.mp3
You should now have a hello.mp3 file that plays the spoken sentence. If it works locally, you’re ready for the cloud.
4. Deploying to Bluehost
Why Bluehost?
Bluehost offers a simple, affordable way to host Node.js applications without wrestling with complex Docker setups or expensive VPS plans. Their shared hosting environment includes a built‑in Node.js manager, one‑click SSL, and a friendly UI that lets you point a domain to your app in minutes.
Step‑by‑Step Deployment
Create a Bluehost account – sign up via the affiliate link Bluehost. You’ll get a free domain for the first year and a $2.95/mo starter plan that supports Node.js.
-
Upload your code
- Zip the entire project folder (excluding
node_modules). - In the Bluehost cPanel, go to File Manager → Upload and place the zip in
public_html. - Extract the archive.
- Zip the entire project folder (excluding
-
Install dependencies
- Open Terminal from cPanel (or SSH in).
- Navigate to the project folder:
cd public_html/tts-saas - Run
npm install– this will recreatenode_moduleson the server.
-
Configure environment variables
- In cPanel, click Setup Node.js App → Create Application.
- Choose the runtime (e.g., Node 18), set the app’s Document Root to the folder you just uploaded, and add the
ELEVENLABS_API_KEYvariable under Environment Variables.
-
Start the app
- In the same Node.js manager, click Run npm start (or specify
node index.js). - Bluehost will assign a temporary URL like
https://yourdomain.com/tts-saas. Test it with the same cURL command, just replace the host.
- In the same Node.js manager, click Run npm start (or specify
-
Optional: Set a custom subdomain
- Add a DNS A record for
api.yourdomain.compointing to your Bluehost server IP. - Update the Node.js manager’s Domain field to use the subdomain, then restart the app.
- Add a DNS A record for
That’s it! Your TTS SaaS is live, secure, and reachable from anywhere.
5. Adding a Simple Rate‑Limiter (Production‑Ready)
When you open your API to the public, you’ll want to prevent abuse. Here’s a lightweight middleware using the express-rate-limit package:
npm install express-rate-limit
Add it to index.js before the route definitions:
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 30, // max 30 requests per minute per IP
message: { error: 'Too many requests, please try again later.' },
});
app.use(limiter);
Now each IP can only hit the /synthesize endpoint 30 times per minute—enough for most demos while keeping costs under control.
6. Monetizing the Service
With the core API in place, you can layer on:
- API keys per customer stored in a tiny SQLite or MongoDB collection.
- Usage tracking (characters processed) to enforce free‑tier limits.
-
Web dashboard built with React or Vue that lets users type text, pick a voice, and download the MP3—all calling the same
/synthesizeendpoint behind the scenes.
All of these features can live on the same Bluehost account; you only need to add a few more files and a modest database.
7. Next Steps & Resources
-
Voice Cloning – Explore ElevenLabs’ voice‑cloning endpoint to let users upload a short sample and generate a personal voice. The API call is identical; you just swap the
voiceIdwith the newly created clone’s ID. -
SSML Support – ElevenLabs also accepts SSML (Speech Synthesis Markup Language) for richer prosody. Pass an
ssmlfield instead of plaintextif you need pauses, emphasis, or phoneme control. - Caching – Store generated MP3s in a CDN (Cloudflare, BunnyCDN) to reduce repeated calls for the same text.
8. Wrap‑Up
You now have a fully functional Text‑to‑Speech SaaS built with Node.js, powered by ElevenLabs’ state‑of‑the‑art neural voices, and hosted on the Bluehost platform that makes deployment feel as easy as publishing a static site.
Give it a spin, experiment with custom voice clones, and start charging for the minutes you generate. The barrier to entry is low, but the impact—adding a human‑like voice to any product—can be huge.
Ready to build?
- Grab your ElevenLabs API key at ElevenLabs and start generating natural‑sounding speech today.
- Deploy your code in minutes with the affordable, developer‑friendly hosting from Bluehost.
Happy coding, and may your SaaS be as smooth as the voices it produces!
Top comments (0)