AutomationFlowsSocial Media › Repurpose Youtube Videos Into Multichannel Content with Gemini and Google Sheets

Repurpose Youtube Videos Into Multichannel Content with Gemini and Google Sheets

ByRavi Patel @ravipatel7210 on n8n.io

This workflow takes a YouTube video URL, fetches its transcript via RapidAPI, uses Google Gemini to generate multiple repurposed content assets, stores everything in Google Sheets, and automatically publishes the LinkedIn post while logging posted/failed status and any errors.…

Event trigger★★★★☆ complexityAI-powered17 nodesForm TriggerHTTP RequestChain LlmGoogle Gemini ChatGoogle SheetsLinkedIn
Social Media Trigger: Event Nodes: 17 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #16060 — we link there as the canonical source.

This workflow follows the Chainllm → Form Trigger 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 →

Download .json
{
  "id": "XUANZYDSgp5uAypH",
  "name": "ai_content_repurposing_machine",
  "tags": [],
  "nodes": [
    {
      "id": "574c00cd-7a41-421a-a2e8-094b5f295429",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "width": 480,
        "height": 896,
        "content": "## ai_content_repurposing_machine\n\n### How it works\n\nThis workflow turns a YouTube video transcript into repurposed LinkedIn content. It starts with a form submission, retrieves and processes the transcript, sends it to Gemini for content generation, parses the result, saves it in Google Sheets, and publishes it to LinkedIn. It also has a separate error logging path that records failures to a sheet.\n\n### Setup steps\n\n- Configure the form trigger with the fields required by the workflow, such as the YouTube video URL or video ID.\n- Add RapidAPI credentials or headers for the YouTube Transcript API request node.\n- Connect Google Gemini credentials for the Gemini chat model used by the LLM chain.\n- Connect Google Sheets credentials and set the spreadsheet, sheet names, and column mappings for content records, status updates, and error logs.\n- Connect LinkedIn credentials and verify the target profile or organization page for publishing.\n- Review the custom code nodes to ensure they match the transcript API response format and the expected AI response structure.\n\n### Customization\n\nYou can adjust the Gemini prompt to produce different content formats, change the Google Sheets columns used for tracking, or replace LinkedIn publishing with another social channel."
      },
      "typeVersion": 1
    },
    {
      "id": "38347ac7-8b4a-43c9-a610-9decc9ebe3d6",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 672,
        "height": 320,
        "content": "## Collect video transcript\n\nStarts from a submitted form, fetches the YouTube transcript through the RapidAPI transcript endpoint, and runs custom code to clean or normalize the transcript for downstream AI processing."
      },
      "typeVersion": 1
    },
    {
      "id": "987fc2a8-fefd-45d2-b4f5-6b0eed1a1217",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1328,
        32
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 560,
        "content": "## Generate and parse content\n\nUses a Gemini-powered LLM chain to repurpose the processed transcript into social content, then parses the AI output into structured fields for saving and publishing."
      },
      "typeVersion": 1
    },
    {
      "id": "9b539284-c84d-4991-bdbc-cc40b073b155",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1888,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 768,
        "height": 480,
        "content": "## Publish and update status\n\nAppends the generated content to Google Sheets, publishes it to LinkedIn, and updates the sheet with either posted or failed status based on the publishing result."
      },
      "typeVersion": 1
    },
    {
      "id": "a381ac29-5ecc-49c0-8bfd-087b4d9908ca",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2208,
        576
      ],
      "parameters": {
        "color": 7,
        "height": 432,
        "content": "## Handle workflow errors\n\nA separate lower canvas cluster that receives errors from transcript fetching, transcript processing, AI generation, parsing, and sheet appending, formats the error details, and logs them to Google Sheets."
      },
      "typeVersion": 1
    },
    {
      "id": "d2923783-b8f4-4382-a3bf-1d8100be705f",
      "name": "When Form Submitted",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        608,
        208
      ],
      "parameters": {
        "options": {},
        "formTitle": "AI Content Repurposing Machine",
        "formFields": {
          "values": [
            {
              "fieldLabel": "YouTube Video URL",
              "placeholder": "https://www.youtube.com/watch?v=...",
              "requiredField": true
            }
          ]
        },
        "formDescription": "Enter a YouTube video URL to automatically generate multiple content assets."
      },
      "typeVersion": 2.2
    },
    {
      "id": "e7dd8a84-0422-422b-95ae-9d8193f22829",
      "name": "Fetch Transcript from YouTube",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Calls RapidAPI transcript API and pulls transcript text from the submitted YouTube URL.",
      "onError": "continueErrorOutput",
      "position": [
        848,
        208
      ],
      "parameters": {
        "url": "https://youtube-transcript3.p.rapidapi.com/api/transcript-with-url",
        "options": {},
        "sendQuery": true,
        "sendHeaders": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "url",
              "value": "={{ $json['YouTube Video URL'] }}"
            },
            {
              "name": "flat_text",
              "value": "true"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "x-rapidapi-host",
              "value": "youtube-transcript3.p.rapidapi.com"
            },
            {
              "name": "x-rapidapi-key",
              "value": "YOUR_RAPIDAPI_KEY_HERE"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "ae3b25ed-7fcc-4e73-9d62-af5735be2812",
      "name": "Process YouTube Transcript",
      "type": "n8n-nodes-base.code",
      "notes": "Normalizes transcript API output into a clean single string.",
      "onError": "continueErrorOutput",
      "position": [
        1088,
        208
      ],
      "parameters": {
        "jsCode": "const input = $input.first().json;\nlet transcript = '';\nif (typeof input === 'string') { transcript = input; }\nelse if (typeof input.transcript === 'string') { transcript = input.transcript; }\nelse if (typeof input.text === 'string') { transcript = input.text; }\nelse if (Array.isArray(input)) { transcript = input.map(i => i.text || i.transcript || '').join(' '); }\nelse if (Array.isArray(input.transcripts)) { transcript = input.transcripts.map(i => i.text || '').join(' '); }\nelse { const raw = JSON.stringify(input); const matches = [...raw.matchAll(/\\\"text\\\":\\\"(.*?)\\\"/g)]; transcript = matches.map(m => m[1]).join(' '); }\ntranscript = transcript.replace(/\\[\\d{2}:\\d{2}(?::\\d{2})?\\]/g, ' ').replace(/\\(\\d{2}:\\d{2}(?::\\d{2})?\\)/g, ' ').replace(/\\s+/g, ' ').trim();\nif (!transcript || transcript.length < 50) throw new Error('Transcript is empty or too short.');\nreturn [{ json: { youtubeUrl: $('When Form Submitted').first().json['YouTube Video URL'], transcript, transcriptLength: transcript.length } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "5a3b41ac-e6cf-4fe7-902a-9fd48464ce0d",
      "name": "Generate Content with LLM",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "notes": "Generates all requested content assets from the cleaned transcript using Gemini.",
      "onError": "continueErrorOutput",
      "position": [
        1376,
        208
      ],
      "parameters": {
        "text": "=You are an expert content repurposing strategist. Analyze the following YouTube transcript and return ONLY valid JSON with these exact keys: title, summary, blog, linkedin, twitter_thread, newsletter, content_ideas, viral_hooks, cta_suggestions.\\n\\nRules:\\n- title: concise and SEO-friendly\\n- summary: 150-200 words\\n- blog: minimum 1500 words in markdown with headings\\n- linkedin: highly engaging post for LinkedIn\\n- twitter_thread: exactly 10 tweets, numbered 1/10 to 10/10\\n- newsletter: 400-600 words with subject line\\n- content_ideas: 5 ideas as numbered list\\n- viral_hooks: 10 hooks as numbered list\\n- cta_suggestions: 5 CTA suggestions as numbered list\\n- Return raw JSON only, no code fences, no commentary\\n\\nYouTube URL: {{ $json.youtubeUrl }}\\n\\nTranscript:\\n{{ $json.transcript }}",
        "promptType": "define"
      },
      "typeVersion": 1.5
    },
    {
      "id": "764b54ba-28db-407a-a1ab-a35e70ad4ab2",
      "name": "AI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "notes": "Gemini chat model connected to the Basic LLM Chain node.",
      "position": [
        1376,
        448
      ],
      "parameters": {
        "options": {
          "temperature": 0.7,
          "maxOutputTokens": 8192
        }
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "0a6cb248-d9b5-486a-be99-3a698c009886",
      "name": "Parse Content Response",
      "type": "n8n-nodes-base.code",
      "notes": "Parses the Gemini JSON response and prepares a normalized object for downstream steps.",
      "onError": "continueErrorOutput",
      "position": [
        1664,
        208
      ],
      "parameters": {
        "jsCode": "const ai = $input.first().json;\nlet text = ai.text || ai.content || ai.response || ai.message || JSON.stringify(ai);\ntext = text.replace(/```json\\n?/g, '').replace(/```\\n?/g, '').trim();\nconst start = text.indexOf('{');\nconst end = text.lastIndexOf('}');\nif (start === -1 || end === -1) throw new Error('AI did not return valid JSON.');\nconst raw = text.slice(start, end + 1);\nlet parsed;\ntry { parsed = JSON.parse(raw); } catch (e) { throw new Error('Failed to parse AI JSON: ' + e.message); }\nconst required = ['title','summary','blog','linkedin','twitter_thread','newsletter','content_ideas','viral_hooks','cta_suggestions'];\nfor (const key of required) { if (!parsed[key]) parsed[key] = ''; }\nconst transcriptData = $('Process YouTube Transcript').first().json;\nreturn [{ json: { timestamp: new Date().toISOString(), youtubeUrl: transcriptData.youtubeUrl, transcript: transcriptData.transcript, title: parsed.title, summary: parsed.summary, blog: parsed.blog, linkedin: parsed.linkedin, twitter_thread: parsed.twitter_thread, newsletter: parsed.newsletter, content_ideas: parsed.content_ideas, viral_hooks: parsed.viral_hooks, cta_suggestions: parsed.cta_suggestions, linkedin_status: 'Pending', created_date: new Date().toISOString().split('T')[0] } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "222a9db9-f442-4d6b-b196-902d77c98e5b",
      "name": "Append Output to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Appends all generated content into Sheet1. Create the exact header names in advance.",
      "onError": "continueErrorOutput",
      "position": [
        1936,
        208
      ],
      "parameters": {
        "columns": {
          "value": {
            "Summary": "={{ $json.summary }}",
            "Timestamp": "={{ $json.timestamp }}",
            "Newsletter": "={{ $json.newsletter }}",
            "Transcript": "={{ $json.transcript }}",
            "Video Title": "={{ $json.title }}",
            "Viral Hooks": "={{ $json.viral_hooks }}",
            "YouTube URL": "={{ $json.youtubeUrl }}",
            "Blog Article": "={{ $json.blog }}",
            "Created Date": "={{ $json.created_date }}",
            "Content Ideas": "={{ $json.content_ideas }}",
            "LinkedIn Post": "={{ $json.linkedin }}",
            "Twitter Thread": "={{ $json.twitter_thread }}",
            "CTA Suggestions": "={{ $json.cta_suggestions }}",
            "LinkedIn Status": "={{ $json.linkedin_status }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID_HERE"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "54ab2b1a-62c1-44ea-abff-3826df0f3550",
      "name": "Post Content on LinkedIn",
      "type": "n8n-nodes-base.linkedIn",
      "notes": "Publishes the AI-generated LinkedIn post to your LinkedIn profile. Uses OAuth2 for authentication. Ensure your LinkedIn OAuth2 credentials are configured in n8n credentials.",
      "onError": "continueErrorOutput",
      "position": [
        2240,
        192
      ],
      "parameters": {
        "text": "={{ $('Parse Content Response').first().json.linkedin }}",
        "person": "urn:li:person:me",
        "additionalFields": {}
      },
      "retryOnFail": false,
      "typeVersion": 1
    },
    {
      "id": "8ad470a3-01dc-43ae-b5ca-634e05884f5e",
      "name": "Update Posted Status in Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Marks the matching row as Posted after successful LinkedIn publish.",
      "position": [
        2512,
        128
      ],
      "parameters": {
        "columns": {
          "value": {
            "LinkedIn Status": "Posted"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID_HERE"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "47c756d7-cdc9-445d-93ea-d03309001d00",
      "name": "Update Failure Status in Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Marks the matching row as Failed with the LinkedIn error message when publishing fails.",
      "position": [
        2512,
        304
      ],
      "parameters": {
        "columns": {
          "value": {
            "LinkedIn Status": "={{ 'Failed - ' + ($json.message || $json.error?.message || 'Unknown LinkedIn error') }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID_HERE"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "c8e40a99-f187-4b5c-ab39-70b6472ddf6c",
      "name": "Log Errors to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Appends transcript, Gemini, parse, or sheets errors to the Errors tab.",
      "position": [
        2480,
        848
      ],
      "parameters": {
        "columns": {
          "value": {
            "Timestamp": "={{ $json['Timestamp'] }}",
            "Error Node": "={{ $json['Error Node'] }}",
            "YouTube URL": "={{ $json['YouTube URL'] }}",
            "Error Message": "={{ $json['Error Message'] }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Errors"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID_HERE"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "a7aa6cbe-84c1-4088-830b-4a4f7d9cdd6d",
      "name": "Handle Errors in Workflow",
      "type": "n8n-nodes-base.code",
      "notes": "Normalizes upstream errors into a simple row format for the Errors sheet.",
      "position": [
        2256,
        848
      ],
      "parameters": {
        "jsCode": "const err = $input.first().json;\nconst msg = err.error?.message || err.message || JSON.stringify(err);\nconst node = err.error?.node?.name || 'Unknown Node';\nreturn [{ json: { Timestamp: new Date().toISOString(), 'YouTube URL': (() => { try { return $('When Form Submitted').first().json['YouTube Video URL']; } catch (e) { return ''; } })(), 'Error Message': msg, 'Error Node': node } }];"
      },
      "typeVersion": 2
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "c22aaa7a-dc50-4a38-9608-0dd6be20aa1d",
  "connections": {
    "AI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Generate Content with LLM",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "When Form Submitted": {
      "main": [
        [
          {
            "node": "Fetch Transcript from YouTube",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Content Response": {
      "main": [
        [
          {
            "node": "Append Output to Sheets",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle Errors in Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append Output to Sheets": {
      "main": [
        [
          {
            "node": "Post Content on LinkedIn",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle Errors in Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post Content on LinkedIn": {
      "main": [
        [
          {
            "node": "Update Posted Status in Sheets",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Update Failure Status in Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Content with LLM": {
      "main": [
        [
          {
            "node": "Parse Content Response",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle Errors in Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Handle Errors in Workflow": {
      "main": [
        [
          {
            "node": "Log Errors to Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process YouTube Transcript": {
      "main": [
        [
          {
            "node": "Generate Content with LLM",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle Errors in Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Transcript from YouTube": {
      "main": [
        [
          {
            "node": "Process YouTube Transcript",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle Errors in Workflow",
            "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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow takes a YouTube video URL, fetches its transcript via RapidAPI, uses Google Gemini to generate multiple repurposed content assets, stores everything in Google Sheets, and automatically publishes the LinkedIn post while logging posted/failed status and any errors.…

Source: https://n8n.io/workflows/16060/ — original creator credit. Request a take-down →

More Social Media workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Social Media

This workflow provides a powerful AI assistant for content creators, book editors, and marketers. It automates the collection and analysis of trending discussions from Reddit, YouTube, and X (Twitter)

HTTP Request, Form Trigger, Reddit +6
Social Media

This workflow is built for creators, solopreneurs, SaaS founders, and agencies looking to automate their social media content process from idea to publication. It combines the power of OpenAI, Google

OpenAI Chat, Tool Workflow, Agent +15
Social Media

✨🤖Automated AI Powered Social Media Content Factory for X + Facebook + Instagram + LinkedIn. Uses outputParserStructured, lmChatGoogleGemini, lmChatOpenAi, httpRequest. Event-driven trigger; 57 nodes

Output Parser Structured, Google Gemini Chat, OpenAI Chat +11
Social Media

Social Media Managers and Digital Marketers seeking to streamline content production across 7+ platforms (X/Twitter, Instagram, LinkedIn, Facebook, TikTok, Threads, YouTube Shorts) using AI-powered au

Output Parser Structured, Google Gemini Chat, OpenAI Chat +11
Social Media

✨🤖Automated AI Powered Social Media Content Factory for X + Facebook + Instagram + LinkedIn. Uses outputParserStructured, lmChatGoogleGemini, lmChatOpenAi, httpRequest. Event-driven trigger; 57 nodes

Output Parser Structured, Google Gemini Chat, OpenAI Chat +11