This workflow corresponds to n8n.io template #14316 — we link there as the canonical source.
This workflow follows the Agent → Execute Workflow 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": "d89322eb-8d39-4e43-81a6-5c5e851ba92b",
"name": "Get Video Ideas",
"type": "n8n-nodes-base.googleSheets",
"position": [
-7808,
480
],
"parameters": {
"sheetName": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": ""
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1XgFKo9N2jIiUNtizbpQXMAIDc6mSOhngW6EnAKdtawc",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1XgFKo9N2jIiUNtizbpQXMAIDc6mSOhngW6EnAKdtawc/edit?usp=drivesdk",
"cachedResultName": "Ads Factory: Tax Relief - Final AI Videos (n8n)"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 4.7,
"waitBetweenTries": 5000
},
{
"id": "6994d18f-8ffb-4f78-9f24-ff172b73fca7",
"name": "HTTP Request12",
"type": "n8n-nodes-base.httpRequest",
"position": [
-7552,
1728
],
"parameters": {
"url": "https://api.kie.ai/api/v1/veo/generate",
"method": "POST",
"options": {},
"jsonBody": "={\n \"prompt\": {{ JSON.stringify($json.SCRIPT.parseJson()) }},\n \"imageUrls\": [\"{{ $json['IMAGE URL'] }}\",\"{{ $json['IMAGE URL'] }}\" ],\n \"model\": \"veo3_fast\",\n \"aspect_ratio\": \"Auto\",\n \"generationType\": \"FIRST_AND_LAST_FRAMES_2_VIDEO\"\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"retryOnFail": true,
"typeVersion": 4.3,
"waitBetweenTries": 5000
},
{
"id": "8652d395-55d2-42a9-a379-68c14272c501",
"name": "HTTP Request13",
"type": "n8n-nodes-base.httpRequest",
"position": [
-7376,
1728
],
"parameters": {
"url": "=https://api.kie.ai/api/v1/veo/record-info?taskId={{ $json.data.taskId }}",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"retryOnFail": true,
"typeVersion": 4.3,
"waitBetweenTries": 5000
},
{
"id": "0148cb0b-b080-46dd-9b60-e055dcb1388e",
"name": "Wait6",
"type": "n8n-nodes-base.wait",
"position": [
-7200,
1888
],
"parameters": {
"unit": "minutes",
"amount": 10
},
"typeVersion": 1.1
},
{
"id": "fe407dbe-fa9f-4d53-a4df-106be370ccd9",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-8960,
336
],
"parameters": {
"width": 768,
"height": 816,
"content": " \n # UGC Ads Factory \n **Automated AI pipeline for UGC-style video ads** \n \n `Create row \u2192 Reference image \u2192 Scene plan \u2192 Scene clips \u2192 Stitch final video \u2192 Publish links` \n \n ### How it works \n - The trigger reads rows in **Videos** where `LAUNCH CREATION = Create`, normalizes fields, and marks each row `Processing`. \n - Kie creates a reference image. The workflow polls until completion, then uploads and shares the image in Google Drive. \n - Claude-4o-mini analyzes visual details. Claude Opus converts the script into ordered 8-second scenes with consistent visual context and movement prompts. \n - Each scene is appended to **Video Data** using `VIDEO ID`, `SCENE NO`, `SCRIPT`, and `TOTAL SCENES`. \n - VEO3 generates one clip per scene. Successful clips are uploaded and linked; failures are logged with error state. \n - After all scenes complete, clips are sorted and merged via fal.ai FFmpeg. \n - Final video links are written back to **Videos**, and campaign status becomes `Completed`. \n \n ### Setup \n - Configure credentials: Google Sheets, Google Drive, Kie, OpenRouter, OpenAI, fal.ai. \n - Confirm sheet/tab names and column headers exactly match workflow mapping. \n - Set destination folder IDs for image clips and final stitched videos. \n \n ### Customization \n - Tune scene length, polling intervals, model defaults, retry policy, and failure-routing behavior. "
},
"typeVersion": 1
},
{
"id": "0559e237-00ff-4efe-a47e-36c8af909baf",
"name": "Video Status Check",
"type": "n8n-nodes-base.switch",
"position": [
-7200,
1696
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "Success",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "vid-poll-success-flag",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $json.data.successFlag }}",
"rightValue": 1
},
{
"id": "vid-poll-success-state",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.state }}",
"rightValue": "success"
}
]
},
"renameOutput": true
},
{
"outputKey": "Failed",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "vid-poll-failed-flag",
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "={{ $json.data.successFlag }}",
"rightValue": 2
},
{
"id": "vid-poll-failed-state",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.state }}",
"rightValue": "failed"
}
]
},
"renameOutput": true
},
{
"outputKey": "Processing",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "vid-poll-processing-flag",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $json.data.successFlag }}",
"rightValue": 0
},
{
"id": "vid-poll-waiting",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.state }}",
"rightValue": "waiting"
},
{
"id": "vid-poll-processing",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.state }}",
"rightValue": "processing"
},
{
"id": "vid-poll-generating",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.state }}",
"rightValue": "generating"
}
]
},
"renameOutput": true
}
]
},
"options": {
"fallbackOutput": "extra",
"renameFallbackOutput": "Unknown Status"
}
},
"typeVersion": 3.4
},
{
"id": "4b470e1c-d761-4d7d-b1be-b52222135c20",
"name": "Prompt Agent LLM",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"position": [
-7488,
704
],
"parameters": {
"model": "anthropic/claude-opus-4.5",
"options": {}
},
"typeVersion": 1
},
{
"id": "5c6d334c-8555-4459-812e-b495955719c7",
"name": "Prompt Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
-7344,
704
],
"parameters": {
"schemaType": "manual",
"inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"prompt\": { \"type\": \"string\" },\n \"model\": { \"type\": \"string\" },\n \"aspectRatio\": { \"type\": \"string\" },\n \"resolution\": { \"type\": \"string\" }\n },\n \"required\": [\"prompt\", \"model\", \"aspectRatio\",\"resolution\"]\n}"
},
"typeVersion": 1.3
},
{
"id": "0b88243e-35a0-48ed-8642-7eb2fd553a23",
"name": "Image Gen Error",
"type": "n8n-nodes-base.stopAndError",
"position": [
-5696,
1904
],
"parameters": {
"errorMessage": "=Image generation API failed. Code: {{ $json.code }}. Message: {{ $json.msg }}"
},
"typeVersion": 1
},
{
"id": "757ee7c8-04b1-44a2-bdc5-2bc952ea21e8",
"name": "Script Agent LLM",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"position": [
-5456,
592
],
"parameters": {
"model": "anthropic/claude-opus-4.5",
"options": {}
},
"typeVersion": 1
},
{
"id": "f5fdbb5e-0f2d-4d74-a869-c86aa65fe6b2",
"name": "Scene Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
-5280,
592
],
"parameters": {
"schemaType": "manual",
"inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"scenes\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"scene_number\": { \"type\": \"number\" },\n \"script\": { \"type\": \"string\" },\n \"visual_description\": { \"type\": \"string\" },\n \"audio_description\": { \"type\": \"string\" },\n \"movement\": { \"type\": \"string\" },\n \"duration_seconds\": { \"type\": \"number\" }\n },\n \"required\": [\"scene_number\", \"script\", \"visual_description\", \"movement\", \"duration_seconds\"]\n }\n }\n },\n \"required\": [\"scenes\"]\n}\n"
},
"typeVersion": 1.3
},
{
"id": "a40e50b2-5f5c-4b7b-9e94-e3730408f4e3",
"name": "Nano Banana Prompt Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-7488,
480
],
"parameters": {
"text": "=Character Description:\n{{ $('Input').item.json.character_description }}\n\nVideo Script image reference:\n{{ $('Input').item.json.demo_script }}\n\nAspect_ratio:\n{{ $json.aspect_ratio }}\n\nGenerate the complete JSON for Nano Banana Pro API.",
"options": {
"systemMessage": "=You are an expert at crafting photorealistic AI image prompts for authentic UGC (User Generated Content) videos.\n\nTASK: Convert the user's character description and setting into a complete Nano Banana Pro API JSON body that generates an ultra-realistic raw mobile selfie photo. Use input details to ger\n\nSTRUCTURED PROMPT ELEMENTS (include ALL in your prompt string):\n\n1. CAMERA & COMPOSITION:\n - \"iPhone 15 Pro front camera selfie\"\n - \"9:16/169 vertical/Horizontal portrait orientation\"\n - \"close-up/Medium close up head and shoulders shot\"\n - \"35mm lens look, f/2.0 aperture\"\n - \"EXTREME shallow depth of field, heavy soft bokeh background\" (CRITICAL: The background must be blurred into soft shapes to hide details for later video generation, regardless of the setting)\n\n2. SETTING & POSTURE (Analyze user input and adapt dynamically):\n - IF CAR: \"Subject sitting in driver's seat of a car, phone positioned like a dash-mount or held casually, car interior and window, character looking toward camera.\"\n - IF WALKING (Indoors/Outdoors): \"Subject walking, holding camera at arm's length (vlog style), dynamic posture, background elements completely blurred to conceal movement. \"\n - IF ROOM (Bedroom, Office, Bathroom): \"Casual indoor environment, relaxed posture (sitting or standing), character looking toward camera.\"\n - IF OTHER: Apply natural UGC-style framing appropriate for the requested environment.\n\n3. LIGHTING (critical for realism):\n - \"Natural soft window light\" OR \"soft diffused daylight\"\n - \"Subtle rim light, no harsh shadows\"\n - AVOID: \"studio lighting\", \"flash\", \"ring light\"\n\n4. SUBJECT REALISM (anti-AI detection):\n - \"Realistic skin texture with visible pores, subtle skin imperfections\"\n - \"Authentic facial expression, mid-conversation, natural hair\"\n5. IMPORTANT:\n - No iphone or mobile should be visible in the video.\n\nOUTPUT: Return ONLY valid JSON (no markdown, no explanation):\n{\n \"prompt\": \"[Comprehensive prompt combining all elements above with the user's character description]\",\n \"model\": \"nano_banana_pro\",\n \"aspectRatio\": \"9:16\",\n \"resolution\": \"2k\"\n}"
},
"promptType": "define",
"hasOutputParser": true
},
"retryOnFail": true,
"typeVersion": 3.1,
"waitBetweenTries": 5000
},
{
"id": "087b06f3-bed6-4e82-9c49-2652143803bd",
"name": "Generate UGC Image",
"type": "n8n-nodes-base.httpRequest",
"position": [
-7104,
480
],
"parameters": {
"url": "=https://api.kie.ai/api/v1/jobs/createTask",
"method": "POST",
"options": {},
"jsonBody": "={\n \"model\": \"nano-banana-2\",\n \"callBackUrl\": \"https://your-domain.com/api/callback\",\n \"input\": {\n \"prompt\": {{ JSON.stringify($json.output.prompt) }},\n \"aspect_ratio\": \"{{ $('Input').item.json.aspect_ratio }}\",\n \"resolution\": \"2K\",\n \"output_format\": \"png\"\n }\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"executeOnce": false,
"retryOnFail": true,
"typeVersion": 4.3,
"waitBetweenTries": 5000
},
{
"id": "c0d40d1a-ad66-4c7a-a1bb-ebe2e6c589d5",
"name": "Image Gen Response Check",
"type": "n8n-nodes-base.switch",
"position": [
-6912,
464
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "Success",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "img-gen-success",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $json.code }}",
"rightValue": 200
}
]
},
"renameOutput": true
},
{
"outputKey": "Error",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "img-gen-error",
"operator": {
"type": "number",
"operation": "notEquals"
},
"leftValue": "={{ $json.code }}",
"rightValue": 200
}
]
},
"renameOutput": true
}
]
},
"options": {
"fallbackOutput": "extra",
"renameFallbackOutput": "Unexpected"
}
},
"typeVersion": 3.4
},
{
"id": "e9040eb0-e298-4cb5-b8a2-e021476905a3",
"name": "Workflow Configuration3",
"type": "n8n-nodes-base.set",
"position": [
-5792,
400
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "7ee37300-28a6-4426-85c8-1b23dab144ea",
"name": "referenceImage",
"type": "string",
"value": "={{ $('Upload file').item.json.webViewLink }}"
},
{
"id": "ref-img",
"name": "download_image",
"type": "string",
"value": "={{ $('Upload file').item.json.webContentLink }}"
},
{
"id": "21a05480-dd91-4a05-a824-e260a621e4f6",
"name": "character_description",
"type": "string",
"value": "={{ $('Input').item.json.character_description }}"
},
{
"id": "demo-script",
"name": "demo_script",
"type": "string",
"value": "={{ $('Input').item.json.demo_script }}"
},
{
"id": "aspect-ratio",
"name": "aspect_ratio",
"type": "string",
"value": "={{ $('Input').item.json.aspect_ratio }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "3f7fdefa-aefa-40f1-b2cc-3d7a97a35655",
"name": "Split Scenes",
"type": "n8n-nodes-base.splitOut",
"position": [
-5168,
400
],
"parameters": {
"options": {},
"fieldToSplitOut": "output.scenes"
},
"typeVersion": 1
},
{
"id": "fe848a2d-d4ef-4015-839c-2107b9ad6250",
"name": "Analyze UGC Image3",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
-5600,
400
],
"parameters": {
"text": "Analyze this UGC image in detail. Describe the subject's appearance (age, ethnicity, hair, clothing), setting, lighting, mood, and composition. Focus on details needed for video generation consistency.",
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "GPT-4O-MINI"
},
"options": {
"detail": "high"
},
"resource": "image",
"imageUrls": "={{ $json.download_image }}",
"operation": "analyze"
},
"retryOnFail": true,
"typeVersion": 2.1
},
{
"id": "eef8c19c-57b7-4b3b-995d-f642cfa394fe",
"name": "Generate Scene Scripts3",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-5456,
400
],
"parameters": {
"text": "=Image Prompt:\n{{ $('Workflow Configuration3').item.json.character_description }}\n\nGenerated Image Analysis:\n{{ $json['0'].content[0].text }}\n\nUser Script:\n{{ $('Workflow Configuration3').item.json.demo_script }}\n\nCreate video scenes from this script.",
"options": {
"systemMessage": "=You are an expert Creative Director and Scriptwriter for AI-generated \"talking photo\" video sequences. \n\nCRITICAL GOAL\nYour task is to take a reference image analysis and user instructions (script/requirements) and turn them into a structured series of video scenes.\n\nVISUAL CONSISTENCY (Non-negotiable)\n1. The entire video is generated from ONE static reference image. \n2. The `visual_description` for EVERY scene must be IDENTICAL. \n3. Use the provided image analysis to create a concise (max 300 characters) static visual description. Add: \"iPhone UGC style, slightly grainy, authentic speaking gestures\".\n\nSCENE GENERATION LOGIC\n1. Split the script into logical segments of approximately 20 - 27 words (roughly 8 seconds of speech).\n2. Output a JSON object containing a \"scenes\" array.\n\nSCENE STRUCTURE RULES\nEach object in the `scenes` array must include:\n- `scene_number`: Sequential integer starting at 1.\n- `script`: The spoken text for that specific 8-second segment.\n- `visual_description`: The identical string described above.\n- `duration_seconds`: Always 8.\n\nDYNAMIC MOVEMENT LOGIC (Crucial for Video AI):\nAnalyze the setting from the image analysis and assign the appropriate `movement` string for EVERY scene:\n- IF CAR INTERIOR: \"natural head movements while talking, slight camera vibration from car idling, blurred scenery passing subtly in the windows.\"\n- IF WALKING (Outdoors/Indoors): \"continuous forward walking motion, subject holding camera vlog-style, natural camera bounce matching footsteps, heavily blurred background passing by smoothly.\"\n- IF STATIC ROOM (Bedroom/Office/Couch): \"natural subtle body movement, slight handheld camera drift, expressive facial gestures, static blurred background.\"\n- IF OTHER: Deduce the natural physics of the scene (is the camera static or moving? is the background static or moving?) and write a brief, cohesive motion prompt.\n\nSCRIPT RULES FOR AUTHENTICITY:\n- Don't include pauses: \"And I couldn't believe it\"\n- Conversational tone, not salesy\n- NO stage directions like [smiles] or [nods] in the script text.\n\nOUTPUT: Return ONLY valid JSON:\n{\n \"scenes\": [\n {\n \"scene_number\": 1,\n \"script\": \"The spoken text...\",\n \"visual_description\": \"Static description of the person...\",\n \"audio_description\": \"No background noice\",\n \"movement\": \"Dynamic motion instructions based on the identified environment...\",\n \"duration_seconds\": 8\n }\n ]\n}\n"
},
"promptType": "define",
"hasOutputParser": true
},
"retryOnFail": true,
"typeVersion": 3.1
},
{
"id": "5307f0e6-a123-43b9-8d77-b4fbb75cb652",
"name": "Input",
"type": "n8n-nodes-base.set",
"position": [
-7648,
480
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "8117b31c-6433-447e-89d0-1ae00d8bd3a5",
"name": "character_description",
"type": "string",
"value": "={{ $json['CHARACTER/SETTING DESCRIPTION'] }}"
},
{
"id": "711643da-17f7-46bc-8c66-294843d4a2b9",
"name": "demo_script",
"type": "string",
"value": "={{ $json.SCRIPT }}"
},
{
"id": "fb55afcc-a21b-49bb-b4b2-e9e504b7bc13",
"name": "aspect_ratio",
"type": "string",
"value": "={{ $json['ASPECT RATIO'] || \"9:16\" }}"
},
{
"id": "23dcda06-c268-4fcd-9e5f-4d8813dcbde7",
"name": "id",
"type": "string",
"value": "={{ $execution.id + '_' + Date.now().toString() + Math.random().toString(36).substring(2, 10) }}"
},
{
"id": "e30c7c90-87e9-47d5-b001-5062a3c7e678",
"name": "row_number",
"type": "number",
"value": "={{ $json.row_number }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "8dc23647-0633-47cf-942c-755cc4b9f94c",
"name": "videoInput",
"type": "n8n-nodes-base.set",
"position": [
-7728,
1728
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "94515e20-338a-425c-838d-f77c802c5266",
"name": "ID",
"type": "string",
"value": "={{ $json.ID }}"
},
{
"id": "aa02ee83-02aa-4aee-9e7b-2eb98bcdc902",
"name": "VIDEO ID",
"type": "string",
"value": "={{ $json['VIDEO ID'] }}"
},
{
"id": "cbda8d7e-3f8b-4b3c-8029-7564002e4068",
"name": "SCRIPT",
"type": "string",
"value": "={{ $json.SCRIPT }}"
},
{
"id": "e6a0442e-46b0-4226-a1f5-07e3fa9105a1",
"name": "IMAGE URL",
"type": "string",
"value": "={{ $json['IMAGE URL'] }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "160418ac-08be-4a9d-beb2-cd1074379038",
"name": "HTTP Request1",
"type": "n8n-nodes-base.httpRequest",
"position": [
-6960,
1680
],
"parameters": {
"url": "={{ $('Video Status Check').item.json.data.response.resultUrls[0] }}",
"options": {}
},
"retryOnFail": true,
"typeVersion": 4.4,
"waitBetweenTries": 5000
},
{
"id": "79ed8983-c1ca-4b49-aa0f-742f443de5b4",
"name": "Wait 10s",
"type": "n8n-nodes-base.wait",
"position": [
-6480,
608
],
"parameters": {
"amount": 60
},
"typeVersion": 1.1
},
{
"id": "d9a1c791-c535-4cd2-a6e5-a878aa144df3",
"name": "Image Poll Error",
"type": "n8n-nodes-base.stopAndError",
"position": [
-6480,
864
],
"parameters": {
"errorMessage": "=Image generation failed permanently. State: {{ $json.data.state }}. SuccessFlag: {{ $json.data.successFlag }}. Error: {{ $json.data.errorMessage || 'Unknown error' }}. TaskId: {{ $json.data.taskId }}"
},
"typeVersion": 1
},
{
"id": "210cb9ec-6c71-4673-8818-14fa28cb34c3",
"name": "Poll Image Status",
"type": "n8n-nodes-base.httpRequest",
"position": [
-6640,
448
],
"parameters": {
"url": "=https://api.kie.ai/api/v1/jobs/recordInfo?taskId={{ $json.data.taskId }}",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"retryOnFail": true,
"typeVersion": 4.3,
"waitBetweenTries": 5000
},
{
"id": "06526cb8-8aba-47bb-aefe-6553420fe5b1",
"name": "Image Status Check",
"type": "n8n-nodes-base.switch",
"position": [
-6480,
416
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "Success",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "img-poll-success-flag",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $json.data.successFlag }}",
"rightValue": 1
},
{
"id": "img-poll-success-state",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.state }}",
"rightValue": "success"
}
]
},
"renameOutput": true
},
{
"outputKey": "Failed",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "img-poll-failed-flag",
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "={{ $json.data.successFlag }}",
"rightValue": 2
},
{
"id": "img-poll-failed-state",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.state }}",
"rightValue": "failed"
}
]
},
"renameOutput": true
},
{
"outputKey": "Processing",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "img-poll-processing-flag",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $json.data.successFlag }}",
"rightValue": 0
},
{
"id": "img-poll-waiting",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.state }}",
"rightValue": "waiting"
},
{
"id": "img-poll-processing",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.state }}",
"rightValue": "processing"
},
{
"id": "img-poll-generating",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.state }}",
"rightValue": "generating"
}
]
},
"renameOutput": true
}
]
},
"options": {
"fallbackOutput": "extra",
"renameFallbackOutput": "Unknown Status"
}
},
"typeVersion": 3.4
},
{
"id": "9ece6252-e993-493b-9dea-6e4dd721e6b9",
"name": "Upload file",
"type": "n8n-nodes-base.googleDrive",
"position": [
-6080,
400
],
"parameters": {
"name": "={{ $('Input').item.json.id }}.png",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "id",
"value": "11kfsPSUmo3vzh5J3evGxEFa6aRrNPh5R"
}
},
"typeVersion": 3
},
{
"id": "99701b3a-4f09-4071-b787-1643a5353309",
"name": "Download Image",
"type": "n8n-nodes-base.httpRequest",
"position": [
-6208,
400
],
"parameters": {
"url": "={{ $json.data.resultJson.parseJson().resultUrls[0] }}",
"options": {}
},
"typeVersion": 4.4
},
{
"id": "dc6b25d5-23de-4609-b1c6-7f3f83065d75",
"name": "Share file",
"type": "n8n-nodes-base.googleDrive",
"position": [
-5952,
400
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.id }}"
},
"options": {},
"operation": "share",
"permissionsUi": {
"permissionsValues": {
"role": "reader",
"type": "anyone"
}
}
},
"typeVersion": 3
},
{
"id": "a24f13cb-c7af-4452-8c90-28d2d8ba7bdb",
"name": "UpdateSheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-5008,
400
],
"parameters": {
"columns": {
"value": {
"ID": "={{ $('Input').first().json.id }}",
"LAUNCH": "Processing",
"SCRIPT": "={{ JSON.stringify($json) }}",
"SCENE NO": "={{ $json.scene_number }}",
"VIDEO ID": "={{ $('Input').first().json.id }}_{{ $itemIndex }}",
"IMAGE URL": "={{ $('Workflow Configuration3').first().json.download_image }}",
"TOTAL SCENES": "={{ $('Generate Scene Scripts3').first().json.output.scenes.length }}"
},
"schema": [
{
"id": "ID",
"type": "string",
"display": true,
"required": false,
"displayName": "ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "VIDEO ID",
"type": "string",
"display": true,
"required": false,
"displayName": "VIDEO ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "IMAGE URL",
"type": "string",
"display": true,
"required": false,
"displayName": "IMAGE URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "TOTAL SCENES",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "TOTAL SCENES",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "SCENE NO",
"type": "string",
"display": true,
"required": false,
"displayName": "SCENE NO",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "SCRIPT",
"type": "string",
"display": true,
"required": false,
"displayName": "SCRIPT",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "VIDEO VIEW CLIP",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "VIDEO VIEW CLIP",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "VIDEO CLIP LINK",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "VIDEO CLIP LINK",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "LAUNCH",
"type": "string",
"display": true,
"required": false,
"displayName": "LAUNCH",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Error",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Error",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 419137619,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JmhjG7XehIfIqlwhxf5orUlNDxMf_uuaz01_gyMtBBk/edit#gid=419137619",
"cachedResultName": "Video Data"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1XgFKo9N2jIiUNtizbpQXMAIDc6mSOhngW6EnAKdtawc",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1XgFKo9N2jIiUNtizbpQXMAIDc6mSOhngW6EnAKdtawc/edit?usp=drivesdk",
"cachedResultName": "Ads Factory: Tax Relief - Final AI Videos (n8n)"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 4.7,
"waitBetweenTries": 5000
},
{
"id": "ebb29036-8a05-4fce-8bb5-d233b87de2e2",
"name": "UpdateSheet1",
"type": "n8n-nodes-base.googleSheets",
"position": [
-4720,
864
],
"parameters": {
"columns": {
"value": {
"ID": "={{ $('Input').first().json.id }}",
"SCRIPT": "={{ $('Input').item.json.demo_script }}",
"row_number": "={{ $('Input').item.json.row_number }}",
"LAUNCH CREATION": "Processing"
},
"schema": [
{
"id": "ID",
"type": "string",
"display": true,
"required": false,
"displayName": "ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "SCRIPT NAME",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "SCRIPT NAME",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "SCRIPT",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "SCRIPT",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "CHARACTER/SETTING DESCRIPTION",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "CHARACTER/SETTING DESCRIPTION",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ASPECT RATIO",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "ASPECT RATIO",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "VIDEO VIEW LINK",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "VIDEO VIEW LINK",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "VIDEO LINK",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "VIDEO LINK",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "LAUNCH CREATION",
"type": "string",
"display": true,
"required": false,
"displayName": "LAUNCH CREATION",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "number",
"display": true,
"removed": false,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"row_number"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JmhjG7XehIfIqlwhxf5orUlNDxMf_uuaz01_gyMtBBk/edit#gid=0",
"cachedResultName": "Videos"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1XgFKo9N2jIiUNtizbpQXMAIDc6mSOhngW6EnAKdtawc",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1XgFKo9N2jIiUNtizbpQXMAIDc6mSOhngW6EnAKdtawc/edit?usp=drivesdk",
"cachedResultName": "Ads Factory: Tax Relief - Final AI Videos (n8n)"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"executeOnce": true,
"retryOnFail": true,
"typeVersion": 4.7,
"waitBetweenTries": 5000
},
{
"id": "dca509d8-8d78-4be5-aefb-9addf3debc47",
"name": "Get row(s) in sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-7872,
1728
],
"parameters": {
"options": {},
"filtersUI": {
"values": [
{
"lookupValue": "={{ $('Input').item.json.id }}",
"lookupColumn": "ID"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": 419137619,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JmhjG7XehIfIqlwhxf5orUlNDxMf_uuaz01_gyMtBBk/edit#gid=419137619",
"cachedResultName": "Video Data"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1XgFKo9N2jIiUNtizbpQXMAIDc6mSOhngW6EnAKdtawc",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1XgFKo9N2jIiUNtizbpQXMAIDc6mSOhngW6EnAKdtawc/edit?usp=drivesdk",
"cachedResultName": "Ads Factory: Tax Relief - Final AI Videos (n8n)"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"executeOnce": true,
"retryOnFail": true,
"typeVersion": 4.7,
"waitBetweenTries": 5000
},
{
"id": "cdcd3e51-a210-4a4d-8b58-d6a095fc85eb",
"name": "Upload file1",
"type": "n8n-nodes-base.googleDrive",
"position": [
-6784,
1680
],
"parameters": {
"name": "={{ $('videoInput').item.json['VIDEO ID'] }}.mp4",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "id",
"value": "1HlQRqwXfdYEm8zIsxQ0NsEYRAUEaFvMD"
}
},
"retryOnFail": true,
"typeVersion": 3,
"waitBetweenTries": 5000
},
{
"id": "3bda72be-7bf7-425b-8fa0-e262c5452cb1",
"name": "Share file1",
"type": "n8n-nodes-base.googleDrive",
"position": [
-6640,
1680
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.id }}"
},
"options": {},
"operation": "share",
"permissionsUi": {
"permissionsValues": {
"role": "reader",
"type": "anyone"
}
}
},
"retryOnFail": true,
"typeVersion": 3,
"waitBetweenTries": 5000
},
{
"id": "6aee447c-c1f3-418d-9c3b-eb661161f707",
"name": "UpdateSheet2",
"type": "n8n-nodes-base.googleSheets",
"position": [
-6464,
1680
],
"parameters": {
"columns": {
"value": {
"Error": "No Error",
"LAUNCH": "Completed",
"VIDEO ID": "={{ $('videoInput').item.json['VIDEO ID'] }}",
"VIDEO CLIP LINK": "={{ $('Upload file1').item.json.webContentLink }}",
"VIDEO VIEW CLIP": "={{ $('Upload file1').item.json.webViewLink.split(\"?\")[0] }}"
},
"schema": [
{
"id": "ID",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "VIDEO ID",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "VIDEO ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "IMAGE URL",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "IMAGE URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "TOTAL SCENES",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "TOTAL SCENES",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "SCENE NO",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "SCENE NO",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "SCRIPT",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "SCRIPT",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "VIDEO VIEW CLIP",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "VIDEO VIEW CLIP",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "VIDEO CLIP LINK",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "VIDEO CLIP LINK",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "LAUNCH",
"type": "string",
"display": true,
"required": false,
"displayName": "LAUNCH",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Error",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Error",
"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": 419137619,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JmhjG7XehIfIqlwhxf5orUlNDxMf_uuaz01_gyMtBBk/edit#gid=419137619",
"cachedResultName": "Video Data"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1XgFKo9N2jIiUNtizbpQXMAIDc6mSOhngW6EnAKdtawc",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1XgFKo9N2jIiUNtizbpQXMAIDc6mSOhngW6EnAKdtawc/edit?usp=drivesdk",
"cachedResultName": "Ads Factory: Tax Relief - Final AI Videos (n8n)"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 4.7,
"waitBetweenTries": 5000
},
{
"id": "98e90d5c-382b-4017-b8e7-b8a958360bd2",
"name": "Get row(s) for Stitch",
"type": "n8n-nodes-base.googleSheets",
"position": [
-6272,
1680
],
"parameters": {
"options": {},
"filtersUI": {
"values": [
{
"lookupValue": "={{ $('videoInput').item.json.ID }}",
"lookupColumn": "ID"
},
{
"lookupValue": "Completed",
"lookupColumn": "LAUNCH"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": 419137619,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JmhjG7XehIfIqlwhxf5orUlNDxMf_uuaz01_gyMtBBk/edit#gid=419137619",
"cachedResultName": "Video Data"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1XgFKo9N2jIiUNtizbpQXMAIDc6mSOhngW6EnAKdtawc",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1XgFKo9N2jIiUNtizbpQXMAIDc6mSOhngW6EnAKdtawc/edit?usp=drivesdk",
"cachedResultName": "Ads Factory: Tax Relief - Final AI Videos (n8n)"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"executeOnce": true,
"retryOnFail": true,
"typeVersion": 4.7,
"waitBetweenTries": 5000
},
{
"id": "09d31ad8-e2fb-47d9-9bc4-7c7f72346821",
"name": "Sort",
"type": "n8n-nodes-base.sort",
"position": [
-5696,
1600
],
"parameters": {
"options": {},
"sortFieldsUi": {
"sortField": [
{
"fieldName": "SCENE NO"
}
]
}
},
"typeVersion": 1
},
{
"id": "a44712c4-c5b4-4915-a42e-6bbecbf150c7",
"name": "Code in JavaScript",
"type": "n8n-nodes-base.code",
"position": [
-6080,
1680
],
"parameters": {
"jsCode": "const items = $input.all();\nconst totalItems = items.length;\n\n// Assuming TOTAL SCENES is same for all items (usually from sheet row)\nconst totalScenes = Number(items[0].json[\"TOTAL SCENES\"]);\n\nconst isComplete = totalItems >= totalScenes;\n\nfor (const item of items) {\n item.json.isComplete = isComplete;\n}\n\nreturn items;"
},
"typeVersion": 2
},
{
"id": "9e26a0ce-0a75-41d3-92e0-e774afccf9a6",
"name": "If",
"type": "n8n-nodes-base.if",
"position": [
-5872,
1680
],
"parameters": {
"options": {
"ignoreCase": true
},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": false,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "0b05360c-9abf-4e3d-ba2a-f3ae3627932b",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.isComplete }}",
"rightValue": true
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.3
},
{
"id": "81261d3e-c2d1-44c4-a396-54c225b9a9a2",
"name": "download-video8",
"type": "n8n-nodes-base.httpRequest",
"position": [
-5104,
1600
],
"parameters": {
"url": "={{ $json.video.url }}",
"options": {}
},
"retryOnFail": true,
"typeVersion": 4.3,
"waitBetweenTries": 5000
},
{
"id": "65fc1067-2502-460a-aad9-0f4f4afb930d",
"name": "Upload file2",
"type": "n8n-nodes-base.googleDrive",
"position": [
-4864,
1600
],
"parameters": {
"name": "={{ $('videoInput').item.json.ID }}.mp4",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "id",
"value": "1HlQRqwXfdYEm8zIsxQ0NsEYRAUEaFvMD"
}
},
"retryOnFail": true,
"typeVersion": 3,
"waitBetweenTries": 5000
},
{
"id": "6ad7af35-7562-448c-a703-80194c105b5e",
"name": "Share file2",
"type": "n8n-nodes-base.googleDrive",
"position": [
-4720,
1600
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.id }}"
},
"options": {},
"operation": "share",
"permissionsUi": {
"permissionsValues": {
"role": "reader",
"type": "anyone"
}
}
},
"retryOnFail": true,
"typeVersion": 3,
"waitBetweenTries": 5000
},
{
"id": "fdcb362c-2d19-40b6-9fb4-7eb3368668e0",
"name": "UpdateSheet3",
"type": "n8n-nodes-base.googleSheets",
"position": [
-4544,
1600
],
"parameters": {
"columns": {
"value": {
"ID": "={{ $('videoInput').first().json.ID }}",
"VIDEO LINK": "={{ $('Upload file2').item.json.webContentLink }}",
"LAUNCH CREATION": "Completed",
"VIDEO VIEW LINK": "={{ $('Upload file2').item.json.webViewLink.split(\"?\")[0] }}"
},
"schema": [
{
"id": "ID",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "SCRIPT NAME",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "SCRIPT NAME",
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.
googleSheetsOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This n8n workflow turns a script and character/setting description from Google Sheets into a complete stitched UGC-style video ad, fully automated from intake to final delivery.
Source: https://n8n.io/workflows/14316/ — 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 is designed for: Content creators and marketers E-commerce and product-based businesses Agencies producing social media visuals and videos Automation builders looking for AI-powered crea
This workflow automates the creation, rendering, approval, and posting of TikTok-style POV (Point of View) videos to Instagram, with cross-posting to Facebook and YouTube. It eliminates manual video p
Viral Video Agent. Uses lmChatOpenRouter, httpRequest, googleSheets, googleDrive. Scheduled trigger; 44 nodes.
Content marketers and SEO specialists who need to generate multiple SEO-optimized articles targeting keyword variations. Ideal for affiliate sites, niche blogs, or service-based businesses creating lo
This advanced automation template allows marketing teams, content creators, and branding specialists to automatically generate and publish high-quality, visually captivating branded short videos acros