This workflow corresponds to n8n.io template #17119 — 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 →
{
"meta": {
"templateCredsSetupCompleted": false
},
"name": "Weekly AI Social Video \u2014 Airtable + Claude + Sora + Buffer",
"tags": [],
"nodes": [
{
"id": "e6e3a486-5a0f-4980-931e-181e63b6378b",
"name": "Schedule Trigger Reels",
"type": "n8n-nodes-base.scheduleTrigger",
"notes": "Runs once a week, Monday at 17:00 (workflow timezone). Change day/hour here.",
"position": [
608,
128
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": [
1
],
"triggerAtHour": 17
}
]
}
},
"notesInFlow": false,
"typeVersion": 1.3
},
{
"id": "36ae33f2-d1cd-4cc3-bafd-1b7e48ba02ed",
"name": "Get Reel Ideas",
"type": "n8n-nodes-base.airtable",
"notes": "Reads every row from the 'Topics' table where Active = TRUE. This is your idea bank: one topic per row in a field called 'Topic'.",
"position": [
832,
128
],
"parameters": {
"base": {
"__rl": true,
"mode": "list",
"value": ""
},
"table": {
"__rl": true,
"mode": "list",
"value": ""
},
"options": {},
"operation": "search",
"filterByFormula": "{Active} = TRUE()"
},
"notesInFlow": false,
"typeVersion": 2.2
},
{
"id": "1ece2eef-5d67-4fc4-829d-8cb3479c7557",
"name": "Check History Reels",
"type": "n8n-nodes-base.airtable",
"notes": "Fetches the last 14 published reels (sorted by Date, newest first). Used to avoid repeating a topic too soon. 'Always output data' is ON so an empty table does not stop the run.",
"position": [
1056,
128
],
"parameters": {
"base": {
"__rl": true,
"mode": "list",
"value": ""
},
"sort": {
"property": [
{
"field": "Date",
"direction": "desc"
}
]
},
"limit": 14,
"table": {
"__rl": true,
"mode": "list",
"value": ""
},
"options": {},
"operation": "search",
"returnAll": false
},
"notesInFlow": false,
"typeVersion": 2.2,
"alwaysOutputData": true
},
{
"id": "589fefa5-8f41-4d26-8658-5bab66d9f761",
"name": "Filter and Choose Reel Topic",
"type": "n8n-nodes-base.code",
"notes": "Compares the idea bank against the last 14 published reels, keeps only the topics that were NOT used recently and picks one at random. Outputs { topic, isValid }.",
"position": [
1280,
128
],
"parameters": {
"jsCode": "// 1. Haal de beschikbare topics op uit de 'Get Ideas' node\nconst availableRecords = $('Get Reel Ideas').all();\nconst availableTopics = availableRecords.map(item => {\n return item.json.Topic || item.json.topic || (item.json.fields ? item.json.fields.Topic : undefined);\n}).filter(t => t !== undefined);\n\n// 2. Haal de LAATSTE 14 posts op uit de 'Check History Posts' node\nconst historyRecords = $('Check History Reels').all();\nconst recentTopics = historyRecords.map(item => {\n return item.json.Topic || item.json.topic || (item.json.fields ? item.json.fields.Topic : undefined);\n}).filter(t => t !== undefined);\n\n// 3. Filter: Hou alleen de onderwerpen over die NIET in de afgelopen 14 dagen zijn gepost\nconst freshTopics = availableTopics.filter(topic => !recentTopics.includes(topic));\n\n// 4. Als ALLE beschikbare opties in de afgelopen 14 dagen al zijn gebruikt\nif (freshTopics.length === 0) {\n return [{\n json: {\n topic: \"Alle beschikbare topics zijn de afgelopen 14 dagen al gepost!\",\n isValid: false\n }\n }];\n}\n\n// 5. Kies een willekeurig onderwerp uit de \"toegestane\" lijst\nconst chosenTopic = freshTopics[Math.floor(Math.random() * freshTopics.length)];\n\nreturn [{\n json: {\n topic: chosenTopic,\n isValid: true\n }\n}];"
},
"notesInFlow": false,
"typeVersion": 2
},
{
"id": "c98cffcb-68d3-46cb-a36f-0cc5689f5334",
"name": "Is Valid Reel?",
"type": "n8n-nodes-base.if",
"notes": "TRUE branch = a fresh topic was found, continue. FALSE branch = every topic was already used in the last 14 runs, stop safely.",
"position": [
1504,
128
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c47f4a42-4f78-4660-a026-936af9adea14",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.isValid }}",
"rightValue": true
}
]
}
},
"notesInFlow": false,
"typeVersion": 2.3
},
{
"id": "5c3abe09-4c57-4122-b61b-25808e6b6f9f",
"name": "Claude - Write Post Text1",
"type": "n8n-nodes-base.httpRequest",
"notes": "Calls the Anthropic Messages API and writes a short video caption for the chosen topic. EDIT THE PROMPT INSIDE THE JSON BODY: replace the brand context, tone of voice and rules with your own.",
"position": [
1728,
128
],
"parameters": {
"url": "https://api.anthropic.com/v1/messages",
"method": "POST",
"options": {},
"jsonBody": "={\n \"model\": \"claude-sonnet-5\",\n \"max_tokens\": 500,\n \"messages\": [\n {\n \"role\": \"user\",\n \"content\": \"Je bent een ervaren content schrijver voor 'Kijkes'.\\n\\nBEDRIJFSCONTEXT:\\nKijkes is GEEN traditioneel webdesignbureau. Wij bouwen automatisch, razendsnel en zonder gedoe professionele websites voor Belgische ondernemers (kmo's) die nu nog geen online aanwezigheid hebben.\\n\\nOPDRACHT:\\nSchrijf een super vlot, kort bijschrift (caption) voor een Instagram Reel / LinkedIn Video in het Nederlands. De kijker ziet op de achtergrond een strakke, paarse 3D tech-animatie.\\n\\nONDERWERP: {{ $json.topic }}\\n\\nSTRIKTE REGELS:\\n- Lengte: Maximaal 60 tot 90 woorden (kort en krachtig voor social video).\\n- Emojis: Maximaal 2 subtiele, functionele emoji's (bijv. \ud83d\udcf1, \ud83d\ude80).\\n- Hashtags: Gebruik er exact 5 onderaan: #belgischeondernemers #kmo #ondernemen #kijkes #website\\n- Toon: Direct, hands-on, herkenbaar voor de hardwerkende zelfstandige.\\n- Structuur: Begin meteen met de pijn/haak (bijv. 'Geen website = onzichtbaar...'), bied Kijkes aan als de automatische oplossing vanaf \u20ac39/md, en eindig met een call-to-action (bijv. 'Typ WEBSITE in de reacties!').\\n\\nGeef ALLEEN de tekst van de post terug, zonder inleiding of extra opmerkingen.\"\n }\n ]\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"headerParameters": {
"parameters": [
{
"name": "anthropic-version",
"value": "2023-06-01"
}
]
},
"nodeCredentialType": "anthropicApi"
},
"notesInFlow": false,
"typeVersion": 4.4
},
{
"id": "17f85a14-21c1-4b00-87ab-33afee739cb5",
"name": "Put Text in Variable1",
"type": "n8n-nodes-base.set",
"notes": "Extracts the plain text out of the Anthropic API response and stores it as 'postText', so later nodes can reference it cleanly.",
"position": [
1952,
128
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "ae899b15-0887-42ee-ac55-9cfec431c8a3",
"name": "postText",
"type": "string",
"value": "={{ $json.content[1]?.text || $json.content[0]?.text }}"
}
]
}
},
"notesInFlow": false,
"typeVersion": 3.4
},
{
"id": "459cf42e-4aff-4e00-83f9-e6bac26278b5",
"name": "Generate a video",
"type": "@n8n/n8n-nodes-langchain.openAi",
"notes": "Generates a vertical 720x1280 video clip (Sora) from the chosen topic. Edit the prompt to match your own visual style. Note: video generation takes a while and is the most expensive step.",
"position": [
2176,
128
],
"parameters": {
"size": "720x1280",
"prompt": "=A premium 3D motion graphics animation in a modern tech SaaS aesthetic, 720x1280 vertical aspect ratio, perfect for Instagram Reels loop. VISUAL SCENE: Dynamic and stylized 3D objects, clay-textured tech devices, and abstract geometric elements that visually represent and match the topic: '{{ $('Is Valid Reel?').item.json.topic }}'. BACKGROUND & MOVEMENT: A clean, minimalist soft lavender-grey and white infinite digital workspace. Vibrant purple (#6C54F7) neon light streams and glossy abstract shapes pulse, float, and morph smoothly in the center of the screen. The camera does a very subtle, elegant zoom-in. CRITICAL CONSTRAINTS: Absolutely NO text, NO typography, and NO letters anywhere on the screen. Focus purely on clean, high-end 3D symbolic and abstract visuals. No real human faces, no photorealism, high-end clean render style.",
"modelId": {
"__rl": true,
"mode": "list",
"value": "sora-2",
"cachedResultName": "SORA-2"
},
"options": {},
"resource": "video"
},
"notesInFlow": false,
"typeVersion": 2.3
},
{
"id": "950418aa-966b-4d5a-8a29-997c4b645fdf",
"name": "Upload Reel to Cloudinary",
"type": "n8n-nodes-cloudinary.cloudinary",
"notes": "Uploads the generated video file to Cloudinary and returns a public URL, which the social APIs need. Any public file host works here.",
"position": [
2464,
128
],
"parameters": {
"operation": "uploadFile",
"resource_type_file": "video",
"additionalFieldsFile": {}
},
"notesInFlow": false,
"typeVersion": 2
},
{
"id": "9b772335-6cc9-4ced-bf00-3f5db37b1a27",
"name": "Create LinkedIn Video",
"type": "@bufferapp/n8n-nodes-buffer.buffer",
"notes": "Sends caption + video URL to Buffer for the LinkedIn channel. Fill in your own Buffer organization ID and channel ID.",
"position": [
2688,
128
],
"parameters": {
"postText": "={{ $('Put Text in Variable1').item.json.postText }}",
"resource": "post",
"videoUrl": "={{ $json.url }}",
"channelId": "",
"attachmentType": "video",
"organizationId": ""
},
"notesInFlow": false,
"typeVersion": 1
},
{
"id": "75db38f3-9423-406f-bfa2-26af048d205d",
"name": "Create Instagram Reel",
"type": "@bufferapp/n8n-nodes-buffer.buffer",
"notes": "Sends the same caption + video URL to Buffer for the Instagram channel. Fill in your own Buffer organization ID and channel ID.",
"position": [
2912,
128
],
"parameters": {
"postText": "={{ $('Put Text in Variable1').item.json.postText }}",
"resource": "post",
"videoUrl": "={{ $('Upload Reel to Cloudinary').item.json.url }}",
"channelId": "",
"attachmentType": "video",
"organizationId": ""
},
"notesInFlow": false,
"typeVersion": 1
},
{
"id": "506c35fd-6592-412a-8a17-276a94f44c14",
"name": "Log Posted Reel",
"type": "n8n-nodes-base.airtable",
"notes": "Writes topic and caption to the 'Reels' table. This is what makes the 14-day anti-repeat memory work, so do not remove it.",
"position": [
3136,
128
],
"parameters": {
"base": {
"__rl": true,
"mode": "list",
"value": ""
},
"table": {
"__rl": true,
"mode": "list",
"value": ""
},
"columns": {
"value": {
"Post": "={{ $('Put Text in Variable1').item.json.postText }}",
"Topic": "={{ $('Is Valid Reel?').item.json.topic }}"
},
"schema": [
{
"id": "Date",
"type": "dateTime",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Topic",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "Topic",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Post",
"type": "string",
"display": true,
"removed": false,
"readOnly": false,
"required": false,
"displayName": "Post",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Image URL",
"type": "string",
"display": true,
"removed": true,
"readOnly": false,
"required": false,
"displayName": "Image URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Platform",
"type": "array",
"display": true,
"options": [
{
"name": "LinkedIn",
"value": "LinkedIn"
},
{
"name": "Instagram",
"value": "Instagram"
}
],
"removed": true,
"readOnly": false,
"required": false,
"displayName": "Platform",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "create"
},
"notesInFlow": false,
"typeVersion": 2.2
},
{
"id": "5b65829a-b2a1-48fa-86b4-2cce89c271bc",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
544,
0
],
"parameters": {
"color": 7,
"width": 1120,
"height": 520,
"content": "## 1. Pick a fresh topic\nLoads your active topics and the last 14 published reels, then randomly picks one that was not used recently. If every topic has been used, the run stops instead of repeating itself."
},
"typeVersion": 1
},
{
"id": "6ff9b999-f3d1-4e36-9ffb-dadf0d0e1f10",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1680,
0
],
"parameters": {
"color": 7,
"width": 710,
"height": 520,
"content": "## 2. Generate the content\nClaude writes a short video caption, then Sora renders a vertical 720x1280 clip for that same topic."
},
"typeVersion": 1
},
{
"id": "6ce7cbf0-4c1b-4471-ae3c-ce372d54312c",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
2416,
0
],
"parameters": {
"color": 7,
"width": 980,
"height": 520,
"content": "## 3. Publish and remember\nCloudinary turns the video into a public URL, Buffer schedules it on LinkedIn and Instagram, and Airtable logs it as next week's memory."
},
"typeVersion": 1
},
{
"id": "f6f2403a-c879-4160-9949-98c4f64d53b3",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
544
],
"parameters": {
"color": 7,
"width": 500,
"height": 924,
"content": "## \ud83d\uddc2\ufe0f Airtable setup\n\nCreate one base with these tables. Both the daily-post and the weekly-video version of this workflow can share the same base.\n\n**Topics** \u2014 your idea bank\n| Field | Type |\n|---|---|\n| `Topic` | Single line text |\n| `Active` | Checkbox |\n\nOnly checked rows are used. Fill it with 20-40 ideas; the workflow picks one at random per run.\n\n**Reels** \u2014 the history it remembers\n| Field | Type |\n|---|---|\n| `Date` | Created time |\n| `Topic` | Single line text |\n| `Post` | Long text |\n\n\u26a0\ufe0f `Date` must be a **Created time** field, not a normal date. The workflow never writes it, but it sorts on it to find the last 14 items. Without it the anti-repeat check silently breaks.\n\n**How the anti-repeat works:** active topics minus the last 14 logged rows = the pool it picks from. Empty pool means the run stops instead of repeating content, so keep 15+ topics active.\n\nPosts and reels use separate history tables, so the same topic can run as an image post and as a video without blocking each other."
},
"typeVersion": 1
},
{
"id": "df62e0c1-70a4-44cb-8a7a-fea03a904abd",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
0
],
"parameters": {
"width": 500,
"height": 520,
"content": "## \ud83c\udfac Weekly AI Video & Reel Engine\n\nOnce a week this workflow picks a topic it has not used recently, writes a caption with Claude, generates a vertical AI video, and schedules it to LinkedIn and Instagram through Buffer.\n\n### How it works\n1. The schedule trigger fires weekly (Monday 17:00).\n2. Airtable returns your active topics plus the last 14 published reels.\n3. A Code node randomly picks a topic that is not in that history, so content never repeats.\n4. Claude writes the caption and Sora renders a 720x1280 vertical clip.\n5. Cloudinary hosts the file and returns the public URL that the social APIs require.\n6. Buffer schedules the video and Airtable logs it as the memory for next week.\n\n### Setup\n1. Create credentials for Airtable, Anthropic, OpenAI, Buffer and Cloudinary.\n2. Build the Airtable base described in the grey note below this one.\n3. Pick your organization and channel from the dropdowns in both Buffer nodes.\n4. Keep at least 15 active topics, otherwise the workflow stops instead of repeating itself.\n\n### Customization\nEdit the prompt in *Generate a video* to match your own visual style, and the Claude prompt for your tone of voice. Video generation is the slowest and most expensive step, which is why this runs weekly rather than daily."
},
"typeVersion": 1
},
{
"id": "907af88c-7005-4a51-a72f-94207d64ca32",
"name": "No Operation, do nothing",
"type": "n8n-nodes-base.noOp",
"notes": "Dead end on purpose: nothing is published when no fresh topic is available. Add more rows to the Topics table (or a Slack/Email node here) if you want an alert.",
"position": [
1504,
384
],
"parameters": {},
"notesInFlow": false,
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"connections": {
"Get Reel Ideas": {
"main": [
[
{
"node": "Check History Reels",
"type": "main",
"index": 0
}
]
]
},
"Is Valid Reel?": {
"main": [
[
{
"node": "Claude - Write Post Text1",
"type": "main",
"index": 0
}
],
[
{
"node": "No Operation, do nothing",
"type": "main",
"index": 0
}
]
]
},
"Generate a video": {
"main": [
[
{
"node": "Upload Reel to Cloudinary",
"type": "main",
"index": 0
}
]
]
},
"Check History Reels": {
"main": [
[
{
"node": "Filter and Choose Reel Topic",
"type": "main",
"index": 0
}
]
]
},
"Create Instagram Reel": {
"main": [
[
{
"node": "Log Posted Reel",
"type": "main",
"index": 0
}
]
]
},
"Create LinkedIn Video": {
"main": [
[
{
"node": "Create Instagram Reel",
"type": "main",
"index": 0
}
]
]
},
"Put Text in Variable1": {
"main": [
[
{
"node": "Generate a video",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger Reels": {
"main": [
[
{
"node": "Get Reel Ideas",
"type": "main",
"index": 0
}
]
]
},
"Claude - Write Post Text1": {
"main": [
[
{
"node": "Put Text in Variable1",
"type": "main",
"index": 0
}
]
]
},
"Upload Reel to Cloudinary": {
"main": [
[
{
"node": "Create LinkedIn Video",
"type": "main",
"index": 0
}
]
]
},
"Filter and Choose Reel Topic": {
"main": [
[
{
"node": "Is Valid Reel?",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow runs weekly to pick a fresh video topic from Airtable, generate a short caption with Anthropic Claude and a vertical Sora video via OpenAI, upload the clip to Cloudinary for a public URL, and schedule the post to LinkedIn and Instagram through Buffer. Runs every…
Source: https://n8n.io/workflows/17119/ — 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.
Workflow runs at 08:00 (UK), AI stories from TechCrunch, The Verge, and the OpenAI Blog via RSS, AI to select and editorially shape one signal into a post and image prompt, generates and QA-checks a p
This workflow automatically fetches product reviews from your WooCommerce store, analyzes the sentiment of each review using AI, stores the results in Airtable and sends a summary of positive, neutral
Time Tracker - 15min Ping (Template). Uses slack, openAi, airtable, httpRequest. Scheduled trigger; 17 nodes.
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
This workflow is ideal for sales teams, marketers, and virtual assistants who manage outbound campaigns and want to improve their cold outreach personalization. It helps automate the research and writ