This workflow corresponds to n8n.io template #14266 — we link there as the canonical source.
This workflow follows the Google Sheets → HTTP Request 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 →
{
"id": "zH2888HsyPtX4Bdi56Bie",
"name": "Heygen Viral UGC generation",
"tags": [],
"nodes": [
{
"id": "0d005363-17ba-43e8-8046-68845d1be070",
"name": "Code: Check HeyGen Status",
"type": "n8n-nodes-base.code",
"position": [
416,
176
],
"parameters": {
"jsCode": "const pollResponse = $('HTTP: Poll HeyGen Status').first().json;\nconst state = $('Wait: HeyGen Processing').first().json || $('Code: Extract HeyGen Video ID').first().json;\n\nconst statusRaw = pollResponse.data?.status || pollResponse.status || 'unknown';\nconst status = String(statusRaw).toLowerCase();\nconst pollCount = (state.pollCount || 0) + 1;\nconst maxPolls = state.maxPolls || 20;\nconst pollIntervalSec = state.pollIntervalSec || 30;\n\nif (status === 'completed') {\n return [{\n json: {\n ...state,\n pollCount,\n heygenStatus: status,\n heygenRoute: 'completed'\n }\n }];\n}\n\nif (status === 'failed' || status === 'error' || status === 'canceled' || status === 'cancelled') {\n return [{\n json: {\n ...state,\n pollCount,\n heygenStatus: status,\n failStatus: 'Failed',\n failReason: `HeyGen status: ${status}`,\n heygenRoute: 'failed'\n }\n }];\n}\n\nif (pollCount >= maxPolls) {\n return [{\n json: {\n ...state,\n pollCount,\n heygenStatus: status,\n failStatus: 'Timed Out',\n failReason: `Timed out after ${pollCount} polls (~${pollCount * pollIntervalSec}s)`,\n heygenRoute: 'failed'\n }\n }];\n}\n\nreturn [{\n json: {\n ...state,\n pollCount,\n heygenStatus: status,\n heygenRoute: 'retry'\n }\n}];"
},
"typeVersion": 2
},
{
"id": "0912ba07-81f8-47f7-9875-9d9b9adb056c",
"name": "Google Sheets: Log Failure",
"type": "n8n-nodes-base.googleSheets",
"position": [
-704,
1072
],
"parameters": {
"columns": {
"value": {
"Status": "={{ $json.failReason || $json.failStatus }}",
"row_number": "={{ $json.row_number }}"
},
"schema": [
{
"id": "Date",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Section Title",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Section Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Script Text",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Script Text",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "HeyGen Video ID",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "HeyGen Video ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Raw Video URL",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Raw Video URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Final Video URL",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Final Video URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Status",
"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": 2075799952,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4/edit#gid=2075799952",
"cachedResultName": "Production Logs"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4/edit?usp=drivesdk",
"cachedResultName": "AI Avatar - PinkMatcha"
}
},
"typeVersion": 4.4
},
{
"id": "04668811-7ae7-4fa2-999c-35fa8bb58f87",
"name": "Code: Calculate Content Index",
"type": "n8n-nodes-base.code",
"position": [
-528,
-528
],
"parameters": {
"jsCode": "// Get day of year (1-365)\nconst now = new Date();\nconst start = new Date(now.getFullYear(), 0, 0);\nconst diff = now - start;\nconst oneDay = 1000 * 60 * 60 * 24;\nconst dayOfYear = Math.floor(diff / oneDay);\n\n// Will use modulo with total workbook sections count in next node\nreturn [{\n json: {\n dayOfYear: dayOfYear,\n date: now.toISOString().split('T')[0]\n }\n}];"
},
"typeVersion": 2
},
{
"id": "0387f5dd-c55f-4118-a9e5-3d4cc7e72ad1",
"name": "Google Sheets: Get Workbook Content",
"type": "n8n-nodes-base.googleSheets",
"position": [
-304,
-528
],
"parameters": {
"options": {},
"filtersUI": {
"values": [
{
"lookupValue": "Idea",
"lookupColumn": "Status"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4/edit#gid=0",
"cachedResultName": "Workbook Content"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4/edit?usp=drivesdk",
"cachedResultName": "AI Avatar - PinkMatcha"
}
},
"typeVersion": 4.4
},
{
"id": "6005b492-ca52-4646-a64f-9f0d5bfa50c1",
"name": "Code: Select Today's Section",
"type": "n8n-nodes-base.code",
"position": [
-80,
-528
],
"parameters": {
"jsCode": "// Get day of year from earlier node\nconst dayOfYear = $('Code: Calculate Content Index').first().json.dayOfYear;\nconst date = $('Code: Calculate Content Index').first().json.date;\n\n// Get all workbook sections from Google Sheets\nconst sections = $('Google Sheets: Get Workbook Content').all();\nconst totalSections = sections.length;\n\nif (totalSections === 0) {\n throw new Error('Workbook Content is empty. Add at least one section before running the workflow.');\n}\n\n// Calculate which section to use today (day 1 should map to index 0)\nconst sectionIndex = (dayOfYear - 1) % totalSections;\nconst selectedSection = sections[sectionIndex].json;\n\nreturn [{\n json: {\n date: date,\n dayOfYear: dayOfYear,\n sectionIndex: sectionIndex,\n totalSections: totalSections,\n rowId: selectedSection.row_id || selectedSection.row_number,\n sectionTitle: selectedSection.section_title,\n workbookContent: selectedSection.workbook_content,\n keyMessage: selectedSection.key_message\n }\n}];"
},
"typeVersion": 2
},
{
"id": "6e44dd92-3fe6-4fd4-9d85-68989046f858",
"name": "Code: Select Random Avatar & Combine Data",
"type": "n8n-nodes-base.code",
"position": [
128,
-528
],
"parameters": {
"jsCode": "// Get section data from earlier\nconst sectionData = $('Code: Select Today\\'s Section').first().json;\n\n// Avatar IDs list\nconst avatarIds = [\n 'f95484e160dd46d49bd3eff27a70efa0',\n 'ecc28e92ccda43039065e010f6b745e7',\n 'bbb7020a766f429e811c1b23fcecf987',\n '7fe0025cb65741bcb4de30c5334e3e1e',\n '7ca05b019f4641628f8ca7b2b28dd22c',\n '67f62143cfb64b70a09f5e493dc9986b',\n '65ff242eb2834888a0a25ddaf0d3fdd8',\n '59ae496933a54670885354e0147e11f4',\n '4e8149cc6be54a84b40b79a751d0c06e',\n '38e03f446adb44ada5f510bb9809fdbf',\n '2f02a0c1fa0b4595b94a9a1a075e73ab',\n '29b98540e4974d43807d4ce6ee3d68cf',\n '210d27cf1f8e428dbd01410a05ea4dd2',\n '1c8b64b6925340f597cc6521d1c7abfd'\n];\n\n// Select random avatar for background variation\nconst randomIndex = Math.floor(Math.random() * avatarIds.length);\nconst selectedAvatarId = avatarIds[randomIndex];\n\nreturn [{\n json: {\n date: sectionData.date,\n rowId: sectionData.rowId,\n sectionTitle: sectionData.sectionTitle,\n workbookContent: sectionData.workbookContent,\n keyMessage: sectionData.keyMessage,\n avatarId: selectedAvatarId,\n avatarIndex: randomIndex\n }\n}];"
},
"typeVersion": 2
},
{
"id": "a9016ce7-dc0d-48a4-9213-620bc46ebe9f",
"name": "Code: Parse AI Response",
"type": "n8n-nodes-base.code",
"position": [
-416,
-176
],
"parameters": {
"jsCode": "// Get the response from the generator node\nconst response = $('Generate Script').first().json;\n\n// Recursive function to find the JSON string containing \"script\"\nfunction findJsonRecursive(obj, depth = 0) {\n if (depth > 5) return null;\n if (obj === null || typeof obj !== 'object') return null;\n for (const key of Object.keys(obj)) {\n const val = obj[key];\n if (typeof val === 'string') {\n const trimmed = val.trim();\n if (trimmed.includes('\"script\"') || trimmed.indexOf(\"'script'\") > -1) {\n return trimmed;\n }\n }\n if (typeof val === 'object') {\n const result = findJsonRecursive(val, depth + 1);\n if (result) return result;\n }\n }\n return null;\n}\n\nlet content = response.message?.content || response.choices?.[0]?.message?.content;\nif (typeof content !== 'string') content = null;\n\nif (!content && Array.isArray(response.content) && response.content[0]?.text) {\n content = response.content[0].text;\n}\n\nif (!content) {\n content = findJsonRecursive(response);\n}\n\nif (!content && response.script) {\n content = JSON.stringify(response);\n}\n\nif (!content) {\n throw new Error('Could not find any string containing \"script\" in the response object. Please check the Input JSON. Structure: ' + JSON.stringify(response));\n}\n\nlet parsed;\ntry {\n try {\n parsed = JSON.parse(content);\n } catch (e) {\n const jsonMatch = content.match(/\\{[^{}]*\"script\"[^{}]*\\}/) || content.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n parsed = JSON.parse(jsonMatch[0]);\n } else {\n throw e;\n }\n }\n} catch (e) {\n throw new Error('Found content string but failed to parse JSON: ' + e.message + ' | Content: ' + content.substring(0, 100));\n}\n\nif (!parsed || !parsed.script) {\n if (parsed && typeof parsed === 'object' && !parsed.script) {\n throw new Error('Parsed JSON is missing \"script\" property. Result: ' + JSON.stringify(parsed));\n }\n}\n\nconst combinedData = $('Code: Select Random Avatar & Combine Data').first().json;\n\nreturn [{\n json: {\n date: combinedData.date,\n rowId: combinedData.rowId,\n sectionTitle: combinedData.sectionTitle,\n avatarId: combinedData.avatarId,\n script: parsed.script\n }\n}];"
},
"typeVersion": 2
},
{
"id": "9a9bafc5-9d6f-4ed6-88ff-b5e1a8d0b5cb",
"name": "Google Sheets: Create Production Log",
"type": "n8n-nodes-base.googleSheets",
"position": [
-192,
-176
],
"parameters": {
"columns": {
"value": {
"Date": "={{ $json.date }}",
"Status": "Generating",
"Script Text": "={{ $json.script }}",
"Section Title": "={{ $json.sectionTitle }}"
},
"schema": [
{
"id": "Date",
"type": "string",
"display": true,
"required": false,
"displayName": "Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Section Title",
"type": "string",
"display": true,
"required": false,
"displayName": "Section Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Script Text",
"type": "string",
"display": true,
"required": false,
"displayName": "Script Text",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "HeyGen Video ID",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "HeyGen Video ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Raw Video URL",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Raw Video URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Final Video URL",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Final Video URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 2075799952,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4/edit#gid=2075799952",
"cachedResultName": "Production Logs"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4/edit?usp=drivesdk",
"cachedResultName": "AI Avatar - PinkMatcha"
}
},
"typeVersion": 4.4
},
{
"id": "a436d05f-16f9-48e9-9c43-c30da42a8452",
"name": "Google Sheets: Save HeyGen Video ID",
"type": "n8n-nodes-base.googleSheets",
"position": [
-288,
176
],
"parameters": {
"columns": {
"value": {
"Status": "Processing",
"row_number": "={{ $('Code: Parse AI Response').item.json.rowId }}",
"HeyGen Video ID": "={{ $json.heygenVideoId }}"
},
"schema": [
{
"id": "Date",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Section Title",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Section Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Script Text",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Script Text",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "HeyGen Video ID",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "HeyGen Video ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Raw Video URL",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Raw Video URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Final Video URL",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Final Video URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Status",
"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": 2075799952,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4/edit#gid=2075799952",
"cachedResultName": "Production Logs"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4/edit?usp=drivesdk",
"cachedResultName": "AI Avatar - PinkMatcha"
}
},
"typeVersion": 4.4
},
{
"id": "37aef713-65d0-4237-a821-2c28f301ef58",
"name": "Google Sheets: Save Raw Video URL",
"type": "n8n-nodes-base.googleSheets",
"position": [
1184,
176
],
"parameters": {
"columns": {
"value": {
"Status": "Finalizing",
"row_number": "={{ $('Code: Parse AI Response').item.json.rowId }}",
"Raw Video URL": "={{ $json.rawVideoUrl }}"
},
"schema": [
{
"id": "Date",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Section Title",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Section Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Script Text",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Script Text",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "HeyGen Video ID",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "HeyGen Video ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Raw Video URL",
"type": "string",
"display": true,
"required": false,
"displayName": "Raw Video URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Final Video URL",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Final Video URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Status",
"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": 2075799952,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4/edit#gid=2075799952",
"cachedResultName": "Production Logs"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4/edit?usp=drivesdk",
"cachedResultName": "AI Avatar - PinkMatcha"
}
},
"typeVersion": 4.4
},
{
"id": "24eab730-94c9-41a7-93f3-f574b066e6dc",
"name": "Google Sheets: Update Complete",
"type": "n8n-nodes-base.googleSheets",
"position": [
-672,
688
],
"parameters": {
"columns": {
"value": {
"Status": "Complete",
"row_number": "={{ $('Code: Parse AI Response').item.json.rowId }}",
"Final Video URL": "={{ $json.finalVideoUrl }}"
},
"schema": [
{
"id": "Date",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Section Title",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Section Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Script Text",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Script Text",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "HeyGen Video ID",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "HeyGen Video ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Raw Video URL",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Raw Video URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Final Video URL",
"type": "string",
"display": true,
"required": false,
"displayName": "Final Video URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Status",
"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": 2075799952,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4/edit#gid=2075799952",
"cachedResultName": "Production Logs"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4/edit?usp=drivesdk",
"cachedResultName": "AI Avatar - PinkMatcha"
}
},
"typeVersion": 4.4
},
{
"id": "8bd4bfce-9c10-48cd-b6cf-d3d223796010",
"name": "Google Sheets: Mark Posted",
"type": "n8n-nodes-base.googleSheets",
"position": [
0,
688
],
"parameters": {
"columns": {
"value": {
"Status": "Posted",
"row_number": "={{ $('Code: Parse AI Response').item.json.rowId }}"
},
"schema": [
{
"id": "Date",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Section Title",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Section Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Script Text",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Script Text",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "HeyGen Video ID",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "HeyGen Video ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Raw Video URL",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Raw Video URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Final Video URL",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Final Video URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Status",
"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": 2075799952,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4/edit#gid=2075799952",
"cachedResultName": "Production Logs"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1mL7ES9lKFd-WQKPe8b-LPufqRHBpOmlJaGkKuSy3lY4/edit?usp=drivesdk",
"cachedResultName": "AI Avatar - PinkMatcha"
}
},
"typeVersion": 4.4
},
{
"id": "844dcc78-47ae-4040-b270-f345929f2a12",
"name": "Schedule: Daily 9am",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-752,
-528
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 12
}
]
}
},
"typeVersion": 1.2
},
{
"id": "c0ad64e8-51c2-44a5-9c28-da26111f6658",
"name": "Code: Prepare HeyGen Request",
"type": "n8n-nodes-base.code",
"position": [
32,
-176
],
"parameters": {
"jsCode": "// Get the created log record\nconst logRecord = $('Google Sheets: Create Production Log').first().json;\nconst contentData = $('Code: Parse AI Response').first().json;\n\nreturn [{\n json: {\n logRowNumber: logRecord.row_number || logRecord.rowNumber,\n avatarId: contentData.avatarId,\n script: contentData.script,\n sectionTitle: contentData.sectionTitle\n }\n}];"
},
"typeVersion": 2
},
{
"id": "1e748632-a584-47b2-b778-5e92880a9d39",
"name": "HTTP: HeyGen Generate Video",
"type": "n8n-nodes-base.httpRequest",
"position": [
-720,
176
],
"parameters": {
"url": "https://api.heygen.com/v2/video/generate",
"method": "POST",
"options": {
"timeout": 60000
},
"jsonBody": "={{ JSON.stringify({\n \"video_inputs\": [{\n \"character\": {\n \"type\": \"talking_photo\",\n \"talking_photo_id\": $json.avatarId\n },\n \"voice\": {\n \"type\": \"text\",\n \"input_text\": $json.script,\n \"voice_id\": \"ca320fd62b784352af74d06a16a6ef3d\"\n }\n }],\n \"dimension\": {\n \"width\": 720,\n \"height\": 1280\n },\n \"test\": false,\n \"caption\": false\n}) }}",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"typeVersion": 4.2
},
{
"id": "8a64e175-4ead-439f-adb2-0e3ba78f4615",
"name": "Code: Extract HeyGen Video ID",
"type": "n8n-nodes-base.code",
"position": [
-512,
176
],
"parameters": {
"jsCode": "const heygenResponse = $('HTTP: HeyGen Generate Video').first().json;\nconst prepData = $('Code: Prepare HeyGen Request').first().json;\n\nconst videoId = heygenResponse.data?.video_id || heygenResponse.video_id;\n\nif (!videoId) {\n throw new Error('No video_id returned from HeyGen: ' + JSON.stringify(heygenResponse));\n}\n\nreturn [{\n json: {\n logRowNumber: prepData.logRowNumber,\n heygenVideoId: videoId,\n pollCount: 0,\n maxPolls: 20,\n pollIntervalSec: 30\n }\n}];"
},
"typeVersion": 2
},
{
"id": "059dc443-3d50-4a2c-83f5-c625e647ad3a",
"name": "Wait: HeyGen Processing",
"type": "n8n-nodes-base.wait",
"position": [
-48,
176
],
"parameters": {
"amount": 50
},
"typeVersion": 1.1
},
{
"id": "8132f8a7-37fd-4b28-b9ab-bf6b4f4dff3f",
"name": "HTTP: Poll HeyGen Status",
"type": "n8n-nodes-base.httpRequest",
"position": [
208,
176
],
"parameters": {
"url": "=https://api.heygen.com/v1/video_status.get?video_id={{ $json['HeyGen Video ID'] }}",
"options": {
"timeout": 30000
},
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"typeVersion": 4.2
},
{
"id": "dd47044e-c6fe-40b2-84aa-74b2e6fc7380",
"name": "Code: Extract HeyGen Video URL",
"type": "n8n-nodes-base.code",
"position": [
960,
176
],
"parameters": {
"jsCode": "const pollResponse = $('HTTP: Poll HeyGen Status').first().json;\nconst current = $input.first().json;\n\nconst videoUrl = pollResponse.data?.video_url || pollResponse.video_url;\n\nif (!videoUrl) {\n throw new Error('No video URL in HeyGen response: ' + JSON.stringify(pollResponse));\n}\n\nreturn [{\n json: {\n logRowNumber: current.logRowNumber,\n heygenVideoId: current.heygenVideoId,\n rawVideoUrl: videoUrl\n }\n}];"
},
"typeVersion": 2
},
{
"id": "d9102495-18e6-4e9c-a132-cd92de6c353f",
"name": "Code: Set Final Video URL",
"type": "n8n-nodes-base.code",
"position": [
1408,
176
],
"parameters": {
"jsCode": "const heygenData = $('Code: Extract HeyGen Video URL').first().json;\n\nreturn [{\n json: {\n logRowNumber: heygenData.logRowNumber,\n finalVideoUrl: heygenData.rawVideoUrl\n }\n}];"
},
"typeVersion": 2
},
{
"id": "2f971e89-70bd-4203-9a39-9288e0ac7121",
"name": "facebook",
"type": "n8n-nodes-base.httpRequest",
"disabled": true,
"position": [
-448,
592
],
"parameters": {
"url": "https://api.upload-post.com/api/upload",
"method": "POST",
"options": {},
"sendBody": true,
"contentType": "multipart-form-data",
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "user",
"value": "pink-matcha"
},
{
"name": "platform[]",
"value": "facebook"
},
{
"name": "video",
"value": "={{ $('Code: Set Final Video URL').first().json.finalVideoUrl }}"
},
{
"name": "title",
"value": "={{ $('Code: Parse AI Response').first().json.sectionTitle.substring(0, 120) + ' - ' + $('Code: Parse AI Response').first().json.script.substring(0, 100) + '... Link in Bio' }}"
}
]
},
"genericAuthType": "httpHeaderAuth"
},
"typeVersion": 4.3
},
{
"id": "eb9eb797-a36c-4dcc-8567-201bd4aeb84e",
"name": "instagram",
"type": "n8n-nodes-base.httpRequest",
"position": [
-448,
768
],
"parameters": {
"url": "https://api.upload-post.com/api/upload",
"method": "POST",
"options": {},
"sendBody": true,
"contentType": "multipart-form-data",
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "user",
"value": "pink-matcha"
},
{
"name": "platform[]",
"value": "instagram"
},
{
"name": "video",
"value": "={{ $('Code: Set Final Video URL').first().json.finalVideoUrl }}"
},
{
"name": "title",
"value": "={{ $('Code: Parse AI Response').first().json.sectionTitle.substring(0, 120) + ' - ' + $('Code: Parse AI Response').first().json.script.substring(0, 100) + '... Link in Bio' }}"
}
]
},
"genericAuthType": "httpHeaderAuth"
},
"typeVersion": 4.3
},
{
"id": "f54ea360-8c57-4c18-902d-49999821186c",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"position": [
-224,
688
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "9be10c2c-0c7b-41fd-acec-d13bc381ccc7",
"name": "Switch",
"type": "n8n-nodes-base.switch",
"position": [
704,
160
],
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "9455b630-813e-47d0-9ba0-4a1c3750ee19",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.heygenRoute }}",
"rightValue": "retry"
}
]
}
},
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "d1a191e1-f7cd-4722-a63f-83b50f6201c7",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.heygenRoute }}",
"rightValue": "completed"
}
]
}
},
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "fd7b658a-5fe4-4953-84c1-e64207cc95b1",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.heygenRoute }}",
"rightValue": "failed"
}
]
}
}
]
},
"options": {}
},
"typeVersion": 3.4
},
{
"id": "e000ac72-1068-44e4-ab0e-21fc93db491e",
"name": "Generate Script",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
-704,
-176
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4.1-mini",
"cachedResultName": "GPT-4.1-MINI"
},
"options": {},
"responses": {
"values": [
{
"content": "=Section Title: {{ $('Code: Select Random Avatar & Combine Data').first().json.sectionTitle }}\n\nWorkbook Content:\n{{ $('Code: Select Random Avatar & Combine Data').first().json.workbookContent }}\n\nKey Message:\n{{ $('Code: Select Random Avatar & Combine Data').first().json.keyMessage }}"
},
{
"role": "system",
"content": "You are \"The Shepherd\", a wise, calm, and deeply compassionate spiritual guide. Your voice carries ancient wisdom but speaks in simple, accessible language. You help people find peace, purpose, and clarity.\n\nYour task is to create content for a short-form video (Instagram Reels, TikTok, YouTube Shorts).\n\nGenerate a SCRIPT based on the workbook section provided:\n\nDetailed instructions:\n- A spoken-word script of 75-90 words (~30 seconds when spoken). THIS IS CRITICAL - THE VIDEO MUST BE 30 SECONDS MAXIMUM.\n- The script should talk about the specific part of the workbook mentioned in the Section Title and Workbook Content.\n- Write ONLY what will be spoken, no stage directions, no timestamps, no scene descriptions.\n- The tone should be warm, grounded, and gently inspiring.\n- The video MUST END with the phrase: \"Visit the link in bio to learn more.\"\n- Keep it concise and within 30 seconds when spoken naturally.\n\nRespond in this exact JSON format:\n{\n \"script\": \"Your full script here...\"\n}\n\nDo NOT include any preamble. Begin immediately with {"
}
]
},
"builtInTools": {}
},
"typeVersion": 2.1
},
{
"id": "82972bfd-5a43-4a3d-8dfa-060bd52eeb14",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1408,
-656
],
"parameters": {
"color": 7,
"width": 528,
"height": 288,
"content": " # Overall Workflow Overview \n This workflow runs daily, picks a content section from Google Sheets, generates a 30-second spoken script using GPT-4.1-mini, renders a talking-head video via HeyGen, then publishes it to Facebook and Instagram. All steps are logged in the \"Production Logs\" sheet."
},
"typeVersion": 1
},
{
"id": "e3e5d2d6-04db-445b-8d44-f1488b63c697",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-864,
-656
],
"parameters": {
"width": 1168,
"height": 288,
"content": "## 1. Content Selection\nPicks today's content using day-of-year modulo total sections, so content rotates automatically without repeating. Only rows with Status = \"Idea\" are eligible. Add new rows to the \"Workbook Content\" sheet to expand the content pool."
},
"typeVersion": 1
},
{
"id": "4220b5f6-01e7-4370-b5f9-a5f52d35b175",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-864,
-336
],
"parameters": {
"color": 2,
"width": 1184,
"height": 320,
"content": "## 2. Script Generation\nUses GPT-4.1-mini with \"The Shepherd\" persona. Target: 75-90 words (~30 seconds spoken). Must end with \"Visit the link in bio to learn more.\" Output is strict JSON { \"script\": \"...\" } \u2014 the parse node handles markdown-wrapped or malformed responses."
},
"typeVersion": 1
},
{
"id": "d1c54f7c-1390-48da-9df2-7df43b7142a8",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-864,
16
],
"parameters": {
"color": 3,
"width": 2464,
"height": 384,
"content": "## 3. HeyGen Polling Loop\nHeyGen video generation is async. This loop polls every 50 seconds, up to 20 times (~16 min max). Switch routes to: retry (still processing), completed (extract URL), or failed (log error). If it times out, it also routes to failed."
},
"typeVersion": 1
},
{
"id": "d9f6b768-3bc6-4d43-94fc-10a5e25e5b12",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-864,
448
],
"parameters": {
"color": 4,
"width": 1232,
"height": 480,
"content": "## 4. Social Publishing\nPosts to Facebook and Instagram via upload-post.com API. The caption is auto-generated from the section title + first 100 chars of script + \"... Link in Bio\". Note: Facebook node is currently disabled \u2014 enable it when ready to go live on Facebook."
},
"typeVersion": 1
},
{
"id": "1da61638-53f7-48f8-838f-d29b615bb6aa",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-864,
976
],
"parameters": {
"color": 5,
"width": 1216,
"height": 304,
"content": "## 5. Error Handling\nIf HeyGen fails or times out, the failure reason and status are written back to the Production Logs sheet. The workflow also has an error workflow configured for unexpected crashes."
},
"typeVersion": 1
}
],
"active": true,
"settings": {
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": "kohRSFWsjOdaD1r7",
"timeSavedMode": "fixed",
"availableInMCP": true,
"executionOrder": "v1"
},
"versionId": "91a8b7ad-f2ea-41d0-bfdd-e935757eaf8a",
"isArchived": false,
"connections": {
"Merge": {
"main": [
[
{
"node": "Google Sheets: Mark Posted",
"type": "main",
"index": 0
}
]
]
},
"Switch": {
"main": [
[
{
"node": "Wait: HeyGen Processing",
"type": "main",
"index": 0
}
],
[
{
"node": "Code: Extract HeyGen Video URL",
"type": "main",
"index": 0
}
],
[
{
"node": "Google Sheets: Log Failure",
"type": "main",
"index": 0
}
]
]
},
"facebook": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"instagram": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"Generate Script": {
"main": [
[
{
"node": "Code: Parse AI Response",
"type": "main",
"index": 0
}
]
]
},
"Schedule: Daily 9am": {
"main": [
[
{
"node": "Code: Calculate Content Index",
"type": "main",
"index": 0
}
]
]
},
"Code: Parse AI Response": {
"main": [
[
{
"node": "Google Sheets: Create Production Log",
"type": "main",
"index": 0
}
]
]
},
"Wait: HeyGen Processing": {
"main": [
[
{
"node": "HTTP: Poll HeyGen Status",
"type": "main",
"index": 0
}
]
]
},
"HTTP: Poll HeyGen Status": {
"main": [
[
{
"node": "Code: Check HeyGen Status",
"type": "main",
"index": 0
}
]
]
},
"Code: Check HeyGen Status": {
"main": [
[
{
"node": "Switch",
"type": "main",
"index": 0
}
]
]
},
"Code: Set Final Video URL": {
"main": [
[
{
"node": "Google Sheets: Update Complete",
"type": "main",
"index": 0
}
]
]
},
"HTTP: HeyGen Generate Video": {
"main": [
[
{
"node": "Code: Extract HeyGen Video ID",
"type": "main",
"index": 0
}
]
]
},
"Code: Prepare HeyGen Request": {
"main": [
[
{
"node": "HTTP: HeyGen Generate Video",
"type": "main",
"index": 0
}
]
]
},
"Code: Select Today's Section": {
"main": [
[
{
"node": "Code: Select Random Avatar & Combine Data",
"type": "main",
"index": 0
}
]
]
},
"Code: Calculate Content Index": {
"main": [
[
{
"node": "Google Sheets: Get Workbook Content",
"type": "main",
"index": 0
}
]
]
},
"Code: Extract HeyGen Video ID": {
"main": [
[
{
"node": "Google Sheets: Save HeyGen Video ID",
"type": "main",
"index": 0
}
]
]
},
"Code: Extract HeyGen Video URL": {
"main": [
[
{
"node": "Google Sheets: Save Raw Video URL",
"type": "main",
"index": 0
}
]
]
},
"Google Sheets: Update Complete": {
"main": [
[
{
"node": "facebook",
"type": "main",
"index": 0
},
{
"node": "instagram",
"type": "main",
"index": 0
}
]
]
},
"Google Sheets: Save Raw Video URL": {
"main": [
[
{
"node": "Code: Set Final Video URL",
"type": "main",
"index": 0
}
]
]
},
"Google Sheets: Get Workbook Content": {
"main": [
[
{
"node": "Code: Select Today's Section",
"type": "main",
"index": 0
}
]
]
},
"Google Sheets: Save HeyGen Video ID": {
"main": [
[
{
"node": "Wait: HeyGen Processing",
"type": "main",
"index": 0
}
]
]
},
"Google Sheets: Create Production Log": {
"main": [
[
{
"node": "Code: Prepare HeyGen Request",
"type": "main",
"index": 0
}
]
]
},
"Code: Select Random Avatar & Combine Data": {
"main": [
[
{
"node": "Generate Script",
"type": "main",
"index": 0
}
]
]
}
},
"description": "Generate viral videos using Heygen and autopublish them directly to facebook and instagram"
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Stop manually creating short-form video content. This n8n workflow automatically generates AI talking-head UGC videos using HeyGen and publishes them to Instagram and Facebook every single day — fully on autopilot.
Source: https://n8n.io/workflows/14266/ — 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.
AI Institutional Stock Valuation Engine with Risk Scoring & Scenario Targets
Overview This is a production-grade, fully automated stock analysis system built entirely in n8n. It combines institutional-level financial analysis, dual AI model consensus, and a self-improving back
This automation is a complete end-to-end system designed to find, qualify, and contact B2B leads — fully automated and powered by AI. Searches for target companies on LinkedIn via Ghost Genius API, us
This comprehensive n8n automation template orchestrates a complete end-to-end workflow for generating engaging short-form Point-of-View (POV) style videos using multiple AI services and automatically
A professional AI equity analysis automation built on n8n that transforms structured financial data and real-time news into disciplined, risk-adjusted price targets and actionable BUY/HOLD/SELL signal