{
  "id": "MxHLOPQIt80lQZs8",
  "name": "Upload reels with AI caption from Google Sheets",
  "tags": [],
  "nodes": [
    {
      "id": "e9950b30-dae2-4bad-ae13-deff2f161f50",
      "name": "Generate Caption with DeepSeek",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1664,
        944
      ],
      "parameters": {
        "text": "=Generate an engaging Instagram caption for a video titled \"{{ $('Get Rows').item.json.NAME}}\" \n\nHere's what to include:\n- 2-4 engaging sentences about video based on title \n- 3-5 relevant hashtags based on the video title \n- A clear call-to-action encouraging to check link in bio.\n\nPlease keep the total caption under 150 characters.\n\nYou are skilled at writing clear, engaging, and detailed captions based on just a file name. Help viewers understand and appreciate the post. The tone should be relatable and suitable for an Instagram audience. Avoid using too many whimsical words or excessive adjectives. Focus on giving more details and facts to educate viewers.",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 2
    },
    {
      "id": "1bd06991-d24c-4dca-b450-4aad17d080a0",
      "name": "Store Caption in Airtable",
      "type": "n8n-nodes-base.airtable",
      "disabled": true,
      "position": [
        1984,
        944
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "id",
          "value": ""
        },
        "table": {
          "__rl": true,
          "mode": "id",
          "value": ""
        },
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "typecast": false
        },
        "operation": "create"
      },
      "typeVersion": 2.1
    },
    {
      "id": "3d2c8eb2-7c71-4507-b1be-3326a00ed31e",
      "name": "Publish Reel to Instagram",
      "type": "n8n-nodes-base.facebookGraphApi",
      "position": [
        3136,
        944
      ],
      "parameters": {
        "edge": "media_publish",
        "node": " ",
        "options": {
          "queryParameters": {
            "parameter": [
              {
                "name": "creation_id",
                "value": "={{ $json.id }}"
              }
            ]
          }
        },
        "graphApiVersion": "v22.0",
        "httpRequestMethod": "POST"
      },
      "typeVersion": 1
    },
    {
      "id": "55027c1f-90b6-4ef2-bc34-3b93eb8067d6",
      "name": "Check Video Processing Status",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2688,
        880
      ],
      "parameters": {
        "url": "=https://graph.facebook.com/v21.0/{{ $('Create container').item.json.id }}?fields=status_code,status",
        "options": {},
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "facebookGraphApi"
      },
      "typeVersion": 4.3
    },
    {
      "id": "e24bab82-84ae-48a9-a2e4-913471e70c80",
      "name": "Is Video Processed?",
      "type": "n8n-nodes-base.if",
      "position": [
        2912,
        944
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "8ab5eeec-4edd-4796-8f54-4c7cfccf99e9",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.status_code }}",
              "rightValue": "FINISHED"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "75cf6c86-22df-4230-852f-8d6840708542",
      "name": "Wait for Video Processing",
      "type": "n8n-nodes-base.wait",
      "position": [
        2464,
        944
      ],
      "parameters": {
        "amount": 90
      },
      "typeVersion": 1.1
    },
    {
      "id": "0b5e4fb5-e167-41b9-b6aa-98672c84d03b",
      "name": "Trigger: New Row in Sheet",
      "type": "n8n-nodes-base.googleSheetsTrigger",
      "disabled": true,
      "position": [
        96,
        848
      ],
      "parameters": {
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "typeVersion": 1
    },
    {
      "id": "53021691-af78-446e-9d1c-24f7fd9a45ac",
      "name": "Trigger: Every 12 Hours",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        96,
        1040
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 12
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "8369241c-2538-4c06-adac-b8a073457f28",
      "name": "DeepSeek Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatDeepSeek",
      "position": [
        1664,
        1232
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "12dde15e-f96c-4eb5-8851-3cdd4248cdcb",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "width": 640,
        "height": 624,
        "content": "# Upload reels with AI Caption from Google Sheets\n\nThis n8n workflow template automates the entire process of publishing Instagram Reels from content stored in Google Sheets and Google Drive. It's designed for content creators, social media managers, and businesses who maintain a content calendar in spreadsheets and need automated publishing with AI-generated captions.\n\n## How It Works\n\n1. **Trigger**: Runs every 12 hours (or when new rows are added)\n2. **Fetch Content**: Retrieves unposted videos from spreadsheet\n3. **Process Video**: Downloads from Drive and adds custom overlays with FFmpeg\n4. **Generate Caption**: Uses AI to create engaging Instagram captions\n5. **Publish**: Uploads to Instagram and marks as posted\n\n## Setup Steps\n\n- Configure Google Sheets connection and document ID\n- Set up Google Drive access for video files\n- Add Instagram/Facebook Graph API credentials\n- Optional: Configure SSH and Airtable for advanced features"
      },
      "typeVersion": 1
    },
    {
      "id": "fade781f-50de-47d9-b25d-6e9a9d5c618d",
      "name": "## 1. Trigger Phase",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -32,
        736
      ],
      "parameters": {
        "color": 7,
        "width": 352,
        "height": 496,
        "content": "## Runs every 12 hours or when new rows added to sheet"
      },
      "typeVersion": 1
    },
    {
      "id": "525aa3a1-1157-4cce-9f64-e2b6a71ca927",
      "name": "## 2. Content Preparation",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        336,
        784
      ],
      "parameters": {
        "color": 7,
        "width": 1112,
        "height": 400,
        "content": "## Download video \u2192 Save file \u2192 Process with FFmpeg \u2192 Load processed video \u2192 Upload via SSH"
      },
      "typeVersion": 1
    },
    {
      "id": "85fcc9c6-baad-4919-a8da-051839d333fa",
      "name": "## 3. Caption Generation",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1472,
        784
      ],
      "parameters": {
        "color": 7,
        "width": 688,
        "height": 400,
        "content": "## Generate AI caption with DeepSeek \u2192 Store in Airtable"
      },
      "typeVersion": 1
    },
    {
      "id": "43decc38-9a35-4963-9dd7-b63aad24849d",
      "name": "## 4. Publishing",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2192,
        784
      ],
      "parameters": {
        "color": 7,
        "width": 1096,
        "height": 400,
        "content": "## Create media container \u2192 Wait \u2192 Check status \u2192 Publish to Instagram"
      },
      "typeVersion": 1
    },
    {
      "id": "6fd42f41-81cd-40d6-b74c-20e467b7bd1c",
      "name": "## 5. Cleanup",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3312,
        784
      ],
      "parameters": {
        "color": 7,
        "width": 394,
        "height": 400,
        "content": "## Mark as posted and clean videos"
      },
      "typeVersion": 1
    },
    {
      "id": "34573a90-81bb-4815-ac25-d3d1f26a27dc",
      "name": "Process Video with FFmpeg",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        1024,
        944
      ],
      "parameters": {
        "command": "=ffmpeg -y -i /data/{{ $execution.id }}_input.mp4 -vf \"scale=1080:1920\" -c:v libx264 -pix_fmt yuv420p /data/{{ $execution.id }}_output.mp4"
      },
      "typeVersion": 1
    },
    {
      "id": "6be11af9-8b93-4e99-b3ed-4c2808921b16",
      "name": "Upload to Server via SSH",
      "type": "n8n-nodes-base.ssh",
      "position": [
        1504,
        944
      ],
      "parameters": {
        "path": "/var/www/html/uploads/",
        "options": {},
        "resource": "file",
        "authentication": "privateKey"
      },
      "credentials": {
        "sshPrivateKey": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "fbbf2f09-f739-4ddc-90c2-e4b905859a63",
      "name": "Fetch Unposted Videos",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        384,
        944
      ],
      "parameters": {
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": ""
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "6db65556-dd93-406b-943d-bceba78faea7",
      "name": "Download Video from Drive",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        592,
        944
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "url",
          "value": "={{ $json.LINK }}"
        },
        "options": {},
        "operation": "download"
      },
      "typeVersion": 3
    },
    {
      "id": "21ad8e54-2a54-4b48-9865-7bb55193cf3f",
      "name": "Save Downloaded File",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        816,
        944
      ],
      "parameters": {
        "options": {},
        "fileName": "=/tmp/{{ $execution.id }}_input.mp4",
        "operation": "write"
      },
      "typeVersion": 1
    },
    {
      "id": "ac69610f-d43a-4ebf-94b1-33e7a85191eb",
      "name": "Load Processed Video",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        1264,
        944
      ],
      "parameters": {
        "options": {},
        "fileSelector": "=/tmp/{{ $execution.id }}_output.mp4"
      },
      "typeVersion": 1
    },
    {
      "id": "f31d0794-fd0a-4b1b-9487-0322a25b4aa5",
      "name": "Create Instagram Media Container",
      "type": "n8n-nodes-base.facebookGraphApi",
      "position": [
        2240,
        944
      ],
      "parameters": {
        "edge": "media",
        "node": " ",
        "hostUrl": "graph-video.facebook.com",
        "options": {
          "queryParameters": {
            "parameter": [
              {
                "name": "media_type",
                "value": "REELS"
              },
              {
                "name": "caption",
                "value": "={{ $('AI Agent').item.json.output }}"
              }
            ]
          }
        },
        "graphApiVersion": "v22.0",
        "httpRequestMethod": "POST"
      },
      "typeVersion": 1
    },
    {
      "id": "4ddb4cbd-0d0a-4f2d-a9a2-9a4fb76e18d6",
      "name": "Mark as Posted",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3328,
        944
      ],
      "parameters": {
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": ""
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": ""
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "5430a5a9-f8e9-48e3-9794-8de5c8b3fdb5",
      "name": "Execute a command",
      "type": "n8n-nodes-base.ssh",
      "position": [
        3552,
        944
      ],
      "parameters": {
        "command": "rm -f /var/www/html/uploads/*",
        "authentication": "privateKey"
      },
      "credentials": {
        "sshPrivateKey": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "54560e78-454f-4692-8f61-1cd8886370e0",
  "connections": {
    "Mark as Posted": {
      "main": [
        [
          {
            "node": "Execute a command",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DeepSeek Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Generate Caption with DeepSeek",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Is Video Processed?": {
      "main": [
        [
          {
            "node": "Publish Reel to Instagram",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait for Video Processing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Load Processed Video": {
      "main": [
        [
          {
            "node": "Upload to Server via SSH",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Downloaded File": {
      "main": [
        [
          {
            "node": "Process Video with FFmpeg",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Unposted Videos": {
      "main": [
        [
          {
            "node": "Download Video from Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Trigger: Every 12 Hours": {
      "main": [
        [
          {
            "node": "Fetch Unposted Videos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload to Server via SSH": {
      "main": [
        [
          {
            "node": "Generate Caption with DeepSeek",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Video from Drive": {
      "main": [
        [
          {
            "node": "Save Downloaded File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Video with FFmpeg": {
      "main": [
        [
          {
            "node": "Load Processed Video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Publish Reel to Instagram": {
      "main": [
        [
          {
            "node": "Mark as Posted",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Store Caption in Airtable": {
      "main": [
        [
          {
            "node": "Create Instagram Media Container",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Trigger: New Row in Sheet": {
      "main": [
        [
          {
            "node": "Fetch Unposted Videos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Video Processing": {
      "main": [
        [
          {
            "node": "Check Video Processing Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Video Processing Status": {
      "main": [
        [
          {
            "node": "Is Video Processed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Caption with DeepSeek": {
      "main": [
        [
          {
            "node": "Store Caption in Airtable",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Instagram Media Container": {
      "main": [
        [
          {
            "node": "Wait for Video Processing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}