DEV Community

VoiceDeveloper
VoiceDeveloper

Posted on

How to Set Up a Voice-Enabled Blog with AI Narration

Why Add AI Narration to Your Blog?

If you’ve ever scrolled through a long article and thought, “I wish I could listen to this while I’m cooking or jogging,” you’re not alone. Voice‑enabled content is exploding—think podcasts, audiobooks, and even AI‑generated narrations that turn any text into a natural‑sounding voice. Adding an audio version of each post can:

  • Boost SEO (Google likes rich media)
  • Increase accessibility for visually‑impaired readers
  • Keep visitors on your site longer, which improves engagement metrics
  • Open a new channel for content distribution (e.g., you can embed the audio in newsletters or social posts)

In this post I’ll walk you through a complete, end‑to‑end setup that lets you automatically generate a spoken version of every new blog entry, host it on a cheap but reliable platform, and embed the audio player right in your article. The stack is intentionally simple:

Component What it does Why we like it
ElevenLabs State‑of‑the‑art text‑to‑speech (TTS) and voice cloning Natural, expressive voices; generous free tier; easy HTTP API
Python Glue code that pulls the latest post, calls the TTS API, and uploads the MP3 Quick to prototype, widely available
Bluehost Shared hosting that supports Python scripts (via SSH) and static site hosting Affordable, one‑click WordPress install, and a friendly UI for beginners

TL;DR – Use ElevenLabs for the narration, write a small Python script to fetch your post and generate an MP3, then push the file to a Bluehost site where you embed a simple HTML5 player.


1. Get Your ElevenLabs API Key

Head over to the ElevenLabs sign‑up page: https://try.elevenlabs.io/kr07zfuqn1bp. After confirming your email you’ll land on the dashboard where you can create an API key. Keep this key secret—treat it like a password.

Tip: Store the key in an environment variable (ELEVENLABS_API_KEY) rather than hard‑coding it. This keeps your repo clean and prevents accidental leaks.


2. Set Up a Basic Python Project

Create a new folder for the project and initialize a virtual environment:

mkdir voice-blog
cd voice-blog
python3 -m venv .venv
source .venv/bin/activate
pip install requests python-dotenv
Enter fullscreen mode Exit fullscreen mode

Create a .env file (make sure you add it to .gitignore) and paste your API key:

ELEVENLABS_API_KEY=your_api_key_here
Enter fullscreen mode Exit fullscreen mode

Install python-dotenv so the script can read it automatically.


3. Pull the Latest Blog Post

For this tutorial I’ll assume you’re using a static Markdown‑based blog (e.g., Jekyll, Hugo, or a simple Markdown folder). The script below reads the most recent .md file, strips the front‑matter, and returns the raw text.

import os
import glob
import re
from pathlib import Path

def get_latest_post():
    md_files = sorted(Path("posts").glob("*.md"), key=os.path.getmtime, reverse=True)
    if not md_files:
        raise FileNotFoundError("No markdown files found in ./posts")
    latest = md_files[0]
    with open(latest, "r", encoding="utf-8") as f:
        content = f.read()
    # Remove YAML front‑matter if present
    cleaned = re.sub(r"^---.*?---\s*", "", content, flags=re.DOTALL)
    return cleaned.strip(), latest.stem  # returns (text, slug)

text, slug = get_latest_post()
print(f"Generating narration for: {slug}")
Enter fullscreen mode Exit fullscreen mode

Feel free to replace the file‑system logic with a WordPress REST call or any CMS API you prefer.


4. Call ElevenLabs to Generate Speech

ElevenLabs provides a straightforward /v1/text-to-speech/{voice_id} endpoint. Below is a minimal curl‑style request wrapped in Python using requests.

import requests
import json
from dotenv import load_dotenv

load_dotenv()
API_KEY = os.getenv("ELEVENLABS_API_KEY")
VOICE_ID = "EXAVITQu4vr4xnSDxMaL"  # default “Rachel” voice – change as you like

def synthesize(text, output_path):
    url = f"https://api.elevenlabs.io/v1/text-to-speech/{VOICE_ID}"
    headers = {
        "xi-api-key": API_KEY,
        "Content-Type": "application/json"
    }
    payload = {
        "text": text,
        "model_id": "eleven_multilingual_v2",
        "voice_settings": {
            "stability": 0.75,
            "similarity_boost": 0.85
        }
    }

    response = requests.post(url, headers=headers, json=payload)
    response.raise_for_status()

    # The API returns raw audio bytes (MP3)
    with open(output_path, "wb") as out_file:
        out_file.write(response.content)
    print(f"Saved audio to {output_path}")

audio_file = f"public/audio/{slug}.mp3"
synthesize(text, audio_file)
Enter fullscreen mode Exit fullscreen mode

Why ElevenLabs? Their voices sound genuinely human, they support multiple languages out of the box, and the API is fast enough for on‑the‑fly generation. You can experiment with different voice IDs or even upload a custom voice clone if you have a sample of your own speaking style. Check out the full docs at https://try.elevenlabs.io/kr07zfuqn1bp.


5. Deploy the Audio Files on Bluehost

If you already have a WordPress blog on Bluehost, simply drop the generated MP3 into the wp-content/uploads folder via FTP or the file manager. For static sites, the public/audio folder we used above maps directly to a public URL.

Quick deployment steps

  1. Create a Bluehost account – use the affiliate link for a discount: https://bluehost.sjv.io/5k0d52.
  2. In the Bluehost dashboard, enable SSH Access (found under “Advanced → SSH Access”). This lets you run the Python script directly on the server if you prefer.
  3. Upload your public/audio directory (or just the new MP3) using the File Manager or an SFTP client.
  4. Make sure the file permissions are set to 644 so the browser can fetch it.

Pro tip: Set up a cron job in Bluehost’s “Cron Jobs” UI to run the script nightly. That way every new post automatically gets an audio version without manual intervention.


6. Embed the Player in Your Blog Post

Now that the MP3 lives at something like https://yourdomain.com/audio/my‑post.mp3, you can embed a native HTML5 player directly in the Markdown file (or via a WordPress block).

<audio controls preload="none" style="width: 100%;">
  <source src="https://yourdomain.com/audio/{{ slug }}.mp3" type="audio/mpeg">
  Your browser does not support the audio element.
</audio>
Enter fullscreen mode Exit fullscreen mode

If you’re using a static site generator, replace {{ slug }} with the appropriate variable syntax (e.g., {{ .Slug }} for Hugo). The player will appear right beneath the article title, giving readers a one‑click way to listen.


7. Automate the Whole Pipeline (Optional)

For a fully hands‑off workflow you can combine everything into a single script and trigger it via a webhook whenever you push a new post to Git. Here’s a high‑level view:

#!/usr/bin/env bash
# 1. Pull latest changes
git pull origin main

# 2. Run the Python generator
source .venv/bin/activate
python generate_narration.py

# 3. Upload the MP3 via rsync (Bluehost supports SSH)
rsync -avz public/audio/ user@yourdomain.com:/home/username/public_html/audio/
Enter fullscreen mode Exit fullscreen mode

Add the script to a GitHub Action or a Bluehost cron job, and you’ve got a self‑maintaining voice‑enabled blog.


8. Troubleshooting Common Issues

Symptom Likely Cause Fix
401 Unauthorized from ElevenLabs Wrong or missing API key Verify ELEVENLABS_API_KEY in .env and that the environment variable is loaded
Audio file is garbled or silent Incorrect voice_settings or model ID Try the default settings or test with the ElevenLabs playground first
MP3 not loading on the page File not uploaded or wrong URL Double‑check the path you used in the <audio> tag matches the location on Bluehost
Cron job never runs Wrong path to Python binary Use the full path (/home/username/.venv/bin/python) in the cron entry

9. Scaling Up

If your blog starts receiving thousands of daily reads, consider:

  • Caching the generated MP3s on a CDN (Bluehost CDN add‑on works well).
  • Batch processing – generate narrations in bulk during off‑peak hours.
  • Custom voice cloning – ElevenLabs lets you train a voice on your own recordings, giving your brand a unique sound.

10. Wrap‑Up & Next Steps

You now have a functional pipeline:

  1. Write a post →
  2. Python script pulls the markdown →
  3. ElevenLabs turns the text into an MP3 →
  4. The file lands on a Bluehost‑hosted site →
  5. Readers click the embedded player and listen.

Give it a spin! The combination of ElevenLabs for high‑quality AI narration and Bluehost for low‑cost, hassle‑free hosting makes voice‑enabled blogging accessible to anyone with a laptop.


Ready to make your blog talk?

Start by signing up for ElevenLabs here: https://try.elevenlabs.io/kr07zfuqn1bp and grab a reliable, affordable hosting plan at Bluehost: https://bluehost.sjv.io/5k0d52. Happy coding, and enjoy the sound of your own words!

Top comments (0)