AutomationFlowsData & Sheets › Ig Publish

Ig Publish

05-ig-publish. Uses supabase, httpRequest. Scheduled trigger; 13 nodes.

Cron / scheduled trigger★★★★☆ complexity13 nodesSupabaseHTTP Request
Data & Sheets Trigger: Cron / scheduled Nodes: 13 Complexity: ★★★★☆ Added:

This workflow follows the HTTP Request → Supabase 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
{
  "name": "05-ig-publish",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "*/10 * * * *"
            }
          ]
        }
      },
      "id": "cron-trigger",
      "name": "Cron Trigger (every 10 min)",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "select * from next_reel_to_publish()"
      },
      "id": "next-reel",
      "name": "Supabase: next_reel_to_publish()",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        200,
        0
      ],
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "number": [
            {
              "value1": "={{ $items().length }}",
              "value2": 0,
              "operation": "equal"
            }
          ]
        }
      },
      "id": "if-no-rows",
      "name": "IF: No Rows",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        400,
        0
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "select token from api_tokens where id = 'ig_long_lived' limit 1"
      },
      "id": "load-token",
      "name": "Load IG Token",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        600,
        -100
      ],
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "url": "=https://graph.facebook.com/v21.0/{{ $env.IG_BUSINESS_ACCOUNT_ID }}/media",
        "method": "POST",
        "sendBody": true,
        "bodyContentType": "json",
        "body": {
          "media_type": "REELS",
          "video_url": "={{ $('Supabase: next_reel_to_publish()').item.json.final_reel_url }}",
          "caption": "={{ $('Supabase: next_reel_to_publish()').item.json.caption + '\\n\\n' + ($('Supabase: next_reel_to_publish()').item.json.hashtags ?? []).join(' ') }}",
          "access_token": "={{ $('Load IG Token').item.json.token }}"
        }
      },
      "id": "create-container",
      "name": "Create Media Container",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        800,
        -100
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "amount": 15,
        "unit": "seconds"
      },
      "id": "wait-15",
      "name": "Wait 15s",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        1000,
        -100
      ]
    },
    {
      "parameters": {
        "url": "=https://graph.facebook.com/v21.0/{{ $('Create Media Container').item.json.id }}",
        "method": "GET",
        "sendQueryParameters": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "fields",
              "value": "status_code"
            },
            {
              "name": "access_token",
              "value": "={{ $('Load IG Token').item.json.token }}"
            }
          ]
        }
      },
      "id": "poll-container",
      "name": "Poll Container Status",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1200,
        -100
      ]
    },
    {
      "parameters": {
        "jsCode": "// Track attempts per container. Bail at 20 attempts (~5 min @ 15s).\nconst containerId = $('Create Media Container').item.json.id;\nconst status = $input.first().json.status_code ?? 'UNKNOWN';\nconst data = $getWorkflowStaticData('node');\nconst key = `ig_${containerId}`;\nconst attempts = (data[key] ?? 0) + 1;\ndata[key] = attempts;\n\nif (status === 'FINISHED') {\n  delete data[key];\n  return [[{ json: { status, attempts, containerId } }], [], []];\n}\nif (status === 'ERROR') {\n  delete data[key];\n  return [[], [], [{ json: { status, attempts, containerId, reason: 'ig_container_error' } }]];\n}\nif (attempts >= 20) {\n  delete data[key];\n  return [[], [], [{ json: { status, attempts, containerId, reason: 'timeout_5min' } }]];\n}\nreturn [[], [{ json: { status, attempts, containerId } }], []];"
      },
      "id": "branch-container",
      "name": "Branch Container Status",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1400,
        -100
      ]
    },
    {
      "parameters": {
        "url": "=https://graph.facebook.com/v21.0/{{ $env.IG_BUSINESS_ACCOUNT_ID }}/media_publish",
        "method": "POST",
        "sendBody": true,
        "bodyContentType": "json",
        "body": {
          "creation_id": "={{ $('Create Media Container').item.json.id }}",
          "access_token": "={{ $('Load IG Token').item.json.token }}"
        }
      },
      "id": "publish-reel",
      "name": "Publish Reel",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1600,
        -200
      ]
    },
    {
      "parameters": {
        "operation": "update",
        "schema": "public",
        "table": "reels_queue",
        "filters": {
          "conditions": [
            {
              "keyName": "id",
              "condition": "eq",
              "keyValue": "={{ $('Supabase: next_reel_to_publish()').item.json.id }}"
            }
          ]
        },
        "fieldsToSend": "defineBelow",
        "dataToSend": {
          "values": [
            {
              "fieldId": "status",
              "fieldValue": "posted"
            },
            {
              "fieldId": "posted_at",
              "fieldValue": "={{ $now.toISOString() }}"
            },
            {
              "fieldId": "ig_media_id",
              "fieldValue": "={{ $json.id }}"
            }
          ]
        }
      },
      "id": "supabase-posted",
      "name": "Supabase Update (posted)",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        1800,
        -200
      ],
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "url": "={{ $env.ALERT_WEBHOOK_URL }}",
        "method": "POST",
        "sendBody": true,
        "bodyContentType": "json",
        "body": {
          "content": "\u2705 **Posted**: {{ $('Supabase: next_reel_to_publish()').item.json.hook }}\nhttps://www.instagram.com/reel/{{ $('Publish Reel').item.json.id }}"
        }
      },
      "id": "notify-posted",
      "name": "Notify Posted",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2000,
        -200
      ]
    },
    {
      "parameters": {
        "url": "={{ $env.ALERT_WEBHOOK_URL }}",
        "method": "POST",
        "sendBody": true,
        "bodyContentType": "json",
        "body": {
          "content": "\ud83d\udea8 **IG create-container FAILED** for reel `{{ $('Supabase: next_reel_to_publish()').item.json.id }}` ({{ $('Supabase: next_reel_to_publish()').item.json.hook }}). Reel stays `ready`; next cron will retry.\nError: {{ $json.error ?? JSON.stringify($json) }}"
        }
      },
      "id": "alert-container-failed",
      "name": "Alert: Container Create Failed",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1000,
        100
      ]
    },
    {
      "parameters": {
        "url": "={{ $env.ALERT_WEBHOOK_URL }}",
        "method": "POST",
        "sendBody": true,
        "bodyContentType": "json",
        "body": {
          "content": "\u26a0\ufe0f **IG container timeout/error** for reel `{{ $('Supabase: next_reel_to_publish()').item.json.id }}` (status={{ $json.status }}, reason={{ $json.reason }}). Reel stays `ready`; next cron retries."
        }
      },
      "id": "alert-container-timeout",
      "name": "Alert: Container Timeout",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1600,
        100
      ]
    }
  ],
  "connections": {
    "Cron Trigger (every 10 min)": {
      "main": [
        [
          {
            "node": "Supabase: next_reel_to_publish()",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase: next_reel_to_publish()": {
      "main": [
        [
          {
            "node": "IF: No Rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: No Rows": {
      "main": [
        [],
        [
          {
            "node": "Load IG Token",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Load IG Token": {
      "main": [
        [
          {
            "node": "Create Media Container",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Media Container": {
      "main": [
        [
          {
            "node": "Wait 15s",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Alert: Container Create Failed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 15s": {
      "main": [
        [
          {
            "node": "Poll Container Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Poll Container Status": {
      "main": [
        [
          {
            "node": "Branch Container Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Branch Container Status": {
      "main": [
        [
          {
            "node": "Publish Reel",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait 15s",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Alert: Container Timeout",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Publish Reel": {
      "main": [
        [
          {
            "node": "Supabase Update (posted)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase Update (posted)": {
      "main": [
        [
          {
            "node": "Notify Posted",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {},
  "staticData": null,
  "tags": [
    "reels-automation"
  ],
  "triggerCount": 1,
  "updatedAt": "2026-04-18T00:00:00.000Z",
  "versionId": "2"
}

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

05-ig-publish. Uses supabase, httpRequest. Scheduled trigger; 13 nodes.

Source: https://github.com/ksksrbiz-arch/reels-automation/blob/37630734bcd00a9986c9c64b4c4cdcc31014993d/n8n-workflows/05-ig-publish.json — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

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

Data & Sheets

This workflow ingests job postings from Greenhouse/Lever/Ashby job boards, Adzuna, and RemoteOK into a Supabase jobs pool, then daily uses Anthropic Claude to score a short list against a single candi

HTTP Request, Supabase, Resend +1
Data & Sheets

This workflow solves a common problem with RSS feeds: they often only provide a short summary or snippet of the full article. This template automatically monitors a list of your favorite blog RSS feed

HTTP Request, RSS Feed Read, Supabase
Data & Sheets

This workflow is a multi-system document synchronization pipeline built in n8n, designed to automatically sync and back up files between Microsoft SharePoint, Supabase/Postgres, and Google Drive.

HTTP Request, Supabase, Postgres +1
Data & Sheets

03 - Recordatorio 4h (CON VERIFICACIÓN) ✅. Uses supabase, httpRequest, twilio. Scheduled trigger; 17 nodes.

Supabase, HTTP Request, Twilio
Data & Sheets

02 - Recordatorio 24h antes (CON VERIFICACIÓN) ✅. Uses supabase, httpRequest, twilio. Scheduled trigger; 17 nodes.

Supabase, HTTP Request, Twilio