Build and Host a Text-to-Speech SaaS with Node.js and Bluehost
Why a Text‑to‑Speech SaaS? Voice AI is moving from novelty to necessity. From accessibility tools to interactive podcasts, developers are building apps that turn text into natural‑sounding speech in real time. The swee
Why a Text‑to‑Speech SaaS?
Voice AI is moving from novelty to necessity. From accessibility tools to interactive podcasts, developers are building apps that turn text into natural‑sounding speech in real time. The sweet spot for a SaaS product is a simple REST endpoint that accepts a string, optional voice parameters, and returns an audio file—nothing more, nothing less. In this guide we’ll:
- Spin up a tiny Node.js service that talks to the ElevenLabs API.
- Package the app for production (environment variables, error handling, logging).
- Deploy it on Bluehost, the affordable host that makes Node.js deployment painless.
Grab an ElevenLabs account (you’ll need an API key) and a Bluehost account using the links below, then let’s get coding.
1. Set Up the Project
# Create a fresh folder
mkdir tts-saas && cd tts-saas
# Initialize a Node project
npm init -y
# Install dependencies
npm install express axios dotenv
- express – lightweight web framework for our API.
- axios – HTTP client to call ElevenLabs.
- dotenv – keep secrets (API keys) out of source control.
Create a .env file (never commit this!) and paste your ElevenLabs API key:
ELEVENLABS_API_KEY=your_api_key_here
PORT=3000
2. Build the TTS Endpoint
Create index.js:
require('dotenv').config();
const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
const ELEVEN_API = 'https://api.elevenlabs.io/v1';
// Helper to call ElevenLabs TTS
async function synthesize(text, voice = 'en_us_001') {
const response = await axios.post(
`${ELEVEN_API}/text-to-speech/${voice}`,
{
text,
// optional: model_id, voice_settings, etc.
},
{
responseType: 'arraybuffer',
headers: {
'xi-api-key': process.env.ELEVENLABS_API_KEY,
'Content-Type': 'application/json',
},
}
);
return response.data; // raw audio bytes (MP3)
}
// POST /speak
app.post('/speak', async (req, res) => {
const { text, voice } = req.body;
if (!text) {
return res.status(400).json({ error: 'Missing "text" in request body.' });
}
try {
const audio = await synthesize(text, voice);
res.set({
'Content-Type': 'audio/mpeg',
'Content-Length': audio.length,
});
res.send(audio);
} catch (err) {
console.error('ElevenLabs error:', err.response?.data || err.message);
res.status(502).json({ error: 'Failed to generate speech.' });
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`🚀 TTS SaaS listening on http://localhost:${PORT}`);
});
Why ElevenLabs?
The ElevenLabs platform offers some of the most natural���sounding voice models on the market, with a generous free tier for testing and a straightforward API. You can swap voices by passing a different voice ID, or even create custom clones once you’ve collected enough training data.
3. Test Locally
node index.js
In another terminal:
curl -X POST http://localhost:3000/speak \
-H "Content-Type: application/json" \
-d '{"text":"Hello, world! This is a Node.js TTS SaaS."}'
You should receive an MP3 stream that you can pipe into a file:
curl -X POST http://localhost:3000/speak \
-H "Content-Type: application/json" \
-d '{"text":"Testing locally"}' > output.mp3
Play output.mp3 with your favorite media player—voilà, you have a working service!
4. Prepare for Production
a. Add a Basic Logger
const morgan = require('morgan');
app.use(morgan('combined'));
Install with npm i morgan. This gives you request logs that are useful on a live server.
b. Secure the Endpoint (optional)
If you plan to expose the API publicly, consider a simple API key header:
const CLIENT_KEY = process.env.CLIENT_KEY; // set in .env
app.use((req, res, next) => {
const key = req.headers['x-client-key'];
if (!key || key !== CLIENT_KEY) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
});
Add CLIENT_KEY=some_secret to .env.
c. Add a Health Check
app.get('/health', (req, res) => res.json({ status: 'ok' }));
5. Deploy to Bluehost
Bluehost isn’t just for WordPress sites; its shared hosting plans now include Node.js support via the cPanel “Setup Node.js App” wizard. The process is quick, inexpensive, and perfect for a lightweight SaaS like this.
Step‑by‑Step Deployment
Create a Bluehost account – use the affiliate link: https://bluehost.sjv.io/5k0d52. Their entry‑level plan gives you 50 GB SSD storage and unlimited bandwidth, more than enough for a modest TTS API.
Log into cPanel and look for “Setup Node.js App” under the Software section.
-
Click Create Application:
- Node version – choose the latest LTS (e.g., 20.x).
- Application mode – Production.
-
Application root –
~/tts-saas. -
Application URL – set to something like
https://yourdomain.com. -
Startup file –
index.js.
Upload your code. The easiest way is to zip the project (excluding
node_modules) and use the File Manager to upload and extract it into the application root.Install dependencies from the terminal provided in the Node.js app interface:
cd ~/tts-saas
npm install
-
Add environment variables in the same cPanel panel:
-
ELEVENLABS_API_KEY– your ElevenLabs key. -
PORT– leave blank; Bluehost will inject the correct port. - (Optional)
CLIENT_KEYif you secured the endpoint.
-
Start the app with the “Run NPM Start” button or by typing:
npm start
The wizard automatically creates a reverse proxy so your endpoint is reachable at https://yourdomain.com/speak.
- Test the live service:
curl -X POST https://yourdomain.com/speak \
-H "Content-Type: application/json" \
-d '{"text":"Hello from Bluehost!"}' > live.mp3
If you hear the audio, congratulations—you’ve just turned a few lines of Node.js into a fully hosted text‑to‑speech SaaS.
Why Bluehost?
- Affordability – starts at a few dollars a month, ideal for early‑stage projects.
- Simplicity – the cPanel UI handles Node.js setup, environment variables, and process management without needing a full VPS.
- Scalability – when traffic grows, you can upgrade to a VPS or dedicated server with a single click.
6. Next Steps & Enhancements
| Feature | How to Implement |
|---|---|
| Voice cloning | Use ElevenLabs’ “Create Voice” endpoint to upload a few minutes of a speaker’s audio, then call the new voice ID in your /speak request. |
| Rate limiting | Add a middleware like express-rate-limit to protect your API from abuse. |
| Caching | Store recently generated MP3s in a Redis cache (or even a simple file cache) to avoid duplicate API calls. |
| Billing | Integrate Stripe or Paddle to charge per‑minute usage, turning your demo into a revenue stream. |
| Web UI | Build a tiny React front‑end that posts text and streams back audio for quick testing. |
All of these can be added without changing the core architecture we just built.
7. Wrap‑Up
You now have:
- A Node.js microservice that leverages the high‑quality voices of ElevenLabs.
- A production‑ready deployment on Bluehost, the budget‑friendly host that makes Node.js apps feel like a one‑click experience.
- A solid foundation to iterate, monetize, and scale your own voice AI product.
Ready to give your users a voice?
👉 Try ElevenLabs today: https://try.elevenlabs.io/kr07zfuqn1bp
👉 Deploy instantly with Bluehost: https://bluehost.sjv.io/5k0d52
Happy coding, and may your SaaS speak loudly!
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.