AutomationFlowsData & Sheets › Google Sheets → HeyGen AI Videos

Google Sheets → HeyGen AI Videos

Original n8n title: Convert Google Sheets Scripts Into Heygen AI Videos

ByPanth1823 @panth1823 on n8n.io

Automate HeyGen Video Generation from Google Sheets Effortlessly convert text scripts in Google Sheets into AI-generated videos using HeyGen.

Event trigger★★★★☆ complexity15 nodesGoogle Sheets TriggerHTTP RequestGoogle Sheets
Data & Sheets Trigger: Event Nodes: 15 Complexity: ★★★★☆ Added:

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

This workflow follows the Google Sheets → Googlesheetstrigger 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
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "dce15696-5aeb-459c-a56d-c65cb4b7fe76",
      "name": "Main Sticky",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2320,
        16
      ],
      "parameters": {
        "color": 2,
        "width": 500,
        "height": 600,
        "content": "## Automate HeyGen Video Generation from Google Sheets\nEffortlessly convert text scripts in Google Sheets into AI-generated videos using HeyGen.\n\n\n### How it works\n1. Monitor Google Sheets for new row updates.\n2. Sanitize script text to prevent JSON errors.\n3. Send text to HeyGen API for processing.\n4. Poll for video completion status.\n5. Update Google Sheets with the final video URL.\n\n\n### Setup\n1. Connect your Google Sheets account.\n2. Provide your HeyGen API Key in the HTTP Request node.\n3. Configure Document ID and Sheet Name in Google nodes.\n4. Adjust the avatar and voice IDs as needed.\n\n\n### Customization\nConsolidate user-specific values (API Keys, IDs) in a Set node at the workflow start for easy configuration."
      },
      "typeVersion": 1
    },
    {
      "id": "bc6f1693-f349-435e-915a-35f402d47a72",
      "name": "Google Sheets Trigger",
      "type": "n8n-nodes-base.googleSheetsTrigger",
      "position": [
        -1696,
        160
      ],
      "parameters": {
        "event": "rowUpdate",
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_RESOURCE_ID_HERE"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_RESOURCE_ID_HERE"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "2dc1d0e8-1ab6-4879-90ad-3a6979b929b5",
      "name": "Has Script?",
      "type": "n8n-nodes-base.if",
      "position": [
        -1472,
        160
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.Script }}",
              "operation": "isNotEmpty"
            },
            {
              "value1": "={{ $json.Status }}",
              "value2": "Completed",
              "operation": "notEqual"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "c046b6a7-18ce-4d14-ad89-6e1b44e46b54",
      "name": "Process One at a Time",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -1264,
        144
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "a4fe5b87-f7c3-42e6-940b-87fbfb1295d1",
      "name": "Sanitize Script",
      "type": "n8n-nodes-base.code",
      "position": [
        -1024,
        160
      ],
      "parameters": {
        "jsCode": "// Sanitize the Script field to make it safe for JSON injection\n// Removes newlines, carriage returns, tabs, and escapes quotes\nconst item = $input.item.json;\n\nconst rawScript = item.Script || '';\n\nconst cleanScript = rawScript\n  .replace(/\\r\\n/g, ' ')  // Windows line endings\n  .replace(/\\n/g, ' ')    // Unix line endings\n  .replace(/\\r/g, ' ')    // Old Mac line endings\n  .replace(/\\t/g, ' ')    // Tabs\n  .replace(/\\\\/g, '\\\\\\\\') // Escape backslashes first\n  .replace(/\"/g, '\\\\\"')   // Escape double quotes\n  .replace(/\\s+/g, ' ')   // Collapse multiple spaces\n  .trim();\n\nreturn [{\n  json: {\n    ...item,\n    CleanScript: cleanScript\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "eeabc558-954a-4f55-bfa3-a3793a9a1e7f",
      "name": "Generate Video",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -736,
        160
      ],
      "parameters": {
        "url": "YOUR_API_ENDPOINT_HERE",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"video_inputs\": [\n    {\n      \"character\": {\n        \"type\": \"avatar\",\n        \"avatar_id\": \"4185302635fa4de29a99ad8ca17475bc\"\n      },\n      \"voice\": {\n        \"type\": \"text\",\n        \"input_text\": \"{{ $json.CleanScript }}\",\n        \"voice_id\": \"d7f0f1713ccd458790d6cffb41ad27e2\"\n      }\n    }\n  ],\n  \"dimension\": {\n    \"width\": 720,\n    \"height\": 1280\n  }\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Api-Key",
              "value": "sk_V2_hgu_khdB00SgqzE_dDenmzsc8IVkvjmZh4pkrngPLd6Alx72"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "825db574-df10-42e7-9c5e-b92c9ffb53e3",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        -512,
        160
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "51d6ebcf-1b85-4752-a61f-a343c5d0e08c",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "=",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "3a1d1e70-1ecb-444e-a8f9-7d06661901e1",
      "name": "Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        -288,
        144
      ],
      "parameters": {
        "amount": 60
      },
      "typeVersion": 1.1
    },
    {
      "id": "bfef54cd-103f-4e31-b62e-40ac6438db8e",
      "name": "Video Status",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -64,
        144
      ],
      "parameters": {
        "url": "YOUR_API_ENDPOINT_HERE",
        "options": {},
        "sendQuery": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "video_id",
              "value": "={{ $('Generate Video').item.json.data.video_id }}"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "accept",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "945b5fee-2151-48f9-a16e-dc2fe46f3a9e",
      "name": "Is Complete?1",
      "type": "n8n-nodes-base.if",
      "position": [
        240,
        144
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.data.status }}",
              "value2": "completed"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b02f439c-71cf-4718-a04e-795cbdc25592",
      "name": "Update Sheet with Video1",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        480,
        128
      ],
      "parameters": {
        "columns": {
          "value": {
            "Row_ID": "={{ $('Process One at a Time').item.json.Row_ID }}",
            "Status": "Completed",
            "Video_URL": "={{ $json.data.video_url }}",
            "row_number": 0,
            "Completed_At": "={{ $now.toISO() }}"
          },
          "schema": [
            {
              "id": "Row_ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Row_ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Script",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Script",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Video_URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Video_URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Completed_At",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Completed_At",
              "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_ID"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_RESOURCE_ID_HERE"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_RESOURCE_ID_HERE"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "11b872c3-8ae5-465b-905a-9baccafa3c26",
      "name": "Wait Before Retry1",
      "type": "n8n-nodes-base.wait",
      "position": [
        480,
        320
      ],
      "parameters": {
        "amount": 60
      },
      "typeVersion": 1.1
    },
    {
      "id": "ac9ac3b8-3833-4b0d-a1b4-6c3b4f02f394",
      "name": "Section 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1760,
        16
      ],
      "parameters": {
        "color": 7,
        "width": 892,
        "height": 312,
        "content": "## 1. Trigger & Data Processing\nWatches Google Sheets for pending scripts and cleans the text."
      },
      "typeVersion": 1
    },
    {
      "id": "04080163-8397-4d96-8818-99d90eb157ba",
      "name": "Section 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -800,
        16
      ],
      "parameters": {
        "color": 7,
        "width": 892,
        "height": 312,
        "content": "## 2. API Communication\nHandles HeyGen requests and polls for video generation status."
      },
      "typeVersion": 1
    },
    {
      "id": "89fc0f7f-d86d-477f-8745-e14cec4de985",
      "name": "Section 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        176,
        16
      ],
      "parameters": {
        "color": 7,
        "width": 488,
        "height": 520,
        "content": "## 3. Sheet Update\nWrites the generated video URL back to the spreadsheet."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait": {
      "main": [
        [
          {
            "node": "Video Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Script?": {
      "main": [
        [
          {
            "node": "Process One at a Time",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Video Status": {
      "main": [
        [
          {
            "node": "Is Complete?1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Complete?1": {
      "main": [
        [
          {
            "node": "Update Sheet with Video1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait Before Retry1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Video": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sanitize Script": {
      "main": [
        [
          {
            "node": "Generate Video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait Before Retry1": {
      "main": [
        [
          {
            "node": "Video Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets Trigger": {
      "main": [
        [
          {
            "node": "Has Script?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process One at a Time": {
      "main": [
        [],
        [
          {
            "node": "Sanitize Script",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Sheet with Video1": {
      "main": [
        [
          {
            "node": "Process One at a Time",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

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

About this workflow

Automate HeyGen Video Generation from Google Sheets Effortlessly convert text scripts in Google Sheets into AI-generated videos using HeyGen.

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

More Data & Sheets workflows → · Browse all categories →

Related workflows

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

Data & Sheets

This powerful no-code workflow automates plagiarism detection using Plagiarism Checker AI Powered. Users submit text through Google Sheets. The system checks for duplication using the API, sends a det

Google Sheets Trigger, HTTP Request, Email Send +1
Data & Sheets

This n8n workflow automates outbound phone calls to new leads using VAPI, with built-in timezone detection to ensure you're only calling during business hours.

HTTP Request, Google Sheets Trigger, Google Sheets
Data & Sheets

Julia. Uses googleSheetsTrigger, googleSheets, httpRequest. Event-driven trigger; 16 nodes.

Google Sheets Trigger, Google Sheets, HTTP Request
Data & Sheets

This n8n template automatically enriches IP addresses with geolocation data and performs HTTP port scanning when new IPs are added to a Google Sheets document. Perfect for network monitoring, security

Google Sheets Trigger, Google Sheets, HTTP Request
Data & Sheets

This n8n template demonstrates how to automatically validate email addresses from your Google Sheets using a reliable email verification API. Perfect for cleaning contact lists, validating leads, and

Google Sheets Trigger, Google Sheets, HTTP Request