AutomationFlowsSocial Media › HeyGen AI Avatar Video to YouTube Upload

HeyGen AI Avatar Video to YouTube Upload

Original n8n title: Generate AI Avatar Videos From Text with Heygen and Upload to Youtube

ByNishant Rayan @nishantrayan on n8n.io

This workflow automates the process of creating an AI-generated avatar video using HeyGen and directly uploading it to YouTube. By sending text input via a webhook, the workflow generates a video with a chosen avatar and voice, waits for processing, downloads the completed file,…

Webhook trigger★★★★☆ complexity17 nodesHTTP RequestYouTube
Social Media Trigger: Webhook Nodes: 17 Complexity: ★★★★☆ Added:

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

This workflow follows the HTTP Request → YouTube 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": "OxdUBxc7llHmoDZx",
  "name": "My workflow 3",
  "tags": [],
  "nodes": [
    {
      "id": "4a993817-3909-4d2b-b7ef-f2b9f34dea76",
      "name": "Sticky - Webhook Contract & Security",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -336,
        48
      ],
      "parameters": {
        "content": "Inbound trigger for external start. Validate secret; parse JSON; return 200 immediately."
      },
      "typeVersion": 1
    },
    {
      "id": "ddb50403-dc30-4068-9c40-0022f222b748",
      "name": "WebHook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -96,
        96
      ],
      "parameters": {
        "path": "52048302-06bd-4eae-9b004c5ed17d",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2.1
    },
    {
      "id": "2322ee6b-3f5a-46d4-95b2-3ac405711621",
      "name": "Sticky - Normalize Text for TTS",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        32,
        16
      ],
      "parameters": {
        "height": 224,
        "content": "Sanitize the video script to ensure HeyGen can use that correctly."
      },
      "typeVersion": 1
    },
    {
      "id": "58891633-6f20-4d91-99f9-6f72cfd0336b",
      "name": "Code",
      "type": "n8n-nodes-base.code",
      "position": [
        128,
        96
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const item = $input.item;\nreturn { json: { content: item.json.body.content.replaceAll(\"\\n\", \"\").replaceAll(\"\\r\", \"\"), title:item.json.body.title } };"
      },
      "typeVersion": 2
    },
    {
      "id": "2cc0fe4b-a229-4937-a8b7-d6ed766aee6b",
      "name": "Sticky - Parameter Staging (Secrets & IDs)",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        304,
        -16
      ],
      "parameters": {
        "height": 320,
        "content": "Init vars (script, voice_id, avatar_id, aspect, sub=false); set defaults."
      },
      "typeVersion": 1
    },
    {
      "id": "86024350-5e49-43a6-a98f-f3cc0ad63abf",
      "name": "Setup Heygen Parameters",
      "type": "n8n-nodes-base.set",
      "disabled": true,
      "position": [
        384,
        96
      ],
      "parameters": {
        "fields": {
          "values": [
            {
              "name": "x-api-key"
            },
            {
              "name": "voice_id"
            },
            {
              "name": "avatar_id"
            },
            {
              "name": "title",
              "stringValue": "={{ $json.title }}"
            },
            {
              "name": "content",
              "stringValue": "={{ $json.content }}"
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "f1fa5816-f371-4a91-8eed-fca27399b46f",
      "name": "Sticky - Create HeyGen Job (v2)",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        -16
      ],
      "parameters": {
        "width": 208,
        "height": 288,
        "content": "Submit video generation request to HeyGen using API: POST /v2/video/generate with params."
      },
      "typeVersion": 1
    },
    {
      "id": "970c4d5f-0ba5-4b3e-9b0b-d6edb8821f9b",
      "name": "Create Avatar Video (HeyGen)",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        608,
        96
      ],
      "parameters": {
        "url": "https://api.heygen.com/v2/video/generate",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"video_inputs\": [\n    {\n      \"character\": {\n        \"type\": \"avatar\",\n        \"avatar_id\": \"{{ $json.avatar_id }}\",\n        \"avatar_style\": \"normal\"\n      },\n      \"voice\": {\n        \"type\": \"text\",\n        \"input_text\": \"{{ $json.content }}\",\n        \"voice_id\": \"{{ $json.voice_id }}\",\n        \"speed\": 1.1\n      }\n    }\n  ],\n  \"dimension\": {\n    \"width\": 1280,\n    \"height\": 720\n  }\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Api-Key",
              "value": "={{ $json['x-api-key'] }}"
            }
          ]
        }
      },
      "typeVersion": 4
    },
    {
      "id": "ff31c0bd-26af-4065-8e7f-9910955e5326",
      "name": "Sticky - Polling Cycle",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        784,
        0
      ],
      "parameters": {
        "width": 208,
        "height": 272,
        "content": "Delay polling to avoid rate limits; increase wait for long video generations"
      },
      "typeVersion": 1
    },
    {
      "id": "2661127a-2c82-4a88-9336-0a04df5eddb3",
      "name": "Wait for Video (HeyGen)",
      "type": "n8n-nodes-base.wait",
      "position": [
        832,
        96
      ],
      "parameters": {
        "unit": "minutes",
        "amount": 0.1
      },
      "typeVersion": 1
    },
    {
      "id": "36b2a0f9-84d4-4b1d-b61b-f2233b28ffe2",
      "name": "Get Avatar Video Status (HeyGen)",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1056,
        96
      ],
      "parameters": {
        "url": "https://api.heygen.com/v1/video_status.get",
        "options": {},
        "sendQuery": true,
        "sendHeaders": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "video_id",
              "value": "={{ $('Create Avatar Video (HeyGen)').item.json.data.video_id }}"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Api-Key",
              "value": "={{ $('Setup Heygen Parameters').item.json['x-api-key'] }}"
            }
          ]
        }
      },
      "typeVersion": 4
    },
    {
      "id": "37a4815e-7562-4764-8883-03e2502a897a",
      "name": "If Processing Completed",
      "type": "n8n-nodes-base.if",
      "position": [
        1264,
        96
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "2b0f3da8-9f60-4a14-af38-8064531cf6d4",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.data.status }}",
              "rightValue": "processing"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "7de09738-3b54-4b96-a46d-65c85767da8e",
      "name": "Sticky - Download Result (Binary)",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1424,
        -16
      ],
      "parameters": {
        "height": 256,
        "content": "If status is not 'processing' -> Try to download; if download fails it means the video generation in HeyGen errored for whatever reason."
      },
      "typeVersion": 1
    },
    {
      "id": "a97d12ea-8280-41bc-a415-42df2083c017",
      "name": "Download Video",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1488,
        96
      ],
      "parameters": {
        "url": "={{ $json.data.video_url }}",
        "options": {}
      },
      "typeVersion": 4
    },
    {
      "id": "d2f7447a-232a-4817-89ef-b2058d570643",
      "name": "Sticky - YouTube Upload (Binary Property & Metadata)",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1680,
        0
      ],
      "parameters": {
        "width": 224,
        "height": 240,
        "content": "Upload the video (downloaded data) to Youtube."
      },
      "typeVersion": 1
    },
    {
      "id": "6056c5ef-2c7f-47fd-b75c-0cf3ad286997",
      "name": "Upload a video",
      "type": "n8n-nodes-base.youTube",
      "position": [
        1712,
        96
      ],
      "parameters": {
        "title": "={{ $('Setup Heygen Parameters').item.json.title }}",
        "options": {},
        "resource": "video",
        "operation": "upload",
        "categoryId": "28",
        "regionCode": "US"
      },
      "credentials": {
        "youTubeOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "2ee94e2e-531d-40d7-8d83-0a805b96b3b4",
      "name": "Sticky - Polling Cycle1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1008,
        0
      ],
      "parameters": {
        "width": 208,
        "height": 272,
        "content": "Get status of the generated video from HeyGen."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "e8f0e6b5-b9a0-4b09-8106-2e326dbd3f14",
  "connections": {
    "Code": {
      "main": [
        [
          {
            "node": "Setup Heygen Parameters",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "WebHook": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Video": {
      "main": [
        [
          {
            "node": "Upload a video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Processing Completed": {
      "main": [
        [
          {
            "node": "Download Video",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait for Video (HeyGen)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Setup Heygen Parameters": {
      "main": [
        [
          {
            "node": "Create Avatar Video (HeyGen)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Video (HeyGen)": {
      "main": [
        [
          {
            "node": "Get Avatar Video Status (HeyGen)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Avatar Video (HeyGen)": {
      "main": [
        [
          {
            "node": "Wait for Video (HeyGen)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Avatar Video Status (HeyGen)": {
      "main": [
        [
          {
            "node": "If Processing Completed",
            "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

This workflow automates the process of creating an AI-generated avatar video using HeyGen and directly uploading it to YouTube. By sending text input via a webhook, the workflow generates a video with a chosen avatar and voice, waits for processing, downloads the completed file,…

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

More Social Media workflows → · Browse all categories →

Related workflows

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

Social Media

Automated n8n workflow: Receives videos via form, dubs/translates them to the selected languages, and—upon completion—uploads them to multiple social media channels and cloud drives, including Box, Dr

HTTP Request, Telegram, Box +3
Social Media

My workflow 3. Uses httpRequest, youTube. Webhook trigger; 17 nodes.

HTTP Request, YouTube
Social Media

Instagram - Fluxo de mensagens. Uses rabbitmq, rabbitmqTrigger, googleSheets, httpRequest. Webhook trigger; 74 nodes.

Rabbitmq, Rabbitmq Trigger, Google Sheets +1
Social Media

Are you a cord-cutter? Do you find yourself looking through the many titles of videos uploaded to Youtube, just to find the ones you want to watch? Even when you subscribe to the channels you like, do

Google Sheets, HTTP Request, YouTube +1
Social Media

Video explanation

HTTP Request, Execute Workflow Trigger, Postgres +1