This workflow corresponds to n8n.io template #17132 — we link there as the canonical source.
This workflow follows the Gmail → Google Drive 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 →
{
"name": "Google Sheets \u2192 personalized videos (render, deliver, write back)",
"nodes": [
{
"id": "c5d7f436-f695-4c0c-8fc2-6e167407cc78",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
272,
208
],
"parameters": {
"width": 480,
"height": 896,
"content": "## Google Sheets \u2192 personalized videos (render, deliver, write back)\n\n### How it works\n\nThis workflow turns new Google Sheets rows into personalized video deliveries. When a row is added, it validates required data, starts a render job, polls the video editor until completion, then downloads and stores the MP4 in Google Drive. It writes the final video URL back to the sheet, emails the recipient, and sends failure alerts if rendering fails or exceeds the retry limit.\n\n### Setup steps\n\n- Connect Google Sheets credentials for the trigger and write-back node, and configure the target spreadsheet, worksheet, and row fields such as title, recipient email, attempts, and video URL.\n- Configure the video editor nodes with the required API credentials, render template, personalization inputs, and status/job ID mappings.\n- Connect Google Drive credentials and choose the destination folder and sharing settings for uploaded MP4 files.\n- Connect Gmail credentials and configure both the success email template and the failure alert recipient/message.\n- Verify the retry counter field and polling logic are initialized correctly so the workflow can loop until the maximum of 20 attempts.\n\n### Customization\n\nAdjust the 60-second wait time, the 20-attempt retry limit, the Drive folder or sharing permissions, and the email templates to match the expected render duration and delivery style."
},
"typeVersion": 1
},
{
"id": "41dcd01d-58cf-49fb-a0b0-1f8e7d62eb7d",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
832,
288
],
"parameters": {
"color": 7,
"width": 416,
"height": 320,
"content": "## Sheet trigger validation\n\nWatches Google Sheets for newly added rows and checks that the row contains the required title before starting video creation."
},
"typeVersion": 1
},
{
"id": "e14b33b4-7595-4fb6-b362-67931e3b9513",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1280,
224
],
"parameters": {
"color": 7,
"width": 240,
"height": 384,
"content": "## Start video render\n\nSubmits the personalized video render job to the video editor service, with a direct failure path if the render request cannot be created."
},
"typeVersion": 1
},
{
"id": "46c5b118-028f-4289-9a49-54da1928d0eb",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1552,
304
],
"parameters": {
"color": 7,
"width": 640,
"height": 304,
"content": "## Poll render status\n\nWaits between checks, queries the render job status, and branches based on whether the video has completed or needs further handling."
},
"typeVersion": 1
},
{
"id": "a537235e-05b8-47e2-8bb4-4091d728bf26",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2224,
208
],
"parameters": {
"color": 7,
"width": 848,
"height": 304,
"content": "## Deliver finished video\n\nDownloads the completed MP4, uploads it to Google Drive, writes the resulting video URL back to Google Sheets, and emails the link to the recipient."
},
"typeVersion": 1
},
{
"id": "68f32e23-2bee-498c-8347-1bc6b46b0343",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1936,
640
],
"parameters": {
"color": 7,
"width": 896,
"height": 304,
"content": "## Retry or alert failure\n\nHandles unsuccessful or unfinished renders by detecting failure states, incrementing the attempt counter, looping back while under the retry limit, or sending a failure alert email."
},
"typeVersion": 1
},
{
"id": "a1b2c3d4-1111-4aaa-8bbb-000000000021",
"name": "When Row Added to Sheets",
"type": "n8n-nodes-base.googleSheetsTrigger",
"position": [
880,
440
],
"parameters": {
"event": "rowAdded",
"pollTimes": {
"item": [
{
"mode": "everyHour"
}
]
},
"sheetName": "REPLACE_WITH_SHEET_NAME",
"documentId": "REPLACE_WITH_GOOGLE_SHEET_DOCUMENT_ID"
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "a1b2c3d4-1111-4aaa-8bbb-000000000022",
"name": "If Title Exists",
"type": "n8n-nodes-base.if",
"position": [
1100,
440
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c0nd1t10-1111-4aaa-8bbb-+1234567890",
"operator": {
"name": "filter.operator.notEmpty",
"type": "string",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.Title }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2
},
{
"id": "a1b2c3d4-1111-4aaa-8bbb-000000000023",
"name": "Render Personalized Video",
"type": "n8n-nodes-ilovevideoeditor.iloveVideoEditor",
"onError": "continueErrorOutput",
"position": [
1320,
440
],
"parameters": {
"resource": "render",
"operation": "createFromTemplate",
"variables": "={ \"title\": \"{{ $json.Title }}\", \"subtitle\": \"{{ $json.Subtitle }}\" }",
"templateId": "cinematic-title"
},
"credentials": {
"iloveVideoEditorApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "a1b2c3d4-1111-4aaa-8bbb-000000000024",
"name": "Wait 60 Seconds",
"type": "n8n-nodes-base.wait",
"position": [
1600,
448
],
"parameters": {
"unit": "seconds",
"amount": 60
},
"typeVersion": 1.1
},
{
"id": "a1b2c3d4-1111-4aaa-8bbb-000000000025",
"name": "Check Video Render Status",
"type": "n8n-nodes-ilovevideoeditor.iloveVideoEditor",
"position": [
1824,
448
],
"parameters": {
"renderId": "={{ $('Render Personalized Video').item.json.jobId }}",
"resource": "render",
"operation": "get"
},
"credentials": {
"iloveVideoEditorApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "a1b2c3d4-1111-4aaa-8bbb-000000000026",
"name": "If Render Complete",
"type": "n8n-nodes-base.if",
"position": [
2048,
448
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c0nd1t10-1111-4aaa-8bbb-+1234567890",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.status }}",
"rightValue": "completed"
}
]
}
},
"typeVersion": 2
},
{
"id": "a1b2c3d4-1111-4aaa-8bbb-000000000027",
"name": "If Render Failed",
"type": "n8n-nodes-base.if",
"position": [
1984,
768
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c0nd1t10-1111-4aaa-8bbb-+1234567890",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.status }}",
"rightValue": "failed"
}
]
}
},
"typeVersion": 2
},
{
"id": "a1b2c3d4-1111-4aaa-8bbb-000000000028",
"name": "Download Video File",
"type": "n8n-nodes-base.httpRequest",
"position": [
2272,
336
],
"parameters": {
"url": "={{ $json.url }}",
"method": "GET",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"typeVersion": 4.2
},
{
"id": "a1b2c3d4-1111-4aaa-8bbb-000000000029",
"name": "Upload Video to Drive",
"type": "n8n-nodes-base.googleDrive",
"position": [
2496,
336
],
"parameters": {
"name": "={{ $('When Row Added to Sheets').item.json.Title }}.mp4",
"options": {},
"parents": [
"REPLACE_WITH_GOOGLE_DRIVE_FOLDER_ID"
],
"resource": "file",
"operation": "upload"
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "a1b2c3d4-1111-4aaa-8bbb-000000000030",
"name": "Update Video URL in Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
2720,
336
],
"parameters": {
"columns": {
"value": {
"ID": "={{ $('When Row Added to Sheets').item.json.ID }}",
"Video URL": "={{ $json.webViewLink || ('https://drive.google.com/file/d/' + $json.id + '/view') }}"
},
"schema": [
{
"id": "ID",
"type": "string",
"display": true,
"required": false,
"displayName": "ID",
"defaultMatch": true,
"canBeUsedToMatch": true
},
{
"id": "Title",
"type": "string",
"display": true,
"required": false,
"displayName": "Title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Subtitle",
"type": "string",
"display": true,
"required": false,
"displayName": "Subtitle",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email",
"type": "string",
"display": true,
"required": false,
"displayName": "Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Video URL",
"type": "string",
"display": true,
"required": false,
"displayName": "Video URL",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"ID"
]
},
"options": {},
"resource": "sheetWithinDocument",
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "REPLACE_WITH_SHEET_NAME"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "REPLACE_WITH_GOOGLE_SHEET_DOCUMENT_ID"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "a1b2c3d4-1111-4aaa-8bbb-000000000031",
"name": "Send Video Link Email",
"type": "n8n-nodes-base.gmail",
"position": [
2928,
336
],
"parameters": {
"message": "=Hi,\n\nYour personalized video is ready:\n{{ $('Upload Video to Drive').item.json.webViewLink || ('https://drive.google.com/file/d/' + $('Upload Video to Drive').item.json.id + '/view') }}\n\nEnjoy!",
"options": {
"sendTo": "={{ $('When Row Added to Sheets').item.json.Email }}"
},
"subject": "=Your video \"{{ $('When Row Added to Sheets').item.json.Title }}\" is ready",
"resource": "message",
"emailType": "text",
"operation": "send"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "a1b2c3d4-1111-4aaa-8bbb-000000000032",
"name": "Increment Attempt Count",
"type": "n8n-nodes-base.set",
"position": [
2240,
768
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "a5519nme-1111-4aaa-8bbb-+1234567890",
"name": "attempts",
"type": "number",
"value": "={{ ($json.attempts ?? 0) + 1 }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "a1b2c3d4-1111-4aaa-8bbb-000000000033",
"name": "If Under 20 Attempts",
"type": "n8n-nodes-base.if",
"position": [
2464,
768
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c0nd1t10-1111-4aaa-8bbb-+1234567890",
"operator": {
"name": "filter.operator.lt",
"type": "number",
"operation": "lt"
},
"leftValue": "={{ $json.attempts }}",
"rightValue": 20
}
]
}
},
"typeVersion": 2
},
{
"id": "a1b2c3d4-1111-4aaa-8bbb-000000000034",
"name": "Send Failure Alert Email",
"type": "n8n-nodes-base.gmail",
"position": [
2688,
768
],
"parameters": {
"message": "=A video render failed or timed out.\n\nSheet row ID: {{ $('When Row Added to Sheets').item.json.ID }}\nTitle: {{ $('When Row Added to Sheets').item.json.Title }}\n\nCheck the n8n execution log for details.",
"options": {
"sendTo": "REPLACE_WITH_YOUR_EMAIL"
},
"subject": "=Video render failed for \"{{ $('When Row Added to Sheets').item.json.Title }}\"",
"resource": "message",
"emailType": "text",
"operation": "send"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
}
],
"settings": {
"executionOrder": "v1"
},
"connections": {
"If Title Exists": {
"main": [
[
{
"node": "Render Personalized Video",
"type": "main",
"index": 0
}
]
]
},
"Wait 60 Seconds": {
"main": [
[
{
"node": "Check Video Render Status",
"type": "main",
"index": 0
}
]
]
},
"If Render Failed": {
"main": [
[
{
"node": "Send Failure Alert Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Increment Attempt Count",
"type": "main",
"index": 0
}
]
]
},
"If Render Complete": {
"main": [
[
{
"node": "Download Video File",
"type": "main",
"index": 0
}
],
[
{
"node": "If Render Failed",
"type": "main",
"index": 0
}
]
]
},
"Download Video File": {
"main": [
[
{
"node": "Upload Video to Drive",
"type": "main",
"index": 0
}
]
]
},
"If Under 20 Attempts": {
"main": [
[
{
"node": "Wait 60 Seconds",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Failure Alert Email",
"type": "main",
"index": 0
}
]
]
},
"Upload Video to Drive": {
"main": [
[
{
"node": "Update Video URL in Sheets",
"type": "main",
"index": 0
}
]
]
},
"Increment Attempt Count": {
"main": [
[
{
"node": "If Under 20 Attempts",
"type": "main",
"index": 0
}
]
]
},
"When Row Added to Sheets": {
"main": [
[
{
"node": "If Title Exists",
"type": "main",
"index": 0
}
]
]
},
"Check Video Render Status": {
"main": [
[
{
"node": "If Render Complete",
"type": "main",
"index": 0
}
]
]
},
"Render Personalized Video": {
"main": [
[
{
"node": "Wait 60 Seconds",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Failure Alert Email",
"type": "main",
"index": 0
}
]
]
},
"Update Video URL in Sheets": {
"main": [
[
{
"node": "Send Video Link Email",
"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.
gmailOAuth2googleDriveOAuth2ApigoogleSheetsOAuth2ApiiloveVideoEditorApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow watches Google Sheets for new rows, renders a personalized video with iLoveVideoEditor using the row data, uploads the finished MP4 to Google Drive, writes the Drive link back to the same sheet row, and emails the link to the recipient via Gmail. Triggers on a…
Source: https://n8n.io/workflows/17132/ — 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.
Hiring teams often struggle with document follow-ups, offer letter generation, and stakeholder communication. Manual checks, email back-and-forth, and missing files slow down hiring and create chaos d
This workflow turns a Google Sheet into an automated certificate-issuing pipeline. The moment a new completion row is added — whether by your training team, a Zap, or a quiz platform — a branded PDF/A
This workflow automates the end-to-end process of generating and sending client payment links using Google Sheets and Stripe.
This template is ideal for HR teams, startup founders, operations leads, remote-first companies, and freelancers managing onboarding manually or across multiple tools.
This workflow ingests proof-of-delivery and completion documents from Gmail or a webhook, extracts key fields with an OpenRouter vision model, reconciles them against Google Sheets dispatch data, arch