This workflow corresponds to n8n.io template #14170 — we link there as the canonical source.
This workflow follows the Form Trigger → Gmail recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "2hi0dwPfJyNF39nP",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Summarize Apple Podcast Episodes with ElevenLabs and GPT-5-MINI",
"tags": [],
"nodes": [
{
"id": "sticky-overview",
"name": "Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3776,
-128
],
"parameters": {
"color": 5,
"width": 556,
"height": 1000,
"content": "## \ud83c\udf99\ufe0f Summarize Apple Podcast Episodes with ElevenLabs and GPT-5-MINI\n\n**Paste one or more Apple Podcast episode URLs into a form (one per line) and receive a structured AI-generated summary by email - powered by ElevenLabs speech-to-text and GPT-5-MINI.**\n\n---\n\n### Who is this for\n- Podcast listeners who want fast episode digests\n- Content creators researching competitor podcasts\n- Teams that share podcast insights via email\n\n---\n\n### How it works\n1. **Submit URLs** - Paste one or more Apple Podcast episode URLs into the trigger form\n2. **Discover RSS feed** - The iTunes API is queried to find the podcast's public RSS feed URL\n3. **Find episode MP3** - The RSS XML is parsed to locate the matching episode audio file\n4. **Transcribe audio** - ElevenLabs Scribe transcribes the full episode via direct URL\n5. **Generate summary** - GPT-5-MINI produces a structured summary: title, key points, useful info, and bottom line\n6. **Email results** - All summaries are combined into a formatted HTML email and sent to your inbox\n\n---\n\n### Setup\n1. **ElevenLabs** - Add HTTP Header Auth credential with your ElevenLabs API key; connect to \"Transcribe Episode with ElevenLabs\"\n2. **OpenAI** - Connect your OpenAI API credential to \"Generate Episode Summary\"\n3. **Gmail** - Connect your Gmail OAuth2 credential to \"Send Summary Email\"\n4. **Recipient email** - Update the \"To\" address in \"Send Summary Email\"\n5. Activate the workflow"
},
"typeVersion": 1
},
{
"id": "sticky-s1",
"name": "Section: User Input",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3200,
208
],
"parameters": {
"color": 5,
"width": 238,
"height": 298,
"content": "## \u2460 User Input\nUser submits Apple Podcast episode URLs via the n8n form."
},
"typeVersion": 1
},
{
"id": "sticky-s2",
"name": "Section: Podcast Discovery",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2928,
208
],
"parameters": {
"color": 3,
"width": 962,
"height": 298,
"content": "## \u2461 Podcast Discovery\nLooks up the RSS feed via iTunes API and extracts the matching episode MP3 URL(s)."
},
"typeVersion": 1
},
{
"id": "sticky-s3",
"name": "Section: Transcription & Summary",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1936,
208
],
"parameters": {
"color": 3,
"width": 490,
"height": 298,
"content": "## \u2462 Transcription & AI Summary\nTranscribes the episode audio and generates a structured summary with GPT-5-MINI."
},
"typeVersion": 1
},
{
"id": "sticky-s4",
"name": "Section: Email Delivery",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1408,
208
],
"parameters": {
"color": 0,
"width": 442,
"height": 298,
"content": "## \u2463 Email Delivery\nCombines all summaries into an HTML email and sends it to the recipient."
},
"typeVersion": 1
},
{
"id": "elevenlabs-stt",
"name": "Transcribe Episode with ElevenLabs",
"type": "n8n-nodes-base.httpRequest",
"position": [
-1872,
320
],
"parameters": {
"url": "https://api.elevenlabs.io/v1/speech-to-text",
"method": "POST",
"options": {
"timeout": 600000
},
"sendBody": true,
"contentType": "multipart-form-data",
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "cloud_storage_url",
"value": "={{ $json.mp3Url }}"
},
{
"name": "model_id",
"value": "scribe_v2"
}
]
},
"genericAuthType": "httpHeaderAuth"
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "fca607d8-ec3a-434f-96ea-b9f3151f9ba9",
"name": "Submit Podcast URLs",
"type": "n8n-nodes-base.formTrigger",
"position": [
-3104,
320
],
"parameters": {
"options": {
"appendAttribution": false
},
"formTitle": "Apple Podcasts Summarizer",
"formFields": {
"values": [
{
"fieldType": "textarea",
"fieldLabel": "Input Apple Podcast links",
"placeholder": "https://podcasts.apple.com/mn/podcast/seasonality-isnt-a-problem-its-a-profit-opportunity-ep-952/id1254720112?i=1+1234567890",
"requiredField": true
}
]
}
},
"typeVersion": 2.3
},
{
"id": "b263c0b1-797d-4197-b6aa-4b967d9af20e",
"name": "Parse Input URLs",
"type": "n8n-nodes-base.code",
"position": [
-2880,
320
],
"parameters": {
"jsCode": "const input = $input.first().json['Input Apple Podcast links'];\nconst urls = input.split('\\n').filter(u => u.trim() !== '');\nreturn urls.map(url => {\n const match = url.match(/id(\\d+)/);\n return {\n json: {\n apple_url: url.trim(),\n podcastId: match ? match[1] : ''\n }\n };\n});"
},
"typeVersion": 2
},
{
"id": "cd36a002-1b68-49b6-a2f9-f56c0bbf675d",
"name": "Look Up RSS Feed via iTunes",
"type": "n8n-nodes-base.httpRequest",
"position": [
-2688,
320
],
"parameters": {
"url": "=https://itunes.apple.com/lookup?id={{ $json.podcastId }}&entity=podcast",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "970c1467-b612-4460-8c86-d3643f617bcf",
"name": "Extract RSS Feed URL",
"type": "n8n-nodes-base.code",
"position": [
-2496,
320
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const rawData = $input.item.json;\nlet data;\nif (rawData.data !== undefined) {\n data = typeof rawData.data === 'string' ? JSON.parse(rawData.data) : rawData.data;\n} else {\n data = rawData;\n}\nlet rssUrl = '';\nif (data.results && data.results.length > 0) { rssUrl = data.results[0].feedUrl; }\nreturn { json: { rssUrl: rssUrl } };"
},
"typeVersion": 2
},
{
"id": "376cb838-552b-4e44-bfd4-99b4285f6918",
"name": "Find Episode MP3 URL",
"type": "n8n-nodes-base.code",
"position": [
-2112,
320
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const xml = $input.item.json.data;\nconst xmlString = typeof xml === 'string' ? xml : JSON.stringify(xml);\nconst originalUrl = $('Parse Input URLs').item.json.apple_url;\nconst urlParts = originalUrl.split('/');\nconst urlSlug = urlParts.find(part => part.includes('-') && part.length > 10) || '';\nconst searchTerms = urlSlug.toLowerCase().replace(/-/g, ' ');\nconst items = xmlString.split('<item>');\nlet mp3Url = '';\nlet episodeTitle = '';\nlet bestMatch = null;\nlet bestScore = 0;\nfor (let item of items) {\n const titleMatch = item.match(/<title><!\\[CDATA\\[([^\\]]+)\\]\\]><\\/title>/) || item.match(/<title>([^<]+)<\\/title>/);\n if (titleMatch) {\n const itemTitle = titleMatch[1].toLowerCase();\n const words = searchTerms.split(' ').filter(w => w.length > 2);\n let score = 0;\n for (let word of words) { if (itemTitle.includes(word)) score++; }\n if (score > bestScore) { bestScore = score; bestMatch = item; episodeTitle = titleMatch[1]; }\n }\n}\nif (bestMatch) {\n const urlMatch = bestMatch.match(/<enclosure[^>]*url=\"([^\"]+)\"[^>]*type=\"audio/);\n if (urlMatch) { mp3Url = urlMatch[1]; }\n}\nif (!mp3Url) {\n const firstMatch = xmlString.match(/<enclosure[^>]*url=\"([^\"]+)\"[^>]*type=\"audio/);\n mp3Url = firstMatch ? firstMatch[1] : '';\n episodeTitle = 'First episode (no match found)';\n}\nreturn { json: { mp3Url: mp3Url, episodeTitle: episodeTitle, matchScore: bestScore, success: mp3Url ? true : false } };"
},
"typeVersion": 2
},
{
"id": "934ac04a-c9da-4ddc-ba9a-882f7b8bef0a",
"name": "Fetch RSS Feed",
"type": "n8n-nodes-base.httpRequest",
"position": [
-2304,
320
],
"parameters": {
"url": "={{ $json.rssUrl }}",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "c2d71e27-2920-4399-afae-fe22db9eb32f",
"name": "Build HTML Email",
"type": "n8n-nodes-base.code",
"position": [
-1360,
320
],
"parameters": {
"jsCode": "const items = $input.all();\n\nfunction mdToHtml(md) {\n const lines = md.split('\\n');\n const out = [];\n let inList = false;\n for (const line of lines) {\n if (line.startsWith('- ')) {\n if (!inList) { out.push('<ul style=\"margin:8px 0;padding-left:20px\">'); inList = true; }\n const content = line.slice(2)\n .replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>')\n .replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href=\"$2\" style=\"color:#0066cc\">$1</a>');\n out.push(`<li style=\"margin:4px 0\">${content}</li>`);\n } else {\n if (inList) { out.push('</ul>'); inList = false; }\n if (line.trim() === '') continue;\n const content = line\n .replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>')\n .replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '<a href=\"$2\" style=\"color:#0066cc\">$1</a>');\n out.push(`<p style=\"margin:6px 0\">${content}</p>`);\n }\n }\n if (inList) out.push('</ul>');\n return out.join('\\n');\n}\n\nlet html = `<!DOCTYPE html>\n<html><head><meta charset=\"UTF-8\"></head>\n<body style=\"font-family:Arial,sans-serif;line-height:1.6;color:#333;max-width:700px;margin:0 auto;padding:20px\">\n<h2 style=\"color:#1a1a1a;border-bottom:2px solid #eee;padding-bottom:10px\">Podcast Summaries</h2>\n<p style=\"color:#888;font-size:13px\">Generated: ${new Date().toLocaleDateString()} · ${items.length} episode(s)</p>\n`;\n\nfor (let i = 0; i < items.length; i++) {\n const item = items[i].json;\n let summary = '';\n if (item.message && item.message.content) { summary = item.message.content; }\n else if (item.choices && item.choices[0] && item.choices[0].message) { summary = item.choices[0].message.content; }\n else if (item.content) { summary = item.content; }\n else { summary = 'Error: Could not extract summary'; }\n html += `<div style=\"border:1px solid #e0e0e0;border-radius:8px;padding:20px;margin:20px 0\">${mdToHtml(summary)}</div>`;\n}\n\nhtml += `</body></html>`;\n\nreturn { json: { html: html } };"
},
"typeVersion": 2
},
{
"id": "9fb5b75e-c772-4c14-87dc-2dcd9dd8c0de",
"name": "Generate Episode Summary",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
-1696,
320
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-5-mini",
"cachedResultName": "GPT-5-MINI"
},
"options": {},
"messages": {
"values": [
{
"content": "=You are a precise podcast summarization engine. Your only job is to fill in the template below using only information found in the transcript. Do not invent, infer, or embellish.\n\n# Formatting Rules (follow strictly):\n- Output ONLY the filled template. No preamble, no closing remarks, no explanations.\n- Keep every pair of ** exactly as shown. Do not remove or alter any markdown characters.\n- Do not change headings, labels, or section order. Do not add new sections.\n- The **Title** and **URL** lines are pre-filled \u2014 copy them exactly as given, do not modify them.\n- Bullets are plain text only: no bold, no nesting, no sub-points. Each must start with \"- \" with no blank lines between them.\n- Do not wrap the URL in any format other than: [URL](URL)\n- If the transcript lacks enough information for a section, write [Insufficient data].\n- The output must be valid Markdown.\n\n# Word Limits:\n- Main Topic: 1 sentence, max 20 words\n- Key Points: 3\u20135 bullets, each 15\u201325 words\n- Useful Info: 2\u20133 sentences, 40\u201360 words\n- Bottom Line: 1 sentence, max 20 words\n\n# Template:\n**Title**: {{ $('Find Episode MP3 URL').item.json.episodeTitle }}\n**URL**: [{{ $('Parse Input URLs').item.json.apple_url }}]({{ $('Parse Input URLs').item.json.apple_url }})\n**Main Topic:** \n**Key Points:**\n- \n**Useful Info:** \n**Bottom Line:** \n\n# Transcript:\n{{ $json.text }}"
}
]
},
"simplify": false
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.8
},
{
"id": "db9a8c06-c22f-4ddc-9d13-f3fa37c985d6",
"name": "Send Summary Email",
"type": "n8n-nodes-base.gmail",
"position": [
-1168,
320
],
"parameters": {
"sendTo": "user@example.com",
"message": "={{ $json.html }}",
"options": {
"appendAttribution": false
},
"subject": "Podcast Summary"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"executeOnce": false,
"typeVersion": 2.1
}
],
"active": false,
"settings": {
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": "Nin8EYMkR9vuyKPp",
"timeSavedMode": "fixed",
"availableInMCP": false,
"executionOrder": "v1",
"timeSavedPerExecution": 100
},
"versionId": "1f8b627d-0552-45ea-9652-1ae9cd97973c",
"connections": {
"Fetch RSS Feed": {
"main": [
[
{
"node": "Find Episode MP3 URL",
"type": "main",
"index": 0
}
]
]
},
"Build HTML Email": {
"main": [
[
{
"node": "Send Summary Email",
"type": "main",
"index": 0
}
]
]
},
"Parse Input URLs": {
"main": [
[
{
"node": "Look Up RSS Feed via iTunes",
"type": "main",
"index": 0
}
]
]
},
"Submit Podcast URLs": {
"main": [
[
{
"node": "Parse Input URLs",
"type": "main",
"index": 0
}
]
]
},
"Extract RSS Feed URL": {
"main": [
[
{
"node": "Fetch RSS Feed",
"type": "main",
"index": 0
}
]
]
},
"Find Episode MP3 URL": {
"main": [
[
{
"node": "Transcribe Episode with ElevenLabs",
"type": "main",
"index": 0
}
]
]
},
"Generate Episode Summary": {
"main": [
[
{
"node": "Build HTML Email",
"type": "main",
"index": 0
}
]
]
},
"Look Up RSS Feed via iTunes": {
"main": [
[
{
"node": "Extract RSS Feed URL",
"type": "main",
"index": 0
}
]
]
},
"Transcribe Episode with ElevenLabs": {
"main": [
[
{
"node": "Generate Episode Summary",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
gmailOAuth2httpHeaderAuthopenAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Submit one or more Apple Podcast episode URLs via the built-in n8n form The workflow queries the iTunes API to retrieve each podcast's public RSS feed, then parses the XML to locate the matching episode's MP3 file ElevenLabs Scribe transcribes the full audio by passing the MP3…
Source: https://n8n.io/workflows/14170/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This workflow auto-generates a personalized research report on any prospect who books a call with you—using their LinkedIn profile and advanced web research.
Deep Multiline Icebreaker automates high-quality, research-led outreach. Feed it a list of leads (emails + websites) and a short product brief via the built-in form; the workflow scrapes each company'
Lead Research & Qualification - Phase 1. Uses httpRequest, openAi, googleSheets, gmail. Event-driven trigger; 22 nodes.
Marketing agencies, digital agencies, and freelancers who need to streamline their client onboarding process and create consistent, professional documentation for new clients. Perfect for teams handli
Clone_Viral_TikToks_with_AI_Avatars___Auto_Post_to_9_Platforms_using_Perplexity___Blotato. Uses httpRequest, telegramTrigger, openAi, googleSheets. Event-driven trigger; 42 nodes.