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 →
{
"name": "IG Reels - v3.0 (n8n 1.110.1)",
"nodes": [
{
"parameters": {
"triggerTimes": {
"item": [
{
"hour": 9,
"minute": 0
}
],
"timezone": "Asia/Taipei"
}
},
"name": "Cron - 09:00",
"type": "n8n-nodes-base.cron",
"typeVersion": 1,
"position": [
-1380,
-20
]
},
{
"parameters": {
"authentication": "none",
"requestMethod": "POST",
"url": "https://api.openai.com/v1/chat/completions",
"jsonParameters": true,
"sendHeaders": true,
"headerParametersJson": "{\"Authorization\":\"Bearer {{$env.OPENAI_API_KEY}}\",\"Content-Type\":\"application/json\"}",
"bodyParametersJson": "{\n \"model\": \"gpt-4o-mini\",\n \"response_format\": {\"type\": \"json_object\"},\n \"messages\": [\n {\"role\": \"system\", \"content\": \"\u4f60\u662f\u77ed\u5f71\u7247\u8173\u672c\u7de8\u5287\u3002\u8f38\u51fa JSON\uff1a{\\\\\"title\\\\\":string,\\\\\"caption\\\\\":string,\\\\\"script\\\\\":string[]}\u3002script \u70ba 6~8 \u884c\uff0c\u6bcf\u884c 5~12 \u5b57\uff0c\u6574\u9ad4\u7bc0\u594f\u63a7\u5236 40~44 \u79d2\uff0c\u8a9e\u6c23\u5c08\u696d\u89aa\u5207\uff0c\u7e41\u9ad4\u4e2d\u6587\uff0c\u907f\u514d\u8a87\u5927\u7528\u8a9e\u3002\"},\n {\"role\": \"user\", \"content\": \"\u4e3b\u984c\uff1aAI \u81ea\u52d5\u5316\u5c0f\u6280\u5de7\u3002\u7522\u51fa\u4e00\u500b\u53ef\u5728 IG Reels \u4f7f\u7528\u7684\u8173\u672c\u8207\u8cbc\u6587\u6587\u6848\u3002\"}\n ]\n}"
},
"name": "AI - Script & Caption",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
-1160,
-20
]
},
{
"parameters": {
"functionCode": "const c=$json.choices?.[0]?.message?.content||'{}';let o={};try{o=JSON.parse(c);}catch(e){o={};}const title=String(o.title||'\u4eca\u65e5\u91cd\u9ede').trim();const caption=String(o.caption||'\u6bcf\u5929\u4e00\u5247\u81ea\u52d5\u5316\u5c0f\u77e5\u8b58').trim();const lines=Array.isArray(o.script)?o.script.filter(s=>String(s).trim()).slice(0,8):['\u5b78\u6703\u4e00\u500b\u81ea\u52d5\u5316\u6280\u5de7','\u66ff\u4f60\u6bcf\u5929\u7701\u4e0b\u6642\u9593','\u5c08\u6ce8\u771f\u6b63\u91cd\u8981\u7684\u4e8b'];return[{json:{title,caption,lines}}];"
},
"name": "Parse AI JSON",
"type": "n8n-nodes-base.function",
"typeVersion": 2,
"position": [
-980,
-20
]
},
{
"parameters": {
"functionCode": "const lines=$json.lines||[];const intro=3,outro=2,bodyMax=45-intro-outro;const n=Math.max(1,lines.length);const base=Math.floor(bodyMax/n);let leftover=bodyMax-base*n,t=intro;const plan=[];for(let i=0;i<n;i++){const dur=base+(leftover>0?1:0);if(leftover>0)leftover--;plan.push({text:String(lines[i]).trim(),start:t,length:dur});t+=dur;}return[{json:{...$json,intro,outro,plan}}];"
},
"name": "Build Timeline Plan",
"type": "n8n-nodes-base.function",
"typeVersion": 2,
"position": [
-800,
-20
]
},
{
"parameters": {
"functionCode": "const title=$json.title;const caption=$json.caption;const plan=$json.plan||[];const introClip={asset:{type:'title',text:title,style:'minimal'},start:0,length:$json.intro,position:'center',effect:'zoomIn'};const outroStart=plan.length?plan[plan.length-1].start+plan[plan.length-1].length:$json.intro;const outroClip={asset:{type:'title',text:'\u8ffd\u8e64\u7372\u5f97\u66f4\u591a AI \u5c0f\u6280\u5de7',style:'minimal'},start:outroStart,length:$json.outro,position:'center',effect:'zoomOut'};const textClips=plan.map(p=>({asset:{type:'title',text:p.text,style:'bold'},start:p.start,length:p.length,position:'bottom',effect:'fade'}));const bgClip={asset:{type:'solid',color:'#0e0f13'},start:0,length:45};const timeline={background:'#0e0f13',tracks:[{clips:[bgClip]},{clips:[introClip,...textClips,outroClip]}]};const body={timeline,output:{format:'mp4',aspectRatio:'9:16',resolution:'high'}};return[{json:{caption,shotstackBody:body}}];"
},
"name": "Shotstack Body",
"type": "n8n-nodes-base.function",
"typeVersion": 2,
"position": [
-620,
-20
]
},
{
"parameters": {
"authentication": "none",
"requestMethod": "POST",
"url": "https://api.shotstack.io/stage/render",
"jsonParameters": true,
"sendHeaders": true,
"headerParametersJson": "{\"x-api-key\":\"{{$env.SHOTSTACK_API_KEY}}\",\"Content-Type\":\"application/json\"}",
"bodyParametersJson": "={{ $json[\"shotstackBody\"] }}"
},
"name": "Shotstack - Render",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
-420,
-20
]
},
{
"parameters": {
"amount": 25,
"unit": "seconds"
},
"name": "Wait 25s",
"type": "n8n-nodes-base.wait",
"typeVersion": 1,
"position": [
-240,
-20
]
},
{
"parameters": {
"authentication": "none",
"requestMethod": "GET",
"url": "={{$json.response?.id ? 'https://api.shotstack.io/stage/render/' + $json.response.id : ''}}",
"jsonParameters": false,
"sendHeaders": true,
"headerParametersJson": "{\"x-api-key\":\"{{$env.SHOTSTACK_API_KEY}}\"}"
},
"name": "Shotstack - Poll",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
-60,
-20
]
},
{
"parameters": {
"functionCode": "const status=String($json.status||'').toLowerCase();const url=$json.url||$json.output?.url||'';if(status!=='done'||!url){return[{json:{ok:false,reason:'\u6e32\u67d3\u672a\u5b8c\u6210\u6216\u7121URL',status,url}}];}return[{json:{ok:true,videoUrl:url}}];"
},
"name": "Render Result",
"type": "n8n-nodes-base.function",
"typeVersion": 2,
"position": [
120,
-20
]
},
{
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{$json[\"ok\"]===true}}",
"value2": true
}
]
}
},
"name": "IF Render OK?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
300,
-20
]
},
{
"parameters": {
"authentication": "none",
"requestMethod": "POST",
"url": "https://graph.facebook.com/v20.0/{{$env.IG_USER_ID}}/media",
"jsonParameters": true,
"sendHeaders": true,
"headerParametersJson": "{\"Authorization\":\"Bearer {{$env.META_ACCESS_TOKEN}}\",\"Content-Type\":\"application/json\"}",
"bodyParametersJson": "{\"media_type\":\"VIDEO\",\"video_url\":\"{{$json.videoUrl}}\",\"caption\":\"{{$node[\\\"Shotstack Body\\\"].json.caption}}\"}"
},
"name": "IG - Create Container",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
520,
-100
]
},
{
"parameters": {
"amount": 5,
"unit": "seconds"
},
"name": "Wait 5s",
"type": "n8n-nodes-base.wait",
"typeVersion": 1,
"position": [
720,
-100
]
},
{
"parameters": {
"authentication": "none",
"requestMethod": "POST",
"url": "https://graph.facebook.com/v20.0/{{$env.IG_USER_ID}}/media_publish",
"jsonParameters": true,
"sendHeaders": true,
"headerParametersJson": "{\"Authorization\":\"Bearer {{$env.META_ACCESS_TOKEN}}\",\"Content-Type\":\"application/json\"}",
"bodyParametersJson": "{\"creation_id\":\"{{$node[\\\"IG - Create Container\\\"].json.id}}\"}"
},
"name": "IG - Publish",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
920,
-100
]
},
{
"parameters": {
"functionCode": "return[{json:{id:'auto-'+Date.now(),caption:$node[\"Shotstack Body\"].json.caption,videoUrl:$json.videoUrl,status:'sent',media_id:$node[\"IG - Publish\"].json.id||'',sentAt:new Date().toISOString(),notes:''}}];"
},
"name": "Build Log Row",
"type": "n8n-nodes-base.function",
"typeVersion": 2,
"position": [
1120,
60
]
},
{
"parameters": {
"operation": "append",
"sheetId": "={{$env.GSHEET_ID_IG}}",
"range": "ready!A:Z",
"fields": [
"id",
"caption",
"videoUrl",
"status",
"media_id",
"sentAt",
"notes"
]
},
"name": "Append Log",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 6,
"position": [
1320,
60
],
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"functionCode": "return[{json:{id:'auto-'+Date.now(),caption:$node[\"Shotstack Body\"].json.caption,videoUrl:'',status:'failed',media_id:'',sentAt:'',notes:$json.reason||'render_failed'}}];"
},
"name": "Build Fail Row",
"type": "n8n-nodes-base.function",
"typeVersion": 2,
"position": [
300,
140
]
},
{
"parameters": {
"operation": "append",
"sheetId": "={{$env.GSHEET_ID_IG}}",
"range": "ready!A:Z",
"fields": [
"id",
"caption",
"videoUrl",
"status",
"media_id",
"sentAt",
"notes"
]
},
"name": "Append Failed",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 6,
"position": [
520,
140
],
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
}
}
],
"connections": {
"Cron - 09:00": {
"main": [
[
{
"node": "AI - Script & Caption",
"type": "main",
"index": 0
}
]
]
},
"AI - Script & Caption": {
"main": [
[
{
"node": "Parse AI JSON",
"type": "main",
"index": 0
}
]
]
},
"Parse AI JSON": {
"main": [
[
{
"node": "Build Timeline Plan",
"type": "main",
"index": 0
}
]
]
},
"Build Timeline Plan": {
"main": [
[
{
"node": "Shotstack Body",
"type": "main",
"index": 0
}
]
]
},
"Shotstack Body": {
"main": [
[
{
"node": "Shotstack - Render",
"type": "main",
"index": 0
}
]
]
},
"Shotstack - Render": {
"main": [
[
{
"node": "Wait 25s",
"type": "main",
"index": 0
}
]
]
},
"Wait 25s": {
"main": [
[
{
"node": "Shotstack - Poll",
"type": "main",
"index": 0
}
]
]
},
"Shotstack - Poll": {
"main": [
[
{
"node": "Render Result",
"type": "main",
"index": 0
}
]
]
},
"Render Result": {
"main": [
[
{
"node": "IF Render OK?",
"type": "main",
"index": 0
}
]
]
},
"IF Render OK?": {
"main": [
[
{
"node": "IG - Create Container",
"type": "main",
"index": 0
}
],
[
{
"node": "Build Fail Row",
"type": "main",
"index": 0
}
]
]
},
"IG - Create Container": {
"main": [
[
{
"node": "Wait 5s",
"type": "main",
"index": 0
}
]
]
},
"Wait 5s": {
"main": [
[
{
"node": "IG - Publish",
"type": "main",
"index": 0
}
]
]
},
"IG - Publish": {
"main": [
[
{
"node": "Build Log Row",
"type": "main",
"index": 0
}
]
]
},
"Build Log Row": {
"main": [
[
{
"node": "Append Log",
"type": "main",
"index": 0
}
]
]
},
"Build Fail Row": {
"main": [
[
{
"node": "Append Failed",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"timezone": "Asia/Taipei"
},
"active": false
}
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.
googleSheetsOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
IG Reels - v3.0 (n8n 1.110.1). Uses httpRequest, googleSheets. Scheduled trigger; 17 nodes.
Source: https://gist.github.com/a84235908423590-sys/999cf234213cad068b1ce44462e5b630 — 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.
This workflow automates video distribution to 9 social platforms simultaneously using Blotato's API. It includes both a scheduled publisher (checks Google Sheets for videos marked "Ready") and a subwo
YogiAI. Uses googleSheets, googleSheetsTool, httpRequest, stopAndError. Scheduled trigger; 61 nodes.
This workflow monitors Google Calendar for events indicating that a customer will visit the company today or the next day, retrieves the required details, and sends reminder notifications to the relev
ofn hook v0.24.0 beta. Uses start, httpRequest, functionItem, itemLists. Scheduled trigger; 42 nodes.
Security teams, DevOps engineers, vulnerability analysts, and automation builders who want to eliminate repetitive Nessus scan parsing, AI-based risk triage, and manual reporting. Designed for orgs fo