A guide to understand, operate, and extend the workflow.
Goal: Turn a simple Airtable sheet into a content calendar that automatically publishes Instagram Reels via the Instagram Graph API, on a schedule you control in n8n.
Why this matters:
Core flow (one row = one post):
status = "To Post" AND scheduled_at <= NOW() AND platform = "IG"
.video_url
, caption
, recordId
.ig_media_id
, and timestamp.[Cron]
→ [Airtable: Search records]
→ [Split Out: records]
→ [Set: Map fields]
→ [IG: Create Media Container]
→ [Wait 90s]
→ [IG: Publish Reel]
→ [Airtable: Update record]
Sticky Notes inside the workflow explain each step (they’re rendered from parameters.content
with Markdown).
Create a table (e.g., Posts
) with these fields:
Field | Type | Purpose |
---|---|---|
video_url |
URL or Text | Directly accessible (public) URL to your MP4 |
caption |
Long text | Final caption (hashtags, line breaks, emojis) |
platform |
Single select | Set IG for this workflow |
status |
Single select | To Post → will be picked up; Posted later |
scheduled_at |
Date/Time (UTC) | When to post |
ig_media_id |
Text (optional) | Filled by n8n after publishing |
posted_at |
Date/Time | Filled by n8n after publishing |
Filter used in the Airtable “Search records” node:
AND({status}='To Post', {scheduled_at}<=NOW(), {platform}='IG')
Tip: If you localize/rename fields, update the filter accordingly.
IG_API_VERSION
(e.g., v21.0
)IG_USER_ID
IG_ACCESS_TOKEN
video_url
(e.g., S3/GCS signed URL, public CDN, Drive/Dropbox direct link). The API pulls from your URL; it cannot fetch files behind logins.search
AND({status}='To Post', {scheduled_at}<=NOW(), {platform}='IG')
records[]
. Each record
has id
and fields
.records[]
array into individual items.recordId
.recordId
= {{$json.id}}
video_url
= {{$json.fields.video_url}}
caption
= {{$json.fields.caption}}
scheduled_at
= {{$json.fields.scheduled_at}}
POST https://graph.facebook.com/{v}/{ig-user-id}/media
video_url
= {{$json.video_url}}
caption
= {{$json.caption}}
media_type=REELS
share_to_feed=true
(optional)access_token=${IG_ACCESS_TOKEN}
id
(this is your creation_id
for publishing).video_url
.120–180s
.POST https://graph.facebook.com/{v}/{ig-user-id}/media_publish
creation_id = {{$json.id}}
(the container id from step E)access_token = ${IG_ACCESS_TOKEN}
id
= ig_media_id (the published media).status = "Posted"
ig_media_id = {{$json.id}}
posted_at = {{$now}}
video_url
= a public MP4 URLcaption
= a small captionplatform
= IG
status
= To Post
scheduled_at
= in the past (so it’s due now)id
media id
Posted
with ig_media_id
and posted_at
status = To Post
, set accurate scheduled_at
in UTC.Backfilling:
If you need to post a bunch of older content, set scheduled_at
in the past for those rows and let Cron pick them up. If needed, run the workflow manually.