DEV Community

VoiceDeveloper
VoiceDeveloper

Posted on

How to Build a Podcast Intro Generator

Why a Podcast Intro Generator?

Every podcast needs a hook—a short, memorable intro that sets the tone, tells listeners what they’re about to hear, and builds brand consistency. Recording a fresh intro for each episode can be tedious, especially for solo creators juggling editing, publishing, and promotion. With modern voice AI and text‑to‑speech (TTS) technology, you can automate that process and generate a polished intro in seconds.

In this post I’ll walk you through building a Podcast Intro Generator that takes a few lines of script, injects your podcast name, and spits out a high‑quality audio file ready for your editing workflow. The core of the solution relies on ElevenLabs, a state‑of‑the‑art TTS service that offers realistic voice cloning and easy API access. Let’s dive in!


High‑Level Architecture

+-------------------+      +--------------------+      +-------------------+
|   User Input      | ---> |  Script Builder    | ---> |  ElevenLabs TTS   |
| (title, tagline) |      | (template + data)  |      |  API (audio file) |
+-------------------+      +--------------------+      +-------------------+
                                      |
                                      v
                              +-----------------+
                              |   Post‑process  |
                              | (fade‑in/out,   |
                              |  normalization)|
                              +-----------------+
                                      |
                                      v
                              +-----------------+
                              |   Output File   |
                              +-----------------+
Enter fullscreen mode Exit fullscreen mode
  1. User Input – Gather episode title, short tagline, and any custom call‑to‑action.
  2. Script Builder – Merge the data into a templated intro script.
  3. ElevenLabs TTS – Send the script to the API, optionally using a cloned voice that sounds like you.
  4. Post‑process – Apply a quick fade‑in/out and normalize loudness so the intro sits nicely with the rest of your episode.
  5. Output – Save as an MP3/WAV ready for your DAW (Audacity, Reaper, etc.).

Getting Started with ElevenLabs

ElevenLabs provides a free tier that’s generous enough for testing, and a paid plan for high‑volume production. The API uses a simple REST interface and returns audio in MP3 format by default.

Quick link: Sign up and grab your API key here → https://try.elevenlabs.io/kr07zfuqn1bp

Once you have the key, you can start sending requests. Below is a minimal Python wrapper that handles authentication, voice selection, and audio retrieval.

import requests
import json
from pathlib import Path

ELEVEN_API_KEY = "YOUR_ELEVENLABS_API_KEY"
BASE_URL = "https://api.elevenlabs.io/v1"

def generate_speech(text: str, voice_id: str = "default", output_path: Path = Path("intro.mp3")):
    """Send a TTS request to ElevenLabs and save the resulting audio."""
    url = f"{BASE_URL}/text-to-speech/{voice_id}"
    headers = {
        "xi-api-key": ELEVEN_API_KEY,
        "Content-Type": "application/json"
    }
    payload = {
        "text": text,
        "model_id": "eleven_monolingual_v1",
        "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
    output_path.write_bytes(response.content)
    print(f"✅ Intro saved to {output_path}")

# Example usage
if __name__ == "__main__":
    script = "Welcome to TechTalk, the podcast where we decode the latest in software engineering. Today we explore serverless architectures."
    generate_speech(script, voice_id="YOUR_CLONED_VOICE_ID")
Enter fullscreen mode Exit fullscreen mode

Tip: If you don’t have a cloned voice yet, create one in the ElevenLabs dashboard. Upload a few seconds of your own voice, and the service will generate a voice_id you can reuse across episodes.


Building the Intro Script Dynamically

Hard‑coding the script defeats the purpose of a generator. Instead, use Python’s f‑strings or a small templating engine like Jinja2 to inject episode‑specific data.

from jinja2 import Template

INTRO_TEMPLATE = """
Welcome to {{ podcast_name }}, the show that {{ tagline }}.
In today's episode, "{{ episode_title }}", we'll dive into {{ episode_topic }}.
Stay tuned!
"""

def build_intro(podcast_name, tagline, episode_title, episode_topic):
    tmpl = Template(INTRO_TEMPLATE.strip())
    return tmpl.render(
        podcast_name=podcast_name,
        tagline=tagline,
        episode_title=episode_title,
        episode_topic=episode_topic
    )
Enter fullscreen mode Exit fullscreen mode

Now you can call build_intro() with data from a CSV, a content management system, or even a simple CLI prompt.

script = build_intro(
    podcast_name="DevBytes",
    tagline="break down complex dev topics into bite‑size episodes",
    episode_title="Zero‑Trust Security",
    episode_topic="how to implement zero‑trust in cloud-native apps"
)
print(script)
Enter fullscreen mode Exit fullscreen mode

The output will be a ready‑to‑speak string that you feed into generate_speech() from the previous section.


Adding a Quick Fade‑In/Out with Pydub

Most podcasts prefer a 0.5‑second fade‑in and fade‑out to smooth the transition. The pydub library makes this trivial.

from pydub import AudioSegment

def add_fade(audio_path: Path, fade_ms: int = 500) -> Path:
    audio = AudioSegment.from_file(audio_path)
    faded = audio.fade_in(fade_ms).fade_out(fade_ms)
    out_path = audio_path.with_name(f"{audio_path.stem}_faded{audio_path.suffix}")
    faded.export(out_path, format="mp3")
    return out_path

# After generating the raw intro:
raw_path = Path("intro.mp3")
faded_path = add_fade(raw_path)
print(f"✅ Faded intro saved to {faded_path}")
Enter fullscreen mode Exit fullscreen mode

Combine the steps into a single function for convenience:

def generate_podcast_intro(data: dict, voice_id: str, out_dir: Path = Path(".")):
    script = build_intro(**data)
    raw_file = out_dir / "intro_raw.mp3"
    generate_speech(script, voice_id=voice_id, output_path=raw_file)
    final_file = add_fade(raw_file)
    return final_file
Enter fullscreen mode Exit fullscreen mode

Putting It All Together – A Minimal CLI

If you like the terminal, here’s a tiny click‑based CLI that ties everything together.

import click
from pathlib import Path

@click.command()
@click.option("--podcast", prompt="Podcast name", help="Your podcast's name")
@click.option("--tagline", prompt="Tagline", help="A short description of your show")
@click.option("--title", prompt="Episode title", help="Current episode's title")
@click.option("--topic", prompt="Episode topic", help="What you’ll discuss")
@click.option("--voice-id", prompt="ElevenLabs voice ID", help="Your cloned voice")
def main(podcast, tagline, title, topic, voice_id):
    data = {
        "podcast_name": podcast,
        "tagline": tagline,
        "episode_title": title,
        "episode_topic": topic,
    }
    out_file = generate_podcast_intro(data, voice_id, out_dir=Path("outputs"))
    click.echo(f"✅ Your intro is ready: {out_file}")

if __name__ == "__main__":
    main()
Enter fullscreen mode Exit fullscreen mode

Run it with:

$ python generate_intro.py
Enter fullscreen mode Exit fullscreen mode

You’ll be prompted for the details, and within seconds a polished intro file lands in the outputs/ folder.


Going Beyond: Adding Background Music

A subtle music bed can elevate the vibe. Grab a royalty‑free loop (e.g., from Free Music Archive) and mix it with the spoken intro using pydub’s overlay:

def add_music(intro_path: Path, music_path: Path, music_volume_db: int = -15) -> Path:
    intro = AudioSegment.from_file(intro_path)
    music = AudioSegment.from_file(music_path).apply_gain(music_volume_db)
    # Loop music if shorter than intro
    if len(music) < len(intro):
        repeats = (len(intro) // len(music)) + 1
        music = music * repeats
    mixed = intro.overlay(music[:len(intro)])
    out_path = intro_path.with_name(f"{intro_path.stem}_with_music{intro_path.suffix}")
    mixed.export(out_path, format="mp3")
    return out_path
Enter fullscreen mode Exit fullscreen mode

Now you can call add_music(faded_path, Path("assets/loop.mp3")) to produce a final, broadcast‑ready intro.


Production Tips

Tip Why it matters
Use a consistent voice Listeners associate a particular timbre with your brand. Clone your own voice once and stick to that voice_id.
Keep scripts under 30 seconds Longer TTS runs increase latency and can sound less natural. Short intros stay punchy.
Normalize loudness to -16 LUFS Most podcast platforms target -16 LUFS; use pydub or ffmpeg to batch‑normalize if you have many episodes.
Cache generated intros If you re‑run the same script, store the MP3 locally to avoid unnecessary API calls (and save credits).

Wrapping Up

You now have a complete, end‑to‑end pipeline:

  1. Gather episode metadata.
  2. Build a dynamic script with Jinja2.
  3. Send it to ElevenLabs for ultra‑realistic speech synthesis.
  4. Add fades, optional music, and normalization.
  5. Drop the final MP3 into your podcast workflow.

All of this can be automated in a CI/CD job, a GitHub Action, or a simple cron script—so each new episode gets a fresh intro without you lifting a finger.


Ready to give it a spin?

If you’re curious about how realistic voice cloning can streamline your podcast production, head over to ElevenLabs and grab your API key: https://try.elevenlabs.io/kr07zfuqn1bp.

Plug the key into the snippets above, and you’ll have a custom intro generator up and running in minutes. Happy coding, and may your podcasts always start with a bang!

Top comments (0)