AutomationFlowsAI & RAG › Generate AI Video Ads with Google Veo 3 and Airtable

Generate AI Video Ads with Google Veo 3 and Airtable

Original n8n title: Automate AI Video Ad Generation with Google Veo 3, Gemini, and Airtable

ByIntuz @intuz on n8n.io

Using Google's state-of-the-art Veo 3 model, this workflow manages the entire creative process from concept to a final, downloadable video file. E-commerce Brands & Marketers Advertising Agencies Social Media Content Creators Product Managers Submit a Creative Brief: The…

Event trigger★★★★☆ complexityAI-powered16 nodesAirtableHTTP RequestGoogle GeminiForm TriggerForm
AI & RAG Trigger: Event Nodes: 16 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Airtable → 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": "O7BiL9gvzMRGnzco",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Development Done - Product Ads via Veo3",
  "tags": [
    {
      "id": "m1paRrANi4GrQXxX",
      "name": "AI Internal",
      "createdAt": "2025-09-18T04:05:25.667Z",
      "updatedAt": "2025-09-18T04:05:25.667Z"
    }
  ],
  "nodes": [
    {
      "id": "dc93f801-d671-49a1-80a1-a19f3c3d4e8d",
      "name": "Create a record",
      "type": "n8n-nodes-base.airtable",
      "position": [
        -48,
        -64
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "Your_Airtable_Base_ID",
          "cachedResultUrl": "https://airtable.com/Your_Airtable_Base_ID",
          "cachedResultName": "Dynamic Video Content"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "Your_Airtable_Table_ID",
          "cachedResultUrl": "https://airtable.com/Your_Airtable_Base_ID/Your_Airtable_Table_ID",
          "cachedResultName": "Product Ads"
        },
        "columns": {
          "value": {
            "Status": "Pending",
            "Image Prompt": "={{ $json[\"Idea Prompt\"] }}"
          },
          "schema": [
            {
              "id": "Id",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "Id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Image Prompt",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Image Prompt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Image",
              "type": "array",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Image",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Video",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Video",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "options",
              "display": true,
              "options": [
                {
                  "name": "Pending",
                  "value": "Pending"
                },
                {
                  "name": "Done",
                  "value": "Done"
                }
              ],
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "create"
      },
      "credentials": {
        "airtableTokenApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "2cffa033-d677-4c1a-8bbd-92f10814e14d",
      "name": "Converting Image file for Storing",
      "type": "n8n-nodes-base.code",
      "position": [
        400,
        -64
      ],
      "parameters": {
        "jsCode": "// Get the first binary key dynamically\nconst binaryKey = Object.keys($input.item.binary || {})[0];\nif (!binaryKey) {\n  throw new Error(\"No binary data found on input item.\");\n}\n\nconst binary = $input.item.binary[binaryKey];\n\n// Convert binary to base64\nconst base64File = binary.data.toString('base64');\n\n// Build JSON payload for Airtable\nreturn [\n  {\n    json: {\n      contentType: binary.mimeType || \"image/jpeg\",\n      file: base64File,\n      filename: binary.fileName || \"upload.jpg\"\n    },\n    pairedItem: { item: 0 }   // \ud83d\udd11 keeps mapping to original input\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "22250c9d-136c-43cd-be88-8c3423c1c642",
      "name": "Uploading Image in Airtable",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        624,
        -64
      ],
      "parameters": {
        "url": "=https://content.airtable.com/v0/Your_Airtable_Base_ID/{{ $('Create a record').item.json.id }}/[Your_Column_Name]/uploadAttachment",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "contentType",
              "value": "={{$json[\"contentType\"]}}"
            },
            {
              "name": "file",
              "value": "={{$json[\"file\"]}}"
            },
            {
              "name": "filename",
              "value": "={{$json[\"filename\"]}}"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_TOKEN_HERE"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "3007c7d8-a294-4146-b610-ba10aa344881",
      "name": "Get a record",
      "type": "n8n-nodes-base.airtable",
      "position": [
        848,
        -64
      ],
      "parameters": {
        "id": "={{ $json.id }}",
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "Your_Airtable_Base_ID",
          "cachedResultUrl": "https://airtable.com/Your_Airtable_Base_ID",
          "cachedResultName": "Dynamic Video Content"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "Your_Airtable_Table_ID",
          "cachedResultUrl": "https://airtable.com/Your_Airtable_Base_ID/Your_Airtable_Table_ID",
          "cachedResultName": "Product Ads"
        },
        "options": {}
      },
      "credentials": {
        "airtableTokenApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "04a074e2-dd05-4699-b30f-cf1f004170e5",
      "name": "Analyze image",
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "position": [
        1056,
        -64
      ],
      "parameters": {
        "text": "=You are an expert AI creative analyst. Your purpose is to analyze an input image together with the user\u2019s creative request and produce a structured creative brief. Always treat the user\u2019s request as the guiding vision, and reinterpret the image so that the final video concept fulfills that request. Your output must be only the plain text report as described below. Do not include any conversational filler or explanatory text.\n\nUSER REQUEST\n{{ $json[\"Image Prompt\"] }}\n\nIMAGE ANALYSIS\n\nDescription\nWrite a comprehensive, single-paragraph description of the image as it visually appears. Then explicitly describe how this image can be creatively reimagined or transformed to align with the user\u2019s request.\n\nStyle Analysis\n\nCore Subject: Identify the main focus of the image and explain how it connects to the user\u2019s request.\n\nSetting: Describe the environment/background and how it could be reinterpreted in the requested concept.\n\nMedium: Specify the artistic medium (e.g., product photography, 3D render) and suggest how the medium might shift in the video.\n\nLighting: Describe the current light and suggest adjustments to match the requested mood.\n\nMood: Define both the existing atmosphere of the image and the intended emotional tone per the user\u2019s request.\n\nComposition: Describe the current framing/camera angle and how it might evolve in the video.\n\nColor Palette: List the dominant colors, then suggest enhancements or transformations to match the user\u2019s request.\n\nText Overlay\nList and describe each distinct piece of text found in the image. If there is no text, simply write \"None.\"\n\nFor each text element, provide:\n- Text\n- Font\n- Effect\n- Color\n- Placement\n\nCREATIVE VIDEO BRIEF\n\nTranslate the user request and image analysis into a structured video brief suitable for Veo 3 generation:\n\nVideo Style: Describe the final style/genre of the requested video.\n\nTarget Emotion: Define the main emotional impact the video should deliver.\n\nMotion Guidance: Suggest dynamic camera motions, transitions, or visual effects that bring the user\u2019s request to life.\n\nAudio/Music Direction: Suggest music/sound design that fits both the brand identity in the image and the requested theme.\n\nSuggested Script Elements: Provide a draft outline of possible voiceover or on-screen text. Ensure this ties the image (e.g., Pepsi product) with the user\u2019s creative request (e.g., exploding into a disco party).\n",
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "models/gemini-2.5-flash",
          "cachedResultName": "models/gemini-2.5-flash"
        },
        "options": {},
        "resource": "image",
        "imageUrls": "={{ $json.Image[0].url }}",
        "operation": "analyze"
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "e0533567-2b84-414d-b841-97f40163b08d",
      "name": "Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        1744,
        -64
      ],
      "parameters": {
        "unit": "minutes",
        "amount": 1
      },
      "typeVersion": 1.1
    },
    {
      "id": "6e0d258e-1e7e-453b-8780-47a959243ff6",
      "name": "Update record",
      "type": "n8n-nodes-base.airtable",
      "position": [
        1968,
        -64
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "Your_Airtable_Base_ID",
          "cachedResultUrl": "https://airtable.com/Your_Airtable_Base_ID",
          "cachedResultName": "Dynamic Video Content"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "Your_Airtable_Table_ID",
          "cachedResultUrl": "https://airtable.com/Your_Airtable_Base_ID/Your_Airtable_Table_ID",
          "cachedResultName": "Product Ads"
        },
        "columns": {
          "value": {
            "Id": "={{ $('Get a record').item.json.Id }}",
            "Status": "Done"
          },
          "schema": [
            {
              "id": "id",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "id",
              "defaultMatch": true
            },
            {
              "id": "Id",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "Id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Image Prompt",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "Image Prompt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Image",
              "type": "array",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "Image",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "options",
              "display": true,
              "options": [
                {
                  "name": "Pending",
                  "value": "Pending"
                },
                {
                  "name": "Done",
                  "value": "Done"
                }
              ],
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Video",
              "type": "array",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "Video",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update"
      },
      "credentials": {
        "airtableTokenApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "3ad82fa6-e313-46e3-bfe7-c3505f8ff8f7",
      "name": "Generate Video Veo 3",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1520,
        -64
      ],
      "parameters": {
        "url": "https://us-central1-aiplatform.googleapis.com/v1/projects/[Project ID]/locations/[Location]/publishers/google/models/veo-3.0-fast-generate-001:predictLongRunning",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ $json.veoRequestBody }}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_TOKEN_HERE"
            }
          ]
        },
        "nodeCredentialType": "googleOAuth2Api"
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        },
        "googleOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "ee7a1540-5467-4461-b73c-dc4eaeba8812",
      "name": "Get the Video",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2192,
        -64
      ],
      "parameters": {
        "url": "https://us-central1-aiplatform.googleapis.com/v1/projects/[Project ID]/locations/[Location]/publishers/google/models/veo-3.0-generate-001:fetchPredictOperation",
        "method": "POST",
        "options": {
          "response": {
            "response": {}
          }
        },
        "sendBody": true,
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "operationName",
              "value": "={{ $('Generate Video Veo 3').item.json.name }}"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_TOKEN_HERE"
            }
          ]
        },
        "nodeCredentialType": "googleOAuth2Api"
      },
      "credentials": {
        "googleOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "42d12f7e-34f5-474b-a136-5a6485763bf6",
      "name": "Downloadable Video",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        2416,
        -64
      ],
      "parameters": {
        "options": {},
        "operation": "toBinary",
        "sourceProperty": "response.videos[0].bytesBase64Encoded"
      },
      "typeVersion": 1.1
    },
    {
      "id": "097d5ffc-0481-4261-9d68-355ab2ec9266",
      "name": "Parse Request",
      "type": "n8n-nodes-base.code",
      "position": [
        1296,
        -64
      ],
      "parameters": {
        "jsCode": "// Get the generated prompt text from the previous node\nconst promptText = $json.content.parts[0].text;\n\n// Build the complete JSON body for the VEO API\nconst requestBody = {\n  \"endpoint\": \"projects/personalised-mail/locations/us-central1/publishers/google/models/veo-3.0-generate-001\",\n  \"instances\": [\n    {\n      \"prompt\": promptText\n    }\n  ],\n  \"parameters\": {\n    \"aspectRatio\": \"16:9\",\n    \"sampleCount\": 1,\n    \"durationSeconds\": \"8\",\n    \"personGeneration\": \"allow_all\",\n    \"addWatermark\": true,\n    \"includeRaiReason\": true,\n    \"generateAudio\": true,\n    \"resolution\": \"720p\"\n  }\n};\n\n// Return the final object inside a wrapper\nreturn [\n  {\n    json: {\n      \"veoRequestBody\": requestBody // <-- Wrapped here\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "f3054ab6-92de-415c-9f72-24feacebb207",
      "name": "Prompt your Idea",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -272,
        -64
      ],
      "parameters": {
        "options": {},
        "formTitle": "Upload Your File",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Idea Prompt",
              "requiredField": true
            }
          ]
        },
        "formDescription": "Please give the prompt !"
      },
      "typeVersion": 2.2
    },
    {
      "id": "2b288e59-f675-4519-8c74-9014e8ce6479",
      "name": "Upload Image",
      "type": "n8n-nodes-base.form",
      "position": [
        176,
        -64
      ],
      "parameters": {
        "options": {},
        "formFields": {
          "values": [
            {
              "fieldType": "file",
              "fieldLabel": "Image"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "89df8bc5-c051-4c14-9ea3-7f214bdbf1d9",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        128,
        -336
      ],
      "parameters": {
        "color": 5,
        "width": 528,
        "height": 192,
        "content": "## Airtable Configuration\n* **Airtable Credentials**: In the \"Create a record\", \"Get a record\", and \"Update record\" nodes, you must select your own Airtable credentials.\n* **Base and Table IDs**: Update the Base ID and Table ID in all four Airtable-related nodes to match your own setup: \"Create a record\", \"Uploading Image in Airtable\" (in the URL), \"Get a record\", and \"Update record\"."
      },
      "typeVersion": 1
    },
    {
      "id": "b4c1f237-6548-44d5-b232-247ac05ee4a8",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1728,
        -368
      ],
      "parameters": {
        "color": 4,
        "width": 544,
        "height": 240,
        "content": "## Google AI Configuration\n* **Gemini Node** (\"Analyze image\"): Select your Google AI (Gemini) API credentials.\n**Veo Nodes (\"Parse Request\" & HTTP Requests):** \n* **Project ID**: In the URLs, replace with your Google Cloud Project ID.\n* **Credentials**: In both HTTP request nodes (\"Generate Video Veo 3\" & \"Get the Video\"), select your Google OAuth2 credentials.\n* **API Info**: For help with endpoints, see the [Google Cloud Vertex AI Studio](https://www.google.com/search?q=https://console.cloud.google.com/vertex-ai/studio/media/generate)"
      },
      "typeVersion": 1
    },
    {
      "id": "e0741edb-ab0f-445e-a415-aff8e58057f3",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1216,
        -352
      ],
      "parameters": {
        "color": 6,
        "width": 304,
        "height": 192,
        "content": "## Customization\n**Video Generation Parameters**: In the \"Parse Request\" node, you can modify the JavaScript code to change video settings like *aspectRatio*, *durationSeconds*, and *resolution*."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "88471e4e-1558-4a15-9060-712afdb19c0d",
  "connections": {
    "Wait": {
      "main": [
        [
          {
            "node": "Update record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get a record": {
      "main": [
        [
          {
            "node": "Analyze image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload Image": {
      "main": [
        [
          {
            "node": "Converting Image file for Storing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analyze image": {
      "main": [
        [
          {
            "node": "Parse Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get the Video": {
      "main": [
        [
          {
            "node": "Downloadable Video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Request": {
      "main": [
        [
          {
            "node": "Generate Video Veo 3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update record": {
      "main": [
        [
          {
            "node": "Get the Video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create a record": {
      "main": [
        [
          {
            "node": "Upload Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prompt your Idea": {
      "main": [
        [
          {
            "node": "Create a record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Downloadable Video": {
      "main": [
        []
      ]
    },
    "Generate Video Veo 3": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Uploading Image in Airtable": {
      "main": [
        [
          {
            "node": "Get a record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Converting Image file for Storing": {
      "main": [
        [
          {
            "node": "Uploading Image in Airtable",
            "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

Using Google's state-of-the-art Veo 3 model, this workflow manages the entire creative process from concept to a final, downloadable video file. E-commerce Brands & Marketers Advertising Agencies Social Media Content Creators Product Managers Submit a Creative Brief: The…

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

More AI & RAG workflows → · Browse all categories →

Related workflows

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

AI & RAG

This workflow contains community nodes that are only compatible with the self-hosted version of n8n.

Airtable, OpenAI, Form Trigger +3
AI & RAG

This workflow empowers marketing teams, agencies and solopreneurs to instantly generate on-brand, platform-optimized social media ads — without designers or complex setup. Running performance marketin

Form Trigger, HTTP Request, Slack +1
AI & RAG

[](https://drive.google.com/file/d/1Cl0KwgRgcuBPVdGgL-nqAcheyvfVXttD/view) Click on the image to see the Example output in google drive

HTTP Request, Stop And Error, OpenAI +3
AI & RAG

How it works • Automates multi-platform social media posting (Instagram, YouTube, TikTok, etc.) using AI-generated content • Integrates Airtable, n8n, and Blotato for full content scheduling and publi

HTTP Request, Airtable, OpenAI +1
AI & RAG

Understand your customers before you build for them. This workflow, Market Segmentation: Buyer Persona Pain Point Report, automates the grueling process of primary market research. By scraping real-wo

Form Trigger, Google Gemini, N8N Nodes Olostep +3