This workflow corresponds to n8n.io template #11638 — we link there as the canonical source.
This workflow follows the Agent → 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 →
{
"nodes": [
{
"id": "412eca65-b548-4e92-a4d3-19e78c3aafa3",
"name": "PUBLISHER NOTE",
"type": "n8n-nodes-base.stickyNote",
"position": [
176,
800
],
"parameters": {
"width": 468,
"height": 180,
"content": "## Flow 2: Approval & auto-publish\n\nEvery 15 minutes the workflow reads VideosTable, filters Status=approved, downloads the file and schedules it to the enabled platforms via Upload-Post. After a successful schedule, it updates the row to Status=scheduled."
},
"typeVersion": 1
},
{
"id": "4b1448f5-3640-42d3-8453-f15be7f7d8e5",
"name": "SAVE NOTE",
"type": "n8n-nodes-base.stickyNote",
"position": [
2672,
144
],
"parameters": {
"width": 420,
"height": 580,
"content": "## Flow 1: Save drafts\n\nFormats the AI output plus schedule info and appends a new row in VideosTable with Status=draft. Change Status to approved when you want Flow 2 to publish it."
},
"typeVersion": 1
},
{
"id": "7649ab2f-6975-466a-87d3-b8ba17bcd84b",
"name": "AI NOTE",
"type": "n8n-nodes-base.stickyNote",
"position": [
1936,
144
],
"parameters": {
"width": 712,
"height": 584,
"content": "## Flow 1: AI analysis & copy\n\nEach video is downloaded, analyzed with Gemini Flash, then Gemini Pro generates unique TikTok/Instagram/YouTube titles, descriptions and hashtags. The parser enforces valid JSON before saving."
},
"typeVersion": 1
},
{
"id": "11ab6690-4752-41a5-aef8-f86944f18538",
"name": "FETCH NOTE",
"type": "n8n-nodes-base.stickyNote",
"position": [
736,
208
],
"parameters": {
"width": 460,
"height": 516,
"content": "## Flow 1: Campaign intake & Drive fetch\n\nThe form collects campaign inputs. Google Drive lists files in the folder, then the filter keeps only video files before building the posting calendar."
},
"typeVersion": 1
},
{
"id": "51f64105-513c-4ec7-a018-a8861f9b5f74",
"name": "WORKFLOW INFO",
"type": "n8n-nodes-base.stickyNote",
"position": [
96,
-160
],
"parameters": {
"color": 4,
"width": 560,
"height": 456,
"content": "## How it works\nThis template has two flows. Flow 1 starts with a Form, reads all videos from a Google Drive folder, filters to keep video files, and builds a posting calendar using the start date, cadence and publish hour. Each file is downloaded, analyzed with Gemini, and used to generate platform-specific titles, descriptions and hashtags for TikTok, Instagram Reels and YouTube Shorts. The workflow then formats the results and appends them to a Google Sheet as drafts.\n\n## Setup steps\n1) Prepare a Google Drive folder with your videos.\n2) Copy this template sheet in your drive: https://docs.google.com/spreadsheets/d/1cegJHxj7Kx4Tg8gMr3uixpzToNc62VEvuuz37iFvnRw/edit?usp=sharing\n3) Connect Google Drive, Google Sheets and Google Gemini credentials.\n4) Run the Form and provide the Drive Folder ID, Upload-Post profile username, platforms, timezone, start date, cadence, publish hour, and Sheet ID.\n5) Activate the workflow. Set any draft row Status to approved; Flow 2 checks every 15 minutes, schedules it via Upload-Post, and updates the row to scheduled."
},
"typeVersion": 1
},
{
"id": "4bbab1e5-df87-450f-bc5d-daa110838cf4",
"name": "Start Campaign",
"type": "n8n-nodes-base.formTrigger",
"position": [
368,
384
],
"parameters": {
"options": {},
"formTitle": "Social Video Autopilot",
"formFields": {
"values": [
{
"fieldLabel": "Google Drive Folder ID",
"placeholder": "1jojIQ8TUjC_O-HfuhcjZfJSGSOl-h0Om",
"requiredField": true
},
{
"fieldLabel": "Profile Username (Upload-Post)",
"placeholder": "mi_perfil_whitelabel",
"requiredField": true
},
{
"fieldType": "dropdown",
"fieldLabel": "Platforms",
"fieldOptions": {
"values": [
{
"option": "TikTok, Instagram, YouTube"
},
{
"option": "TikTok, Instagram"
},
{
"option": "TikTok, YouTube"
},
{
"option": "Instagram, YouTube"
},
{
"option": "TikTok"
},
{
"option": "Instagram"
},
{
"option": "YouTube"
}
]
},
"requiredField": true
},
{
"fieldLabel": "Start Date (YYYY-MM-DD)",
"placeholder": "2025-12-09",
"requiredField": true
},
{
"fieldType": "dropdown",
"fieldLabel": "Cadence",
"fieldOptions": {
"values": [
{
"option": "1_daily"
},
{
"option": "5_per_week"
},
{
"option": "3_per_week"
}
]
},
"requiredField": true
},
{
"fieldLabel": "Publish Hour (HH:MM)",
"placeholder": "09:00",
"requiredField": true
},
{
"fieldLabel": "Google Sheet ID (for tracking)",
"placeholder": "1lg_YOUR_AWS_SECRET_KEY_HERE",
"requiredField": true
}
]
},
"formDescription": "Batch process and schedule your videos across TikTok, Instagram & YouTube with AI-powered optimization"
},
"typeVersion": 2.2
},
{
"id": "4b849329-0771-4a37-9491-0cd2315fb10f",
"name": "Campaign Settings",
"type": "n8n-nodes-base.set",
"position": [
528,
384
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "drive_folder_id",
"name": "drive_folder_id",
"type": "string",
"value": "={{ $json['Google Drive Folder ID'] }}"
},
{
"id": "profile_username",
"name": "profile_username",
"type": "string",
"value": "={{ $json['Profile Username (Upload-Post)'] }}"
},
{
"id": "platforms_raw",
"name": "platforms_raw",
"type": "string",
"value": "={{ $json['Platforms'] }}"
},
{
"id": "timezone",
"name": "timezone",
"type": "string",
"value": "={{ $json['Timezone'] }}"
},
{
"id": "start_date",
"name": "start_date",
"type": "string",
"value": "={{ $json['Start Date (YYYY-MM-DD)'] }}"
},
{
"id": "cadence",
"name": "cadence",
"type": "string",
"value": "={{ $json['Cadence'] }}"
},
{
"id": "publish_hour",
"name": "publish_hour",
"type": "string",
"value": "={{ $json['Publish Hour (HH:MM)'] }}"
},
{
"id": "sheet_id",
"name": "sheet_id",
"type": "string",
"value": "={{ $json['Google Sheet ID (for tracking)'] }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "8d8a2adc-b83f-4e09-9fd4-520ad2cf6c00",
"name": "Fetch Videos from Drive",
"type": "n8n-nodes-base.googleDrive",
"position": [
800,
384
],
"parameters": {
"filter": {},
"options": {},
"resource": "fileFolder",
"returnAll": true,
"queryString": "='{{ $json.drive_folder_id }}' in parents and trashed = false",
"searchMethod": "query"
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "bcc2ac88-8e63-4328-a060-575818f0f487",
"name": "Video Files Only",
"type": "n8n-nodes-base.filter",
"position": [
1040,
384
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "video-mp4",
"operator": {
"type": "string",
"operation": "contains"
},
"leftValue": "={{ $json.name }}",
"rightValue": ".mp4"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "dfc0a1f7-5c8c-4b2a-964a-c546d7f008af",
"name": "Build Schedule Calendar",
"type": "n8n-nodes-base.code",
"position": [
1280,
384
],
"parameters": {
"jsCode": "// Get configuration from Campaign Settings node\nconst config = $('Campaign Settings').first().json;\n\nconst items = $input.all();\nconst enrichedItems = [];\n\nconst startDate = new Date(config.start_date);\nlet cadenceDays = [];\n\nswitch(config.cadence) {\n case '1_daily':\n for(let i = 0; i < items.length; i++) cadenceDays.push(i);\n break;\n case '5_per_week':\n let dayCounter5 = 0;\n let weekDay5 = startDate.getDay();\n for(let i = 0; i < items.length; i++) {\n while(weekDay5 === 0 || weekDay5 === 6) {\n dayCounter5++;\n weekDay5 = (startDate.getDay() + dayCounter5) % 7;\n }\n cadenceDays.push(dayCounter5);\n dayCounter5++;\n weekDay5 = (startDate.getDay() + dayCounter5) % 7;\n }\n break;\n case '3_per_week':\n let dayCounter3 = 0;\n for(let i = 0; i < items.length; i++) {\n while(![1, 3, 5].includes((startDate.getDay() + dayCounter3) % 7)) dayCounter3++;\n cadenceDays.push(dayCounter3);\n dayCounter3++;\n }\n break;\n}\n\nfor (let i = 0; i < items.length; i++) {\n const item = items[i];\n const scheduleDaysOffset = cadenceDays[i] ?? i;\n\n const scheduleDate = new Date(startDate);\n scheduleDate.setDate(scheduleDate.getDate() + scheduleDaysOffset);\n const scheduleDateStr = scheduleDate.toISOString().split('T')[0];\n const scheduleDateTime = `${scheduleDateStr}T${config.publish_hour}:00`;\n\n enrichedItems.push({\n json: {\n ...item.json,\n video_index: i + 1,\n total_videos: items.length,\n config: {\n drive_folder_id: config.drive_folder_id,\n profile_username: config.profile_username,\n platforms_raw: config.platforms_raw,\n timezone: config.timezone,\n start_date: config.start_date,\n cadence: config.cadence,\n publish_hour: config.publish_hour,\n sheet_id: config.sheet_id\n },\n schedule: {\n date: scheduleDateStr,\n datetime: scheduleDateTime\n }\n }\n });\n}\n\nreturn enrichedItems;"
},
"typeVersion": 2
},
{
"id": "7f2ae67b-4dfc-4df8-a678-489a60fd260b",
"name": "Process Each Video",
"type": "n8n-nodes-base.splitInBatches",
"position": [
1520,
384
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "e5844599-a45e-41df-bc14-c9ee5314fd48",
"name": "Download from Drive",
"type": "n8n-nodes-base.googleDrive",
"position": [
1760,
368
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.id }}"
},
"options": {},
"operation": "download"
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "f69c1659-1e4e-4986-b870-5fda82c87f22",
"name": "AI Video Analysis",
"type": "@n8n/n8n-nodes-langchain.googleGemini",
"position": [
2000,
368
],
"parameters": {
"text": "=Analyze the attached video and provide:\n\n1) DETAILED DESCRIPTION: A thorough, faithful narrative of what is seen and heard.\n2) FULL TRANSCRIPTION of the audio.\n3) KEYWORDS: 10-15 SEO-relevant keywords.\n4) KEY MOMENTS with approximate timestamps.\n5) CONTENT TYPE (tutorial, review, vlog, entertainment, educational, etc.).\n6) TONE (serious, funny, professional, casual, etc.).\n7) DETECTED PRIMARY LANGUAGE of the spoken content.\n\nImportant output rule:\nStart your answer with a single line exactly like:\nDetected language: <English|Spanish|Other>\n\nThen write the rest of the analysis in English.\nThis analysis will be used to generate social titles and descriptions in the same detected language.",
"modelId": {
"__rl": true,
"mode": "list",
"value": "models/gemini-2.5-flash",
"cachedResultName": "models/gemini-2.5-flash"
},
"options": {},
"resource": "video",
"inputType": "binary",
"operation": "analyze"
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "ecb3ab65-a67e-47cc-8707-8d45af3608f4",
"name": "Generate Social Copy",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
2192,
368
],
"parameters": {
"text": "=[VIDEO ANALYSIS]\n{{ $json.content.parts[0].text }}\n\n[FILE INFO]\nName: {{ $('Download from Drive').item.json.name }}\n\n[CAMPAIGN SETTINGS]\nPlatforms: {{ $json.config.platforms_raw }}\n\n[GOAL]\nGenerate platform-specific titles, descriptions and hashtags for the selected platforms.\n\nLanguage rule:\n- Use the SAME language as the video.\n- The analysis starts with \"Detected language:\". Follow it strictly.\n- If it says English, write everything in English.\n- If it says Spanish, write everything in Spanish (Spain).\n\nOutput rules:\n- Each platform must be UNIQUE (do not copy/paste across platforms).\n- Return ONLY valid JSON matching this exact structure:\n{\n \"tiktok\": {\n \"title\": \"Optimized TikTok title (max 150 chars, strong hook)\",\n \"description\": \"Short, engaging TikTok description\",\n \"hashtags\": \"#hashtag1 #hashtag2 ...\"\n },\n \"instagram\": {\n \"title\": \"Optimized Instagram Reels caption\",\n \"description\": \"Value-driven description with CTA\",\n \"hashtags\": \"#hashtag1 #hashtag2 ...\"\n },\n \"youtube\": {\n \"title\": \"SEO-first YouTube Shorts title\",\n \"description\": \"YouTube description with natural keywords and CTA\",\n \"tags\": \"tag1, tag2, tag3\"\n },\n \"summary\": \"Very short internal summary\"\n}",
"options": {
"systemMessage": "You are a social media content marketing expert specialized in TikTok, Instagram Reels and YouTube Shorts.\n\nYour goals:\n- Maximize CTR\n- Improve retention\n- Increase engagement\n- Improve organic reach\n- Boost SEO on YouTube\n\nPlatform guidelines:\n\nTikTok:\n- Short, punchy titles with an emotional hook\n- Use emojis sparingly if the language/style fits\n- 10-15 hashtags mixing trending + niche\n- Casual, native tone\n\nInstagram Reels:\n- Strong first line hook\n- Slightly longer caption with light storytelling\n- Clear CTA (save, share, comment)\n- 20-30 hashtags mixing large/medium/niche\n\nYouTube Shorts:\n- SEO-first title, main keyword near the start\n- Ideal 50-60 characters\n- Description with natural keywords and CTA\n- 10-15 tags comma-separated\n\nCritical rules:\n- Each platform content must be DIFFERENT\n- Do not invent facts not present in the video\n- Output ONLY valid JSON, no markdown\n- Use the language detected in the analysis line: \"Detected language:\""
},
"promptType": "define",
"hasOutputParser": true
},
"retryOnFail": true,
"typeVersion": 3
},
{
"id": "a4f34bd2-8f50-41e7-8db8-2681c1add61b",
"name": "Gemini Pro",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
2192,
592
],
"parameters": {
"options": {}
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "47d7f3de-a93d-47cf-9dbe-1b9070ba8f71",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
2336,
576
],
"parameters": {
"autoFix": true,
"jsonSchemaExample": "{\n \"tiktok\": {\n \"title\": \"Optimized TikTok title (max 150 chars, strong hook)\",\n \"description\": \"Short, engaging TikTok description\",\n \"hashtags\": \"#hashtag1 #hashtag2 #hashtag3\"\n },\n \"instagram\": {\n \"title\": \"Optimized Instagram Reels caption\",\n \"description\": \"Value-driven description with CTA\",\n \"hashtags\": \"#hashtag1 #hashtag2\"\n },\n \"youtube\": {\n \"title\": \"SEO-first YouTube Shorts title\",\n \"description\": \"YouTube description with natural keywords and CTA\",\n \"tags\": \"tag1, tag2, tag3\"\n },\n \"summary\": \"Very short internal summary\"\n}"
},
"typeVersion": 1.3
},
{
"id": "0def5138-4385-45b0-96e0-cb334d208c8a",
"name": "Format Content Data",
"type": "n8n-nodes-base.code",
"position": [
2496,
368
],
"parameters": {
"jsCode": "const items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n const calendarInfo = $('Build Schedule Calendar').item?.json ?? {};\n const downloadInfo = $('Download from Drive').item?.json ?? {};\n\n const makeBaseRow = () => ({\n \"Video ID\": calendarInfo?.id || downloadInfo?.id || 'unknown',\n \"Video Name\": downloadInfo?.name || calendarInfo?.name || 'unknown',\n \"Index\": String(calendarInfo?.video_index ?? ''),\n \"Status\": 'draft',\n \"Schedule Date\": calendarInfo?.schedule?.date || '',\n \"Schedule DateTime\": calendarInfo?.schedule?.datetime || '',\n\n \"TikTok Title\": '',\n \"TikTok Description\": '',\n \"TikTok Hashtags\": '',\n\n \"Instagram Title\": '',\n \"Instagram Description\": '',\n \"Instagram Hashtags\": '',\n\n \"YouTube Title\": '',\n \"YouTube Description\": '',\n \"YouTube Tags\": '',\n\n \"Summary\": '',\n \"Profile\": calendarInfo?.config?.profile_username || '',\n \"Platforms\": calendarInfo?.config?.platforms_raw || '',\n \"Created At\": new Date().toISOString()\n });\n\n try {\n const rawOutput = item.json.output ?? item.json.text ?? item.json;\n\n let content;\n if (rawOutput && typeof rawOutput === 'object' && !Array.isArray(rawOutput)) {\n content = rawOutput;\n } else {\n let cleanedOutput = String(rawOutput)\n .replace(/```json\\n?/g, '')\n .replace(/```\\n?/g, '')\n .trim();\n\n const firstBrace = cleanedOutput.indexOf('{');\n const lastBrace = cleanedOutput.lastIndexOf('}');\n if (firstBrace !== -1 && lastBrace !== -1 && lastBrace > firstBrace) {\n cleanedOutput = cleanedOutput.slice(firstBrace, lastBrace + 1);\n }\n\n content = JSON.parse(cleanedOutput);\n }\n\n const row = makeBaseRow();\n\n row[\"TikTok Title\"] = content.tiktok?.title || '';\n row[\"TikTok Description\"] = content.tiktok?.description || '';\n row[\"TikTok Hashtags\"] = content.tiktok?.hashtags || '';\n\n row[\"Instagram Title\"] = content.instagram?.title || '';\n row[\"Instagram Description\"] = content.instagram?.description || '';\n row[\"Instagram Hashtags\"] = content.instagram?.hashtags || '';\n\n row[\"YouTube Title\"] = content.youtube?.title || '';\n row[\"YouTube Description\"] = content.youtube?.description || '';\n row[\"YouTube Tags\"] = content.youtube?.tags || '';\n\n row[\"Summary\"] = content.summary || '';\n\n results.push({ json: row });\n } catch (error) {\n const row = makeBaseRow();\n row[\"Status\"] = 'error';\n row[\"Summary\"] = `PARSE_ERROR: ${error.message}`;\n results.push({ json: row });\n }\n}\n\nreturn results;"
},
"typeVersion": 2
},
{
"id": "f58e58d3-88a4-4f92-9d06-c9bc829ef206",
"name": "Save Draft to Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
2736,
368
],
"parameters": {
"columns": {
"value": {},
"schema": [
{
"id": "Video ID",
"type": "string",
"display": true,
"required": false,
"displayName": "Video ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Video Name",
"type": "string",
"display": true,
"required": false,
"displayName": "Video Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Index",
"type": "string",
"display": true,
"required": false,
"displayName": "Index",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Schedule Date",
"type": "string",
"display": true,
"required": false,
"displayName": "Schedule Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Schedule DateTime",
"type": "string",
"display": true,
"required": false,
"displayName": "Schedule DateTime",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "TikTok Title",
"type": "string",
"display": true,
"required": false,
"displayName": "TikTok Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "TikTok Description",
"type": "string",
"display": true,
"required": false,
"displayName": "TikTok Description",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "TikTok Hashtags",
"type": "string",
"display": true,
"required": false,
"displayName": "TikTok Hashtags",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Instagram Title",
"type": "string",
"display": true,
"required": false,
"displayName": "Instagram Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Instagram Description",
"type": "string",
"display": true,
"required": false,
"displayName": "Instagram Description",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Instagram Hashtags",
"type": "string",
"display": true,
"required": false,
"displayName": "Instagram Hashtags",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "YouTube Title",
"type": "string",
"display": true,
"required": false,
"displayName": "YouTube Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "YouTube Description",
"type": "string",
"display": true,
"required": false,
"displayName": "YouTube Description",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "YouTube Tags",
"type": "string",
"display": true,
"required": false,
"displayName": "YouTube Tags",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Summary",
"type": "string",
"display": true,
"required": false,
"displayName": "Summary",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Profile",
"type": "string",
"display": true,
"required": false,
"displayName": "Profile",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Platforms",
"type": "string",
"display": true,
"required": false,
"displayName": "Platforms",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Created At",
"type": "string",
"display": true,
"required": false,
"displayName": "Created At",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "autoMapInputData",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {
"cellFormat": "USER_ENTERED"
},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "VideosTable"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Campaign Settings').first().json.sheet_id }}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "cb08748d-d99a-4743-a19a-9d94bd51c3ba",
"name": "Publisher Config",
"type": "n8n-nodes-base.set",
"position": [
560,
1040
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "sheet_id_2",
"name": "sheet_id",
"type": "string",
"value": "1cegJHxj7Kx4Tg8gMr3uixpzToNc62VEvuuz37iFvnRw"
},
{
"id": "drive_id_2",
"name": "drive_folder_id",
"type": "string",
"value": "1LB5YDDVnt0vLeC9qN1jc0UgLjMsnCRYn"
},
{
"id": "profile_2",
"name": "profile_username",
"type": "string",
"value": "automated-tests"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "8271992f-6325-401d-b3ba-cfcb5ee43121",
"name": "Load Content Queue",
"type": "n8n-nodes-base.googleSheets",
"position": [
800,
1040
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "name",
"value": "VideosTable"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.sheet_id }}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "2d6f6002-bb19-47c1-9bd3-4b023a5f42fa",
"name": "Only Approved",
"type": "n8n-nodes-base.filter",
"position": [
1040,
1040
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "status-approved",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.Status }}",
"rightValue": "approved"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "537be859-9d07-4492-835a-0958cc1702f8",
"name": "Process Queue",
"type": "n8n-nodes-base.splitInBatches",
"position": [
1280,
1040
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "fff9142c-bca7-4bb2-b44d-64924ac9b695",
"name": "Get Video File",
"type": "n8n-nodes-base.googleDrive",
"position": [
1520,
1040
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $json['Video ID'] }}"
},
"options": {},
"operation": "download"
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "8fcd5a01-cce9-4657-93d6-65d8b54efb6b",
"name": "Build Upload Payload",
"type": "n8n-nodes-base.code",
"position": [
1760,
1040
],
"parameters": {
"jsCode": "const item = $input.first();\nconst sheetData = item.json;\nconst config = $('Publisher Config').first().json;\n\nconst platforms = (sheetData.Platforms || 'tiktok,instagram,youtube').toLowerCase();\n\nreturn {\n json: {\n video_id: sheetData['Video ID'],\n video_name: sheetData['Video Name'],\n row_index: sheetData.row_number,\n\n has_tiktok: platforms.includes('tiktok'),\n has_instagram: platforms.includes('instagram'),\n has_youtube: platforms.includes('youtube'),\n\n tiktok_content: [sheetData['TikTok Title'], sheetData['TikTok Description'], sheetData['TikTok Hashtags']].filter(Boolean).join('\\n\\n'),\n instagram_content: [sheetData['Instagram Title'], sheetData['Instagram Description'], sheetData['Instagram Hashtags']].filter(Boolean).join('\\n\\n'),\n\n youtube_title: sheetData['YouTube Title'] || '',\n youtube_description: sheetData['YouTube Description'] || '',\n\n schedule_datetime: sheetData['Schedule DateTime'] || '',\n\n profile_username: sheetData.Profile || config.profile_username,\n sheet_id: config.sheet_id\n },\n binary: item.binary\n};"
},
"typeVersion": 2
},
{
"id": "32780527-174c-4926-b760-911556755750",
"name": "TikTok Enabled?",
"type": "n8n-nodes-base.if",
"position": [
2000,
880
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "tiktok-check",
"operator": {
"type": "boolean",
"operation": "true"
},
"leftValue": "={{ $json.has_tiktok }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "05d73820-46e5-4dff-b6e4-1fe20482639e",
"name": "Instagram Enabled?",
"type": "n8n-nodes-base.if",
"position": [
2000,
1040
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "ig-check",
"operator": {
"type": "boolean",
"operation": "true"
},
"leftValue": "={{ $json.has_instagram }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "8ba87910-da6f-4c0c-8d92-f0c4c30dee24",
"name": "YouTube Enabled?",
"type": "n8n-nodes-base.if",
"position": [
2000,
1200
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "yt-check",
"operator": {
"type": "boolean",
"operation": "true"
},
"leftValue": "={{ $json.has_youtube }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "81515599-ec20-4e67-8039-e57bbd1d0470",
"name": "Schedule TikTok",
"type": "n8n-nodes-upload-post.uploadPost",
"position": [
2240,
864
],
"parameters": {
"user": "automated-tests",
"title": "={{ $json.tiktok_content }}",
"video": "data",
"platform": [
"tiktok"
],
"operation": "uploadVideo",
"scheduledDate": "={{ $json.schedule_datetime }}",
"waitForCompletion": "="
},
"credentials": {
"uploadPostApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "94ab80ea-33cf-4b4e-8b3f-30db536bd2e9",
"name": "Schedule Instagram",
"type": "n8n-nodes-upload-post.uploadPost",
"position": [
2240,
1024
],
"parameters": {
"user": "automated-tests",
"title": "={{ $json.instagram_content }}",
"video": "data",
"platform": [
"instagram"
],
"operation": "uploadVideo",
"scheduledDate": "={{ $json.schedule_datetime }}",
"waitForCompletion": "=",
"instagramMediaType": "REELS"
},
"credentials": {
"uploadPostApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "fe8db90a-f902-4c2e-b600-5b8583580b76",
"name": "Schedule YouTube",
"type": "n8n-nodes-upload-post.uploadPost",
"position": [
2240,
1184
],
"parameters": {
"user": "automated-tests",
"title": "={{ $json.youtube_title }}",
"video": "data",
"platform": [
"youtube"
],
"operation": "uploadVideo",
"youtubeTitle": "={{ $json.youtube_title }}",
"scheduledDate": "={{ $json.schedule_datetime }}",
"waitForCompletion": "="
},
"credentials": {
"uploadPostApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "3cd7eafd-2a62-4fa4-9599-99012580bb04",
"name": "Mark as Scheduled",
"type": "n8n-nodes-base.googleSheets",
"position": [
2576,
1024
],
"parameters": {
"columns": {
"value": {
"Status": "scheduled",
"Video ID": "={{ $('Get Video File').item.json[\"Video ID\"] }}"
},
"schema": [
{
"id": "Video ID",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Video ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Video Name",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Video Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Index",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Index",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Schedule Date",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Schedule Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Schedule DateTime",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Schedule DateTime",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "TikTok Title",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "TikTok Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "TikTok Description",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "TikTok Description",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "TikTok Hashtags",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "TikTok Hashtags",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Instagram Title",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Instagram Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Instagram Description",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Instagram Description",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Instagram Hashtags",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Instagram Hashtags",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "YouTube Title",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "YouTube Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "YouTube Description",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "YouTube Description",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "YouTube Tags",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "YouTube Tags",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Summary",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Summary",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Profile",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Profile",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Platforms",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Platforms",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Created At",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Created At",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "number",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"Video ID"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1275860196,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1cegJHxj7Kx4Tg8gMr3uixpzToNc62VEvuuz37iFvnRw/edit#gid=1275860196",
"cachedResultName": "VideosTable"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Publisher Config').item.json.sheet_id }}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "cf513981-645e-4221-838f-68f75e9da08c",
"name": "15 mins check",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
304,
1040
],
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 15
}
]
}
},
"typeVersion": 1.2
},
{
"id": "eb774e71-1f51-4da3-931a-0ceffd6d502d",
"name": "FETCH NOTE1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1920,
736
],
"parameters": {
"width": 460,
"height": 628,
"content": "## Upload to social networks\n\nIs configured Tiktok Instagram and Youtube, but you can add all : TikTok, Instagram, LinkedIn, YouTube, Facebook, X, Threads, Pinterest, Reddit, Bluesky"
},
"typeVersion": 1
},
{
"id": "9182d207-8e6c-47e5-b092-c86a06b5b8e2",
"name": "SAVE NOTE1",
"type": "n8n-nodes-base.stickyNote",
"position": [
2400,
736
],
"parameters": {
"width": 420,
"height": 628,
"content": "## Flow 1: Save Schedule\n\nFormats the AI output plus schedule info and appends a new row in VideosTable with Status=approved. Change Status to scheduled when you want Flow 2 to publish it."
},
"typeVersion": 1
}
],
"connections": {
"Gemini Pro": {
"ai_languageModel": [
[
{
"node": "Generate Social Copy",
"type": "ai_languageModel",
"index": 0
},
{
"node": "Structured Output Parser",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"15 mins check": {
"main": [
[
{
"node": "Publisher Config",
"type": "main",
"index": 0
}
]
]
},
"Only Approved": {
"main": [
[
{
"node": "Process Queue",
"type": "main",
"index": 0
}
]
]
},
"Process Queue": {
"main": [
[],
[
{
"node": "Get Video File",
"type": "main",
"index": 0
}
]
]
},
"Get Video File": {
"main": [
[
{
"node": "Build Upload Payload",
"type": "main",
"index": 0
}
]
]
},
"Start Campaign": {
"main": [
[
{
"node": "Campaign Settings",
"type": "main",
"index": 0
}
]
]
},
"Schedule TikTok": {
"main": [
[
{
"node": "Mark as Scheduled",
"type": "main",
"index": 0
}
]
]
},
"TikTok Enabled?": {
"main": [
[
{
"node": "Schedule TikTok",
"type": "main",
"index": 0
}
]
]
},
"Publisher Config": {
"main": [
[
{
"node": "Load Content Queue",
"type": "main",
"index": 0
}
]
]
},
"Schedule YouTube": {
"main": [
[
{
"node": "Mark as Scheduled",
"type": "main",
"index": 0
}
]
]
},
"Video Files Only": {
"main": [
[
{
"node": "Build Schedule Calendar",
"type": "main",
"index": 0
}
]
]
},
"YouTube Enabled?": {
"main": [
[
{
"node": "Schedule YouTube",
"type": "main",
"index": 0
}
]
]
},
"AI Video Analysis": {
"main": [
[
{
"node": "Generate Social Copy",
"type": "main",
"index": 0
}
]
]
},
"Campaign Settings": {
"main": [
[
{
"node": "Fetch Videos from Drive",
"type": "main",
"index": 0
}
]
]
},
"Mark as Scheduled": {
"main": [
[
{
"node": "Process Queue",
"type": "main",
"index": 0
}
]
]
},
"Instagram Enabled?": {
"main": [
[
{
"node": "Schedule Instagram",
"type": "main",
"index": 0
}
]
]
},
"Load Content Queue": {
"main": [
[
{
"node": "Only Approved",
"type": "main",
"index": 0
}
]
]
},
"Process Each Video": {
"main": [
[],
[
{
"node": "Download from Drive",
"type": "main",
"index": 0
}
]
]
},
"Schedule Instagram": {
"main": [
[
{
"node": "Mark as Scheduled",
"type": "main",
"index": 0
}
]
]
},
"Download from Drive": {
"main": [
[
{
"node": "AI Video Analysis",
"type": "main",
"index": 0
}
]
]
},
"Format Content Data": {
"main": [
[
{
"node": "Save Draft to Sheet",
"type": "main",
"index": 0
}
]
]
},
"Save Draft to Sheet": {
"main": [
[
{
"node": "Process Each Video",
"type": "main",
"index": 0
}
]
]
},
"Build Upload Payload": {
"main": [
[
{
"node": "TikTok Enabled?",
"type": "main",
"index": 0
},
{
"node": "Instagram Enabled?",
"type": "main",
"index": 0
},
{
"node": "YouTube Enabled?",
"type": "main",
"index": 0
}
]
]
},
"Generate Social Copy": {
"main": [
[
{
"node": "Format Content Data",
"type": "main",
"index": 0
}
]
]
},
"Build Schedule Calendar": {
"main": [
[
{
"node": "Process Each Video",
"type": "main",
"index": 0
}
]
]
},
"Fetch Videos from Drive": {
"main": [
[
{
"node": "Video Files Only",
"type": "main",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "Generate Social Copy",
"type": "ai_outputParser",
"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.
googleDriveOAuth2ApigooglePalmApigoogleSheetsOAuth2ApiuploadPostApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow automates batch video publishing prep from a Google Drive folder with AI-generated, platform-specific copy and a simple approval queue in Google Sheets. Perfect for Agencies, content creators or Teams Fetches videos from a Google Drive folder You provide a folder…
Source: https://n8n.io/workflows/11638/ — 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.
Streamline your recruitment process with AI-powered resume analysis that goes beyond keyword matching.
This workflow automatically creates AI product review videos from a product image and short description using n8n and Veo 3.
A fully automated Telegram-based personal finance tracker that: Accepts receipts as images, PDFs, or plain text Uses Google Gemini Vision for OCR & intelligent extraction Logs every expense into Googl
This workflow transforms any video you drop into a Google Drive folder into a ready-to-publish YouTube upload. It analyzes the video with AI to craft 3 high-CTR title ideas, 3 long SEO-friendly descri
This n8n workflow is a full inbound → outbound hybrid funnel designed for AI agencies. It captures warm leads through instant AI value, then automatically follows up with personalized, context-aware o