← Back to blog

Turn YouTube Podcasts into Blog Posts Automatically

Zied · 7/30/2026 · 8 min read

Turn YouTube Podcasts into Blog Posts Automatically

Turn YouTube Podcasts into Blog Posts Automatically

A 90-minute podcast episode contains more structured thinking than most blog posts published in a week. The problem is that almost none of it ever becomes searchable text. Here is a practical workflow that changes that, using the transcript as the raw material and an LLM as the editor.

Why Podcast Episodes Are Worth Repurposing

YouTube is now the largest podcast platform, with more than a third of podcast listeners tuning in there according to Edison Research data published by Backlinko. Long-form episodes regularly run 45 to 120 minutes, which means each one contains thousands of words of structured conversation: problem statements, case studies, disagreements, and advice.

That content is invisible to search engines until someone writes it down. Converting it to a blog post does several things at once: it surfaces the episode for readers who prefer text, it creates internal linking opportunities across your content library, and it gives you quotable material for social posts without watching the video again.

The workflow is not complicated. You fetch the full transcript as JSON, split it into sections that match the episode's structure, send those sections to an LLM with a clear prompt, and write out a draft with timestamps pointing back to the video.

Podcast microphone in a recording studio

Downloading the Full Transcript

The YouTube Transcriber API exposes a single GET endpoint that returns the complete transcript as JSON:

curl "https://getyoutubetranscriber.com/api/v2/transcript?video_url=VIDEO_ID&send_metadata=true" \
  -H "Authorization: Bearer YOUR_API_KEY"

The send_metadata=true parameter adds the video title and channel name to the response, which you will need when writing the blog introduction. The response looks like this:

{
  "video_id": "dQw4w9WgXcQ",
  "language": "en",
  "title": "How We Scaled to 10M Users with Three Engineers",
  "author_name": "Lenny's Podcast",
  "transcript": [
    { "text": "Welcome back. Today we're covering three ways to reduce churn.", "start": 0.0, "duration": 4.2 },
    { "text": "The first one is probably the most counterintuitive.", "start": 4.2, "duration": 3.1 },
    { "text": "You actually want to talk to churned users immediately.", "start": 7.3, "duration": 4.8 }
  ]
}

Each segment has a start value in seconds. That is the key field for everything downstream: section boundaries, quote attribution, and timestamp links.

One practical note: long podcast episodes often have 1,500 to 3,000 transcript segments. Load the full array into memory before processing; do not attempt to stream and segment simultaneously, because the chapter boundaries you will define next rely on the global start times.

For a related look at handling caption types and quality, see YouTube Captions API: Auto vs Manual Captions Explained, which covers when auto-generated captions are reliable enough for this kind of pipeline.

Segmenting the Episode into Chapters

Most podcast episodes follow a loose structure: intro, topic one, topic two, and so on. You have two ways to find those breaks.

Option 1: Time-based windows. Split the transcript into fixed chunks, for example every 10 minutes (600 seconds). This is the simplest approach and works well for interview-format podcasts where the conversation shifts gradually.

def chunk_by_time(segments, window_seconds=600):
    chunks = []
    current_chunk = []
    chunk_start = 0.0

    for seg in segments:
        if seg["start"] - chunk_start >= window_seconds and current_chunk:
            chunks.append({"start": chunk_start, "segments": current_chunk})
            chunk_start = seg["start"]
            current_chunk = []
        current_chunk.append(seg)

    if current_chunk:
        chunks.append({"start": chunk_start, "segments": current_chunk})

    return chunks

Option 2: Topic-shift detection. Ask an LLM to read a sliding window of segments and identify where the topic changes. This produces cleaner chapter titles and is worth the extra API call for polished output.

For either approach, build a plain-text block from each chunk by joining the text fields:

def segments_to_text(segments):
    return " ".join(s["text"] for s in segments)

Keep the start value of the first segment in each chunk. You will need it for timestamp links later.

Pulling Quotable Moments

Before you hand the chunks to an LLM, scan each one for segments that are short, self-contained, and assertive. A heuristic that works well in practice: any segment under 20 words that does not start with a filler word ("um", "so", "yeah") is worth flagging as a candidate quote.

FILLER = {"um", "uh", "so", "yeah", "you", "like", "well", "okay"}

def find_quote_candidates(segments):
    quotes = []
    for seg in segments:
        words = seg["text"].split()
        if len(words) <= 20 and words[0].lower() not in FILLER:
            quotes.append(seg)
    return quotes

You will pass these candidates to the LLM prompt so it can select the strongest one per section.

Generating the Blog Draft with an LLM

With the chunks and quote candidates ready, construct a prompt for each section. The prompt below assumes OpenAI's chat API but works with any model that accepts a system and user message:

import openai

def draft_section(chunk_text, quotes, section_number, total_sections, video_title):
    system = (
        "You are an editor converting a podcast transcript excerpt into a blog section. "
        "Write in second person, use short paragraphs, and lead with the main insight. "
        "Do not use em dashes. Keep the tone practical and direct."
    )
    user = (
        f"Podcast: {video_title}\n"
        f"Section {section_number} of {total_sections}\n\n"
        f"Transcript excerpt:\n{chunk_text}\n\n"
        f"Quote candidates:\n" + "\n".join(f'- "{q["text"]}" (start: {q["start"]}s)' for q in quotes) + "\n\n"
        "Write a 150-200 word blog section with:\n"
        "1. An H3 heading that captures the main point\n"
        "2. Two short paragraphs expanding on the idea\n"
        "3. The single strongest quote as a Markdown blockquote\n"
        "Return only the Markdown."
    )
    response = openai.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "system", "content": system}, {"role": "user", "content": user}]
    )
    return response.choices[0].message.content

Run this for each chunk, then concatenate the sections into a single Markdown string. The result is a rough draft with proper heading hierarchy, key quotes surfaced, and the episode's argument laid out in text form.

Laptop with notebook and coffee, content creation workspace

Adding Timestamps and Links Back to the Source Video

Every quote and section heading should link back to the exact moment in the video. YouTube supports deep-link timestamps with the ?t= parameter:

def make_timestamp_link(video_id, start_seconds, label):
    t = int(start_seconds)
    url = f"https://youtu.be/{video_id}?t={t}"
    return f"[{label}]({url})"

Add these links after the quote in each section:

> "You actually want to talk to churned users immediately."

[Watch at 0:07](https://youtu.be/dQw4w9WgXcQ?t=7)

Readers get one-click access to context, and the original creator gets attribution. This also makes the post more useful for anyone who wants to fact-check a claim or listen to the surrounding conversation.

For the introduction, link to the full video thumbnail so readers can switch to video if they prefer:

intro = (
    f"## {title}\n\n"
    f"Original episode by {author_name}: [Watch on YouTube](https://youtu.be/{video_id})\n\n"
)

A Lightweight End-to-End Script

The following script ties everything together. It fetches the transcript, segments it, drafts each section, and writes a Markdown file. Adjust WINDOW_SECONDS and the LLM prompt to match your style guide.

import requests
import openai

API_KEY = "YOUR_TRANSCRIBER_KEY"
OPENAI_KEY = "YOUR_OPENAI_KEY"
VIDEO_URL = "https://www.youtube.com/watch?v=VIDEO_ID"
WINDOW_SECONDS = 600

openai.api_key = OPENAI_KEY

# 1. Fetch transcript
resp = requests.get(
    "https://getyoutubetranscriber.com/api/v2/transcript",
    params={"video_url": VIDEO_URL, "send_metadata": "true"},
    headers={"Authorization": f"Bearer {API_KEY}"}
)
resp.raise_for_status()
data = resp.json()

video_id = data["video_id"]
title = data.get("title", "Podcast Episode")
author = data.get("author_name", "")
segments = data["transcript"]

# 2. Chunk by time
def chunk_by_time(segments, window=WINDOW_SECONDS):
    chunks, current, start = [], [], 0.0
    for seg in segments:
        if seg["start"] - start >= window and current:
            chunks.append({"start": start, "segments": current})
            start, current = seg["start"], []
        current.append(seg)
    if current:
        chunks.append({"start": start, "segments": current})
    return chunks

chunks = chunk_by_time(segments)

# 3. Find quotes
FILLER = {"um", "uh", "so", "yeah", "you", "like", "well", "okay"}
def find_quotes(segs):
    return [s for s in segs if len(s["text"].split()) <= 20
            and s["text"].split()[0].lower() not in FILLER]

# 4. Draft each section
def draft_section(text, quotes, idx, total):
    system = "Convert this podcast excerpt to a blog section. Short paragraphs, no em dashes, second person."
    user = (
        f"Podcast: {title} (section {idx+1}/{total})\n\n"
        f"Transcript:\n{text}\n\n"
        f"Quotes:\n" + "\n".join(f'- "{q["text"]}" ({int(q["start"])}s)' for q in quotes[:3]) + "\n\n"
        "Write: H3 heading, two paragraphs, one blockquote. Return Markdown only."
    )
    r = openai.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "system", "content": system}, {"role": "user", "content": user}]
    )
    return r.choices[0].message.content

# 5. Build output
lines = [f"# {title}\n", f"By {author} | [Watch on YouTube](https://youtu.be/{video_id})\n\n"]

for i, chunk in enumerate(chunks):
    text = " ".join(s["text"] for s in chunk["segments"])
    quotes = find_quotes(chunk["segments"])
    section_md = draft_section(text, quotes, i, len(chunks))
    t = int(chunk["start"])
    lines.append(section_md)
    lines.append(f"\n[Watch this section](https://youtu.be/{video_id}?t={t})\n\n")

with open("blog_draft.md", "w") as f:
    f.write("\n".join(lines))

print(f"Done. {len(chunks)} sections written to blog_draft.md")

This runs in under a minute for a typical 90-minute episode. The output needs a light editorial pass: check that the LLM did not invent specifics, verify quote accuracy against the source text fields, and add your own introduction. The mechanical work of segmenting and structuring is already done.

For teams processing a full podcast back catalog, the Summarize Entire YouTube Playlists with AI guide shows how to extend this pattern to playlist-level batch processing.

Editorial Considerations Before You Publish

A few things the script cannot do for you:

  • Speaker attribution. Auto-generated captions do not include speaker labels. If the episode has multiple guests, read through the draft and tag quotes with names before publishing.
  • Accuracy on proper nouns. Auto-captions frequently mishear product names, company names, and technical terms. Cross-check these against the video before the post goes live.
  • SEO title and meta description. The LLM section headings are functional but not optimized. Rewrite the post title with your target keywords in mind once the content is solid.
  • Freshness. Long-form podcasts age well, but any statistics or recommendations mentioned in the episode should be fact-checked against current sources before you treat them as evergreen content.

If you are running this at scale across multiple podcast channels, cache the raw transcript JSON to disk immediately after fetching. Re-fetching the same episode on every run wastes credits and adds latency. Write each response to a file named after the video ID before passing it to the segmenter.

Getting Started

Start with a single episode you know well so you can evaluate the draft quality against your own memory of the conversation. Run the script, read the output, and tune the prompt for your editorial voice before applying it to the back catalog.

You can get 100 free credits at getyoutubetranscriber.com with no credit card required. That covers roughly 100 transcript fetches to test the workflow end to end.