This workflow corresponds to n8n.io template #9694 — we link there as the canonical source.
This workflow follows the Datatable → 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": "c5c56fa4-6410-45eb-bc41-c61363f538e5",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-672,
48
],
"parameters": {
"width": 464,
"height": 576,
"content": "### Instagram Auto-Publisher (Lightroom \u2192 IG)\n\n**Purpose** \nPick the next unposted photo from **Photos**, build a caption from **ALT + EXIF**, publish via **Instagram Graph API**, then mark it as posted.\n\n**Must-configure**\n- **IG setup:** Instagram **Business/Creator** linked to a **Facebook Page** (Graph API **v23.0**, **long-lived** token).\n- **n8n domain:** Publicly reachable base URL for the Lightroom image webhook.\n- **Lightroom IDs:** Your **LR catalog ID** and asset IDs available in the data table.\n- **Data Table (Photos) columns:** `lr_asset_id`, `alt`, `lr_asset`, `ig_posted_at`, `ig_id`, `ig_caption`.\n- **LLM credentials:** Anthropic (or equivalent) for caption generation.\n- **Selection rule:** Filter rows where **`ig_posted_at` is empty** (only unposted).\n- **Posting cap:** Set your **max posts per run** (the Limit node value).\n- **Schedule:** Your preferred **times/cron** for auto-publishing.\n- **Params node**"
},
"typeVersion": 1
},
{
"id": "1ca855b3-27be-4a12-8c76-dffaef453109",
"name": "Get row(s)",
"type": "n8n-nodes-base.dataTable",
"position": [
-448,
912
],
"parameters": {
"filters": {
"conditions": [
{
"keyName": "ig_posted_at",
"condition": "isEmpty"
}
]
},
"matchType": "allConditions",
"operation": "get",
"returnAll": true,
"dataTableId": {
"__rl": true,
"mode": "list",
"value": "Z4VvX6MjrmHmlAiY",
"cachedResultUrl": "/projects/wrMsdivh0K45jnU5/datatables/Z4VvX6MjrmHmlAiY",
"cachedResultName": "Photos"
}
},
"typeVersion": 1
},
{
"id": "4f8f87b3-7105-4799-96b7-1efcea307fba",
"name": "Sort",
"type": "n8n-nodes-base.sort",
"position": [
-224,
912
],
"parameters": {
"options": {},
"sortFieldsUi": {
"sortField": [
{
"fieldName": "createdAt"
}
]
}
},
"typeVersion": 1
},
{
"id": "e19763a7-714c-4de8-8259-544313f3eb95",
"name": "Limit",
"type": "n8n-nodes-base.limit",
"position": [
0,
912
],
"parameters": {},
"typeVersion": 1
},
{
"id": "92b9bb0a-98eb-4e47-94d9-51ff3ed79af5",
"name": "Message a model",
"type": "@n8n/n8n-nodes-langchain.anthropic",
"position": [
432,
912
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "claude-sonnet-4-5-20250929",
"cachedResultName": "claude-sonnet-4-5-20250929"
},
"options": {},
"messages": {
"values": [
{
"content": "=**ROLE** \nYou write an Instagram caption from ALT text and EXIF metadata. Optimize for search and engagement **without inventing** anything.\n\n**INPUTS** \n- `ALT`: {{ $('Limit').item.json.alt }} \n- `EXIF (JSON or text)`: {{ JSON.stringify(JSON.parse($json.lr_asset).payload) }}\n\n**GOAL** \nProduce **exactly 3 lines** under **220 total characters** (line breaks included): \n1) **Action phrase (-ing) + brief outcome**; include **1\u20132 intent terms** from ALT if present (e.g., \u201cportrait\u201d, \u201clong exposure\u201d). **Max 12 words.** \n2) **Gear & settings** on one line with an en dash: \n `<CameraModel> + <Lens> \u2014 <Shutter> \u00b7 f/<Aperture> \u00b7 ISO <ISO> \u00b7 WB <KelvinIfKnown>` \n - Use EXIF fields **only if present**: make/cameraModel, lensModel, focalLength and FocalLengthIn35mmFilm, fNumber, exposureTime, iso, whiteBalance (Kelvin or \u201cAuto\u201d). \n - If focal length exists but not in lens name, **prefix it** (e.g., `35/1.8`). Display FocalLengthIn35mmFilm too (format: \"(28 mm eq. 35 mm)\")\n - Format shutter `1/250s`; aperture `f/1.8`. \n - Missing field? **Omit** it. **No inference.**\n3) **5\u201310 hashtags** (lowercase, **deduped**) using layered strategy: \n - **Broad:** always `#photography` + **one** brand/lens tag if present (e.g., `#fujifilm #fujifilmxseries\n #fujilove`, `#xe5`). \n - **Mid-tail:** 1\u20133 subject/genre from ALT (e.g., `#portrait`, `#streetphotography`). \n - **Niche:** 1\u20132 specific technique/gear terms from ALT/EXIF. \n - **Location:** add 1\u20132 only if GPS/city exists in EXIF (e.g., `#paris`, `#montmartre`).\n - **Mentions:** if the EXIF description/caption/title/userComment contains Instagram-style mentions (e.g., `@name`), **append them verbatim at the end of line 3 after the hashtags**. Deduplicate; do not invent; preserve exact handles. If the 220-character limit is exceeded, **remove niche hashtags first**, then mid-tail if needed, but keep mentions.\n\n\n**STYLE & SEO RULES** \n- English only. Human, concise, non-salesy. \n- No emojis unless clearly in ALT. No quotes. **No trailing spaces.** \n- **Zero inference:** do not assert people/brands/places/conditions not in ALT/EXIF. \n- **Deduplicate intelligently:** avoid repeating the exact same keyword in line 1 and hashtags if it reduces variety; keep the most useful mix for search. \n- Keep line 2 compact and readable (models/settings aid search without spam).\n\n**OUTPUT (exact format)** \n<action + outcome with intent terms>\n<gear & settings>\n<hashtags>"
}
]
}
},
"credentials": {
"anthropicApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "be2362e2-965e-4dcb-a6fe-f7ef89b8937a",
"name": "Publish image",
"type": "n8n-nodes-base.httpRequest",
"position": [
1824,
912
],
"parameters": {
"url": "=https://graph.facebook.com/v23.0/{{ $('Get instagram id').item.json.instagram_business_account.id }}/media_publish?access_token={{ $('get access_token').item.json.access_token }}",
"method": "POST",
"options": {},
"sendBody": true,
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "creation_id",
"value": "={{ $json.id }}"
}
]
},
"genericAuthType": "httpBearerAuth"
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 4.2,
"waitBetweenTries": 3000
},
{
"id": "4fe1ae6a-ef49-4b3e-9007-fcf0c4b3f279",
"name": "Create container",
"type": "n8n-nodes-base.httpRequest",
"position": [
1616,
912
],
"parameters": {
"url": "=https://graph.facebook.com/v23.0/{{ $json.instagram_business_account.id }}/media?access_token={{ $('get access_token').item.json.access_token }}",
"method": "POST",
"options": {},
"sendBody": true,
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "image_url",
"value": "={{ $('Params').item.json[\"n8n instance domain\"] }}/webhook/lr-image?catalogId={{ $('Params').item.json[\"LR catalog ID\"] }}&assetId={{ $('Limit').item.json.lr_asset_id }}"
},
{
"name": "caption",
"value": "={{ $('Message a model').item.json.content[0].text }}"
},
{
"name": "alt_text",
"value": "={{ $('Limit').item.json.alt }}"
}
]
},
"genericAuthType": "httpBearerAuth"
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "7ed0076c-bd55-438e-97ed-6ff81c93a29f",
"name": "Get instagram id",
"type": "n8n-nodes-base.httpRequest",
"position": [
1328,
912
],
"parameters": {
"url": "=https://graph.facebook.com/v23.0/{{ $('Params').item.json[\"FB id\"] }}?fields=instagram_business_account{id,username}&access_token={{ $json.access_token }}",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpBearerAuth"
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "3a5068e2-e585-49c8-91e2-f5d0cb69e087",
"name": "get access_token",
"type": "n8n-nodes-base.httpRequest",
"position": [
1136,
912
],
"parameters": {
"url": "=https://graph.facebook.com/v23.0/{{ $json[\"FB id\"] }}?fields=access_token ",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpBearerAuth"
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "282ad7a6-f6d7-4bc7-9440-cba5f63f2631",
"name": "Update row(s)",
"type": "n8n-nodes-base.dataTable",
"position": [
2240,
912
],
"parameters": {
"columns": {
"value": {
"ig_id": "={{ $json.id }}",
"ig_caption": "={{ $('Message a model').item.json.content[0].text }}",
"ig_posted_at": "={{ $now }}"
},
"schema": [
{
"id": "lr_asset_id",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "lr_asset_id",
"defaultMatch": false
},
{
"id": "lr_album_id",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "lr_album_id",
"defaultMatch": false
},
{
"id": "ig_posted_at",
"type": "dateTime",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "ig_posted_at",
"defaultMatch": false
},
{
"id": "ig_caption",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "ig_caption",
"defaultMatch": false
},
{
"id": "lr_asset",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "lr_asset",
"defaultMatch": false
},
{
"id": "alt",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "alt",
"defaultMatch": false
},
{
"id": "ig_id",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "ig_id",
"defaultMatch": false
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"filters": {
"conditions": [
{
"keyValue": "={{ $('Limit').item.json.id }}"
}
]
},
"options": {},
"matchType": "allConditions",
"operation": "update",
"dataTableId": {
"__rl": true,
"mode": "list",
"value": "Z4VvX6MjrmHmlAiY",
"cachedResultUrl": "/projects/wrMsdivh0K45jnU5/datatables/Z4VvX6MjrmHmlAiY",
"cachedResultName": "Photos"
}
},
"typeVersion": 1
},
{
"id": "eae2db29-c107-4502-8f19-103d0f02c64f",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-656,
912
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 14,
"triggerAtMinute": 10
},
{
"triggerAtHour": 18,
"triggerAtMinute": 10
},
{
"triggerAtHour": 20,
"triggerAtMinute": 10
},
{
"triggerAtHour": 11,
"triggerAtMinute": 40
}
]
}
},
"typeVersion": 1.2
},
{
"id": "f414301b-84f8-46b0-bb60-8f3dd5622484",
"name": "Params",
"type": "n8n-nodes-base.set",
"position": [
944,
912
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "1e380c14-e908-4eeb-90e0-957a422829d0",
"name": "instagram_business_account_id",
"type": "string",
"value": "..."
},
{
"id": "1e28c4bb-7381-4e75-9eb9-8d0fac288595",
"name": "FB id",
"type": "string",
"value": "..."
},
{
"id": "882e6776-0340-4f75-87ac-8396aba9104e",
"name": "n8n instance domain",
"type": "string",
"value": "..."
},
{
"id": "e50f6946-392a-4e5f-ab41-c6c24774d814",
"name": "LR catalog ID",
"type": "string",
"value": "..."
}
]
}
},
"typeVersion": 3.4
},
{
"id": "fa55bb79-7bb0-44ca-bdfc-665adf10f820",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-496,
752
],
"parameters": {
"color": 5,
"width": 672,
"height": 416,
"content": "## STEP1 - Select the next image to publish"
},
"typeVersion": 1
},
{
"id": "564e8e3c-41eb-451e-9e18-bc9284baee08",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
192,
752
],
"parameters": {
"color": 5,
"width": 672,
"height": 416,
"content": "## STEP2 - Generate the description with AI"
},
"typeVersion": 1
},
{
"id": "a3e90617-d77e-46e0-84d3-eecd3bf5d1d5",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
880,
752
],
"parameters": {
"color": 4,
"width": 608,
"height": 416,
"content": "## STEP3 - Instagram auth\n"
},
"typeVersion": 1
},
{
"id": "362685f6-2692-47a6-a178-66d084640f74",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1504,
752
],
"parameters": {
"color": 4,
"width": 528,
"height": 416,
"content": "## STEP4 - Publish the image\n\n"
},
"typeVersion": 1
},
{
"id": "2055e870-14e5-436d-a674-720a9197b520",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
2048,
752
],
"parameters": {
"color": 6,
"width": 528,
"height": 416,
"content": "## STEP5 - Update Data Table\n\n"
},
"typeVersion": 1
}
],
"connections": {
"Sort": {
"main": [
[
{
"node": "Limit",
"type": "main",
"index": 0
}
]
]
},
"Limit": {
"main": [
[
{
"node": "Message a model",
"type": "main",
"index": 0
}
]
]
},
"Params": {
"main": [
[
{
"node": "get access_token",
"type": "main",
"index": 0
}
]
]
},
"Get row(s)": {
"main": [
[
{
"node": "Sort",
"type": "main",
"index": 0
}
]
]
},
"Publish image": {
"main": [
[
{
"node": "Update row(s)",
"type": "main",
"index": 0
}
]
]
},
"Message a model": {
"main": [
[
{
"node": "Params",
"type": "main",
"index": 0
}
]
]
},
"Create container": {
"main": [
[
{
"node": "Publish image",
"type": "main",
"index": 0
}
]
]
},
"Get instagram id": {
"main": [
[
{
"node": "Create container",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Get row(s)",
"type": "main",
"index": 0
}
]
]
},
"get access_token": {
"main": [
[
{
"node": "Get instagram id",
"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.
anthropicApihttpBearerAuth
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Automatically publish Lightroom photos to Instagram with short, human-sounding AI captions. This workflow pulls the next item from your Data Table queue, generates an on-brand caption from alt text + metadata, uploads via Instagram Graph API, and marks it posted. Use it together…
Source: https://n8n.io/workflows/9694/ — 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.
Create a reusable “photos to post” queue from your Lightroom Cloud album—ideal for Lightroom-to-Instagram automation with n8n. It discovers new photos, stores clean metadata in a Data Table, and gener
This template is perfect for TikTok creators, content marketers, and social media teams who want to turn viral comments into engaging short-form videos without manually scripting, recording, or editin
Slack Channel Daily Digest (Multi-Provider LLM). Uses stickyNote, scheduleTrigger, httpRequest, openAi. Scheduled trigger; 14 nodes.
资讯转视频自动化. Uses anthropic, httpRequest, executeCommand. Scheduled trigger; 10 nodes.
The Helm. Uses github, httpRequest, anthropic. Scheduled trigger; 8 nodes.