This workflow corresponds to n8n.io template #14595 — we link there as the canonical source.
This workflow follows the Airtable → 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 →
{
"nodes": [
{
"id": "e2c7ef94-f917-4ac0-8553-68ed48d514af",
"name": "Sticky \u2014 Webhook + Normalize",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1104,
1824
],
"parameters": {
"color": 7,
"width": 688,
"height": 740,
"content": "Webhook Trigger: Listens for POST payloads (Shopify, Airtable, or manual). It uses a Webhook Respond node to immediately return a 200 ACK, preventing timeout errors from the sender.\n\nSet (Normalize Fields): Sanitizes raw data into a consistent schema. It maps nested fields (e.g., Shopify\u2019s body.title) to flat variables, applies fallback defaults for missing captions/hashtags, and pulls the ig_account_id from environment variables if the payload is empty."
},
"typeVersion": 1
},
{
"id": "864aab29-bfa0-4ca8-a487-d67b1948c65e",
"name": "Sticky \u2014 Fetch + Upload",
"type": "n8n-nodes-base.stickyNote",
"position": [
-336,
1824
],
"parameters": {
"color": 7,
"width": 518,
"height": 472,
"content": "HTTP \u2014 Fetch Product Image: Downloads the image from image_url as a binary file (imageData). It supports any public source, including Shopify CDNs or S3 buckets.\n\nUpload to URL: Uploads the binary to a media host and returns a public CDN URL."
},
"typeVersion": 1
},
{
"id": "4984fd3c-c727-49b8-b6e1-699e6bf7d750",
"name": "Sticky \u2014 Caption + Container",
"type": "n8n-nodes-base.stickyNote",
"position": [
240,
1840
],
"parameters": {
"color": 7,
"width": 624,
"height": 380,
"content": "Code \u2014 Build Caption: Assembles the final text using the product name, price, and links. It automatically truncates to 2,200 characters to meet Instagram\u2019s API limits and outputs a single final_caption string.\n\nIG \u2014 Create Media Container: Initiates the first half of Instagram\u2019s two-step publishing flow. It sends the image_url and final_caption to the Graph API, which processes the image asynchronously and returns a container_id."
},
"typeVersion": 1
},
{
"id": "aff2900c-09af-4369-8133-b2bb7f347f30",
"name": "Sticky \u2014 Wait + Publish",
"type": "n8n-nodes-base.stickyNote",
"position": [
960,
1840
],
"parameters": {
"color": 7,
"width": 576,
"height": 396,
"content": "Wait (5s Buffer): Pauses the workflow to ensure Instagram completes its asynchronous image processing. For high-resolution files, this can be extended or replaced with a status-check polling loop.\n\nIG \u2014 Publish Container: Executes the final media_publish call using the container_id. Once successful, Instagram returns a Live Post ID, confirming the content is officially on the feed."
},
"typeVersion": 1
},
{
"id": "91928124-30f5-4fd0-a9fa-c6ba9d35b7d0",
"name": "Sticky \u2014 Log + Notify",
"type": "n8n-nodes-base.stickyNote",
"position": [
1584,
1840
],
"parameters": {
"color": 7,
"width": 736,
"height": 384,
"content": "Airtable \u2014 Log Post: Records the Post ID, product name, and timestamp into a tracking base for audits and analytics. Easily swappable with Google Sheets.\n\nSlack \u2014 Notify Team: Sends a formatted alert confirming the post is live. Includes the live link and trigger source. Can be replaced with Email or Discord nodes as needed."
},
"typeVersion": 1
},
{
"id": "3e9bb439-0467-407e-acec-84096aa3d3ba",
"name": "\ud83d\udccb Template Overview1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2000,
1088
],
"parameters": {
"width": 708,
"height": 724,
"content": "## \ud83d\udce6 Brand Product Drop \u2014 Single Image Scheduler\n\n**What this workflow does:**\nAutomates the full Instagram product announcement pipeline \u2014 from a new product trigger (Shopify, Airtable, or manual webhook) all the way to a published Instagram post with a structured caption and hashtag block.\n\n**Flow Overview:**\n1. \ud83d\udd14 **Webhook Trigger** \u2014 Receives product data (name, image URL, price, hashtags, caption intro)\n2. \ud83e\uddf9 **Set / Normalize Fields** \u2014 Cleans and structures the incoming payload into consistent fields\n3. \ud83c\udf10 **Fetch Product Image** \u2014 Downloads the raw image binary from the external product image URL\n4. \u2601\ufe0f **Upload to URL** \u2014 Uploads the image binary and returns a public CDN URL\n5. \u270d\ufe0f **Build Caption** \u2014 Constructs a brand-ready caption with emoji, price, CTA, and hashtag block\n6. \ud83d\udcf8 **IG: Create Media Container** \u2014 Calls Instagram Graph API to create a media container using the public image URL\n7. \u23f3 **Wait** \u2014 Pauses 5 seconds to allow Instagram to process the media container\n8. \u2705 **IG: Publish Container** \u2014 Publishes the approved container to the Instagram feed\n9. \ud83d\udcca **Log to Airtable** \u2014 Records post ID, timestamp, caption, and image URL for tracking\n10. \ud83d\udd14 **Notify via Slack** \u2014 Sends a confirmation message with the published post details\n\n**Prerequisites:**\n- Instagram Graph API access token (Business or Creator account)\n- Instagram Business Account ID\n- uploadtourl node credentials configured in n8n\n- (Optional) Airtable API key + Base ID for post logging\n- (Optional) Slack API credentials for team notifications\n\n**Supported Trigger Sources:**\n- Shopify `products/create` webhook\n- Airtable automation webhook\n- Manual HTTP POST for testing"
},
"typeVersion": 1
},
{
"id": "86e26a7e-4da6-4ad7-b3d7-caa2ef228265",
"name": "Webhook \u2014 Product Trigger1",
"type": "n8n-nodes-base.webhook",
"position": [
-1040,
2016
],
"parameters": {
"path": "product-drop",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "b4b02df3-5716-4752-91c1-729a7f9745d0",
"name": "Webhook Response1",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
-912,
2400
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={ \"status\": \"received\", \"message\": \"Product drop workflow triggered successfully\" }"
},
"typeVersion": 1
},
{
"id": "d2efad45-7d2d-475f-99c1-a345b9761495",
"name": "Set \u2014 Normalize Fields1",
"type": "n8n-nodes-base.set",
"position": [
-656,
2016
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "f1",
"name": "product_name",
"type": "string",
"value": "={{ $json.body.product_name ?? $json.body.title ?? 'New Product' }}"
},
{
"id": "f2",
"name": "image_url",
"type": "string",
"value": "={{ $json.body.image_url ?? $json.body.images?.[0]?.src ?? '' }}"
},
{
"id": "f3",
"name": "price",
"type": "string",
"value": "={{ $json.body.price ?? $json.body.variants?.[0]?.price ?? '' }}"
},
{
"id": "f4",
"name": "caption_intro",
"type": "string",
"value": "={{ $json.body.caption_intro ?? 'Something new just dropped.' }}"
},
{
"id": "f5",
"name": "hashtags",
"type": "string",
"value": "={{ $json.body.hashtags ?? '#newdrop #product #brand' }}"
},
{
"id": "f6",
"name": "ig_account_id",
"type": "string",
"value": "={{ $json.body.ig_account_id ?? $env.IG_ACCOUNT_ID }}"
},
{
"id": "f7",
"name": "trigger_source",
"type": "string",
"value": "={{ $json.body.source ?? 'webhook' }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "a2ac043b-f271-418e-aaad-908f1c8f7d73",
"name": "HTTP \u2014 Fetch Product Image1",
"type": "n8n-nodes-base.httpRequest",
"position": [
-256,
2016
],
"parameters": {
"url": "={{ $json.image_url }}",
"options": {
"response": {
"response": {
"responseFormat": "file",
"outputPropertyName": "imageData"
}
}
}
},
"typeVersion": 4.2
},
{
"id": "ba514950-4bae-4010-a35b-4b11a57cea78",
"name": "Code \u2014 Build Caption1",
"type": "n8n-nodes-base.code",
"position": [
304,
2016
],
"parameters": {
"jsCode": "const item = $input.item.json;\nconst norm = $('Set \u2014 Normalize Fields1').item.json;\n\nconst productName = norm.product_name || 'New Drop';\nconst price = norm.price ? `\ud83d\udcb0 ${norm.price}` : '';\nconst captionIntro = norm.caption_intro || 'Something new just dropped.';\nconst hashtags = norm.hashtags || '#newdrop';\n\nconst lines = [\n captionIntro,\n '',\n `\ud83d\udecd\ufe0f ${productName}`,\n price,\n '',\n '\ud83d\udc49 Link in bio to shop now.',\n '.',\n '.',\n '.',\n hashtags\n].filter(l => l !== undefined && l !== null);\n\nlet finalCaption = lines.join('\\n');\n\nif (finalCaption.length > 2200) {\n finalCaption = finalCaption.substring(0, 2196) + '...';\n}\n\nreturn {\n ...item,\n final_caption: finalCaption,\n public_image_url: item.public_url || item.url || item.file_url || item.cdn_url\n};"
},
"typeVersion": 2
},
{
"id": "15aae634-3e02-4adb-826e-e7b9edeab8cf",
"name": "IG \u2014 Create Media Container1",
"type": "n8n-nodes-base.httpRequest",
"position": [
576,
2016
],
"parameters": {
"url": "=https://graph.facebook.com/v19.0/{{ $('Set \u2014 Normalize Fields1').item.json.ig_account_id }}/media",
"method": "POST",
"options": {},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "image_url",
"value": "={{ $json.public_image_url }}"
},
{
"name": "caption",
"value": "={{ $json.final_caption }}"
},
{
"name": "access_token",
"value": "={{ $credentials.instagramGraphApi.accessToken }}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "58cd9531-c677-47e6-a5ee-eeb226809ee8",
"name": "Wait \u2014 5s Processing Buffer1",
"type": "n8n-nodes-base.wait",
"position": [
1024,
2016
],
"parameters": {
"unit": "seconds",
"amount": 5
},
"typeVersion": 1
},
{
"id": "96b03332-c1ba-4e97-8448-038836efdaa1",
"name": "IG \u2014 Publish Container1",
"type": "n8n-nodes-base.httpRequest",
"position": [
1344,
2016
],
"parameters": {
"url": "=https://graph.facebook.com/v19.0/{{ $('Set \u2014 Normalize Fields1').item.json.ig_account_id }}/media_publish",
"method": "POST",
"options": {},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "creation_id",
"value": "={{ $('IG \u2014 Create Media Container1').item.json.id }}"
},
{
"name": "access_token",
"value": "={{ $credentials.instagramGraphApi.accessToken }}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "d1c572eb-4e70-4938-8daa-ec2e6bf8d2ec",
"name": "Airtable \u2014 Log Post1",
"type": "n8n-nodes-base.airtable",
"position": [
1664,
2016
],
"parameters": {
"base": {
"__rl": true,
"mode": "id",
"value": "={{ $env.AIRTABLE_BASE_ID }}"
},
"table": {
"__rl": true,
"mode": "name",
"value": "IG Post Log"
},
"columns": {
"value": {
"Status": "Published",
"Caption": "={{ $('Code \u2014 Build Caption1').item.json.final_caption }}",
"Post ID": "={{ $('IG \u2014 Publish Container1').item.json.id }}",
"Image URL": "={{ $('Code \u2014 Build Caption1').item.json.public_image_url }}",
"Product Name": "={{ $('Set \u2014 Normalize Fields1').item.json.product_name }}",
"Published At": "={{ new Date().toISOString() }}",
"Trigger Source": "={{ $('Set \u2014 Normalize Fields1').item.json.trigger_source }}"
},
"schema": [],
"mappingMode": "defineBelow",
"matchingColumns": []
},
"options": {},
"operation": "create"
},
"typeVersion": 2.1
},
{
"id": "b112898f-c983-4126-b2f1-21d420d2d1a8",
"name": "Slack \u2014 Notify Team1",
"type": "n8n-nodes-base.slack",
"position": [
2128,
2016
],
"parameters": {
"select": "channel",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $env.SLACK_CHANNEL_ID }}"
},
"otherOptions": {}
},
"typeVersion": 2.3
},
{
"id": "ff9789d6-0c7a-4d4d-aa7a-43e1add05b8c",
"name": "Upload a File",
"type": "n8n-nodes-uploadtourl.uploadToUrl",
"position": [
0,
2016
],
"parameters": {},
"credentials": {
"uploadToUrlApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
}
],
"connections": {
"Upload a File": {
"main": [
[
{
"node": "Code \u2014 Build Caption1",
"type": "main",
"index": 0
}
]
]
},
"Airtable \u2014 Log Post1": {
"main": [
[
{
"node": "Slack \u2014 Notify Team1",
"type": "main",
"index": 0
}
]
]
},
"Code \u2014 Build Caption1": {
"main": [
[
{
"node": "IG \u2014 Create Media Container1",
"type": "main",
"index": 0
}
]
]
},
"IG \u2014 Publish Container1": {
"main": [
[
{
"node": "Airtable \u2014 Log Post1",
"type": "main",
"index": 0
}
]
]
},
"Set \u2014 Normalize Fields1": {
"main": [
[
{
"node": "HTTP \u2014 Fetch Product Image1",
"type": "main",
"index": 0
}
]
]
},
"Webhook \u2014 Product Trigger1": {
"main": [
[
{
"node": "Webhook Response1",
"type": "main",
"index": 0
},
{
"node": "Set \u2014 Normalize Fields1",
"type": "main",
"index": 0
}
]
]
},
"HTTP \u2014 Fetch Product Image1": {
"main": [
[
{
"node": "Upload a File",
"type": "main",
"index": 0
}
]
]
},
"IG \u2014 Create Media Container1": {
"main": [
[
{
"node": "Wait \u2014 5s Processing Buffer1",
"type": "main",
"index": 0
}
]
]
},
"Wait \u2014 5s Processing Buffer1": {
"main": [
[
{
"node": "IG \u2014 Publish Container1",
"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.
uploadToUrlApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
📦 Automated Instagram Product Drop via uploadtourl
Source: https://n8n.io/workflows/14595/ — 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.
Convert your customer satisfaction into high-converting social media content with this fully automated social proof pipeline. This workflow scans your database for top-tier reviews, generates a brande
Automate your entire Instagram carousel publishing pipeline from a single webhook call. This workflow receives a product collection payload, loops through each slide image, uploads every asset via Upl
This workflow captures buying-signal leads via a webhook (or optionally polls a HubSpot list), generates a personalized LinkedIn intro and follow-up sequence with Twain, and posts the ready-to-send dr
Automate your post-event Instagram carousel using a fan-out and merge pattern. One Code node splits the photos array into individual n8n items. Every photo then flows through HTTP Fetch, Upload to URL
This workflow automates the post-publish process for YouTube videos, combining advanced SEO optimization, cross-platform promotion, and analytics reporting. It is designed for creators, marketers, and