This workflow corresponds to n8n.io template #6342 — we link there as the canonical source.
This workflow follows the Facebookgraphapi → Google Sheets 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 →
{
"id": "oAaE92ALCw2gDlGu",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Social Media Auto-Poster (Google Sheets \u2192 Twitter & Instagram)",
"tags": [],
"nodes": [
{
"id": "883262fd-4b71-4ad0-bcf8-86aa5a0186b8",
"name": "Schedule Trigger",
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 4
}
]
},
"type": "n8n-nodes-base.scheduleTrigger",
"notes": "This workflow is triggered automatically every 4 hours.",
"position": [
-260,
-60
],
"parameters": {
"rule": {
"interval": [
{}
]
}
},
"typeVersion": 1.2
},
{
"id": "874c156e-d4ec-4c42-a958-c5ae7eff6ede",
"name": "Get row(s) in sheet",
"type": "n8n-nodes-base.googleSheets",
"notes": "Fetches the first row from the Google Sheet where the 'Status' column is marked as 'Pending'. This provides the content for the social media posts.",
"position": [
-80,
-60
],
"parameters": {
"options": {
"returnFirstMatch": true
},
"filtersUI": {
"values": [
{
"lookupValue": "Pending",
"lookupColumn": "Status"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultName": "Sheet1"
},
"documentId": "[YOUR_GOOGLE_SHEET_ID]"
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"executeOnce": true,
"typeVersion": 4.6
},
{
"id": "e8eb5bf7-8939-4af5-a935-38a30da70077",
"name": "Insta post caption",
"type": "n8n-nodes-base.set",
"notes": "Prepares the data for the Instagram post. It combines the 'Caption', 'Description', and 'Hashtags' from the Google Sheet into a single `final_caption`. It also generates an HTML structure to be converted into the post image.",
"position": [
180,
-160
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "6a5be148-4da5-48ab-acae-810ab0f2d825",
"name": "final_caption",
"type": "string",
"value": "={{$json[\"Caption\"]+\" .................. \" +\"[\" + $json[\"Desc\"] +\"]\" +\" .................. \" + $json[\"Hashtags\"]}}"
},
{
"id": "09830a57-d962-4992-aca7-5ddfad947594",
"name": "HTML",
"type": "string",
"value": "=<div style=\"width: 1080px; height: 1080px; background: #0f1419; color: white; font-family: 'Segoe UI', sans-serif; padding: 80px; box-sizing: border-box; display: flex; flex-direction: column; justify-content: flex-start;\">\n <div style=\"display: flex; align-items: center; margin-bottom: 60px;\">\n <img src=\"https://your_URL\" style= width: 100px; height: 100px; border-radius: 50%; margin-right: 30px;\">\n <div>\n <div style=\"font-weight: bold; font-size: 36px;\">Cursed Canvas</div>\n <div style=\"color: #8899a6; font-size: 28px;\">@insane_dvlpr</div>\n </div>\n </div>\n\n <div style=\"font-size: 44px; line-height: 1.5; margin-bottom: 80px;\">{{ $json.Caption }}</div>\n\n <div style=\"display: flex; gap: 40px;\">\n <img src=\"https://cdn4.iconfinder.com/data/icons/twitter-29/512/166_Heart_Love_Like_Twitter-64.png\" style=\"width: 48px; height: 48px;\">\n <img src=\"https://img.icons8.com/ios-glyphs/48/speech-bubble--v1.png\" style=\"width: 48px; height: 48px; filter: invert(1);\">\n </div>\n</div>\n"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "6e6540b9-e5b8-47b4-b806-93f82a3d6be0",
"name": "HCTI Image",
"type": "n8n-nodes-base.httpRequest",
"notes": "Sends the generated HTML to the HTML/CSS to Image API (hcti.io) to create a 1080x1080px image for the Instagram post.",
"position": [
400,
-160
],
"parameters": {
"url": "https://hcti.io/v1/image",
"method": "POST",
"options": {},
"sendBody": true,
"contentType": "form-urlencoded",
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "HTML",
"value": "={{ $json.HTML }}"
},
{
"name": "viewport_width",
"value": "1080"
},
{
"name": "viewport_height",
"value": "1080"
}
]
},
"genericAuthType": "httpBasicAuth"
},
"credentials": {
"httpBasicAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "4c924428-729d-49db-8ac0-d979ab585a31",
"name": "Post on Twitter",
"type": "n8n-nodes-base.httpRequest",
"notes": "Posts the content from the 'Caption' column of the Google Sheet as a new tweet on X (Twitter).",
"position": [
180,
40
],
"parameters": {
"url": "https://api.x.com/2/tweets",
"method": "POST",
"options": {},
"sendBody": true,
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "text",
"value": "={{ $json.Caption }}"
}
]
},
"genericAuthType": "oAuth1Api"
},
"executeOnce": true,
"typeVersion": 4.2
},
{
"id": "b43788d0-447e-402d-a14c-f458ccaa0600",
"name": "Create Insta post",
"type": "n8n-nodes-base.facebookGraphApi",
"notes": "Step 1/2 for Instagram Posting. This node uploads the image generated in the previous step to the Instagram Content Publishing API. This creates a media container but does not publish it yet.",
"position": [
620,
-160
],
"parameters": {
"edge": "media",
"node": "[YOUR_INSTAGRAM_ACCOUNT_ID]",
"options": {
"queryParameters": {
"parameter": [
{
"name": "image_url",
"value": "={{ $json.url }}"
},
{
"name": "caption",
"value": "={{ $('Insta post caption').item.json.final_caption }}"
},
{
"name": "access_token",
"value": "[YOUR_FACEBOOK_ACCESS_TOKEN]"
}
]
}
},
"graphApiVersion": "v19.0",
"httpRequestMethod": "POST"
},
"typeVersion": 1
},
{
"id": "e5f1094d-4445-4ade-a19f-d82de803c572",
"name": "Post On Instagram",
"type": "n8n-nodes-base.facebookGraphApi",
"notes": "Step 2/2 for Instagram Posting. This node takes the container ID from the previous step ('Create Insta post') and publishes the media to the Instagram feed.",
"position": [
840,
-160
],
"parameters": {
"edge": "media_publish",
"node": "[YOUR_INSTAGRAM_ACCOUNT_ID]",
"options": {
"queryParameters": {
"parameter": [
{
"name": "creation_id",
"value": "={{ $json.id }}"
},
{
"name": "access_token",
"value": "[YOUR_FACEBOOK_ACCESS_TOKEN]"
}
]
}
},
"graphApiVersion": "v19.0",
"httpRequestMethod": "POST"
},
"typeVersion": 1
},
{
"id": "0261b9ff-d0de-44c8-a06f-bfa58cebd8c1",
"name": "Update Status Posted",
"type": "n8n-nodes-base.googleSheets",
"notes": "Updates the Google Sheet row that was just used. It changes the 'Status' column to 'Posted on [current date and time]' to prevent it from being posted again.",
"position": [
1060,
-160
],
"parameters": {
"columns": {
"value": {
"RowID": "={{ $('Get row(s) in sheet').item.json.RowID }}",
"Status": "={{ 'Posted on ' + $now.toLocaleString() }}\n"
},
"mappingMode": "defineBelow",
"matchingColumns": [
"RowID"
]
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultName": "Sheet1"
},
"documentId": "[YOUR_GOOGLE_SHEET_ID]"
},
"typeVersion": 4.6
},
{
"id": "3e06fa87-1e19-4f06-b106-48bae0b5e0d6",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-520,
-100
],
"parameters": {
"content": "This workflow is triggered automatically every 4 hours."
},
"typeVersion": 1
},
{
"id": "d4d5baf2-b4a1-4e39-b6ae-e38844e987c3",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-200,
-280
],
"parameters": {
"width": 220,
"height": 180,
"content": "## Google Sheet\nFetches the first row from the Google Sheet where the 'Status' column is marked as 'Pending'. This provides the content for the social media posts."
},
"typeVersion": 1
},
{
"id": "6c184428-9ea3-434a-8853-c50c616bf04e",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
40,
-500
],
"parameters": {
"height": 320,
"content": "## Create a Post Caption for the Instagram post\n\nPrepares the data for the Instagram post. It combines the 'Caption', 'Description', and 'Hashtags' from the Google Sheet into a single `final_caption`. It also generates an HTML structure to be converted into the post image."
},
"typeVersion": 1
},
{
"id": "21402df3-00f8-471a-877a-af51633c4d9d",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
300,
-500
],
"parameters": {
"width": 260,
"height": 320,
"content": "## Create Image using HTMLCSSIMAGE API\n\nSends the generated HTML to the HTML/CSS to Image API (hcti.io) to create a 1080x1080px image for the Instagram post."
},
"typeVersion": 1
},
{
"id": "f34942ad-7f26-4914-9a15-4d050b303622",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
100,
220
],
"parameters": {
"height": 240,
"content": "## Post a Tweet\n\n**Posts the content from the 'Caption' column of the Google Sheet as a new tweet on X (Twitter)."
},
"typeVersion": 1
},
{
"id": "65e786bc-b179-496a-8148-3ac2b2b2b416",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
580,
-500
],
"parameters": {
"color": 3,
"width": 440,
"height": 500,
"content": "## POST on Instagram\n\nStep 1/2 for Instagram Posting. This node uploads the image generated in the previous step to the Instagram Content Publishing API. This creates a media container but does not publish it yet.\n\nStep 2/2 for Instagram Posting. This node takes the container ID from the previous step ('Create Insta post') and publishes the media to the Instagram feed."
},
"typeVersion": 1
},
{
"id": "00a6e0d9-c32a-4353-bc21-6bc022edefdc",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
1080,
-440
],
"parameters": {
"height": 240,
"content": "## Update the Google sheet\n\nUpdates the Google Sheet row that was just used. It changes the 'Status' column to 'Posted on [current date and time]' to prevent it from being posted again."
},
"typeVersion": 1
},
{
"id": "f30a7954-99fa-4248-8a6f-a942b5ad80cb",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1220,
-440
],
"parameters": {
"width": 640,
"height": 980,
"content": "## Social Media Auto-Poster (Google Sheets \u2192 Twitter & Instagram)\n \nThis workflow automatically:\nPulls rows marked as Pending from a Google Sheet.\nGenerates a formatted Instagram caption and HTML preview.\nConverts the HTML into an image via HCTI.io.\nPosts the content:\nAs a tweet (text only) to Twitter (X).\nAs a post (image + caption) to Instagram via the Facebook Graph API.\nMarks the row in Google Sheets as Posted with a timestamp.\nIt runs every 5 hours (configurable via the Schedule Trigger).\n\nRequirements\nGoogle Sheets API Credentials connected in n8n.\nHCTI.io account (HTML \u2192 Image API).\nTwitter (X) OAuth1 credentials.\nFacebook/Instagram Graph API access token (for the business account/page).\nA Google Sheet with at least these columns:\nRowID\nCaption\nDesc\nHashtags\nStatus\nSet Status to Pending for any row you want posted.\n\nSetup\nImport the JSON workflow (My_workflow.json) into your n8n instance.\nLink all credentials (replace placeholders with your own API keys and tokens).\nUpdate the Google Sheet ID and Sheet Name inside the Get row(s) in sheet and Update Status Posted nodes.\n(Optional) Adjust the posting interval in the Schedule Trigger node.\nHow It Works\nTrigger: Runs every 5 hours.\nFetch Rows: Reads Google Sheets for rows with Status = Pending.\nCaption Generation: Combines Desc + Hashtags into final_caption.\nHTML \u2192 Image: Converts caption to a styled 1080x1080 post.\nSocial Posting:\nPosts the caption to Twitter (text only).\nUploads the image + caption to Instagram.\nUpdate Status: Marks the row as Posted on [timestamp].\n\nNotes\nFacebook/Instagram tokens expire; refresh or use long-lived tokens.\nHCTI.io may require a paid plan for high volumes.\nWorks best with a business Instagram account linked to a Facebook Page."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "9fcb74ec-477d-44e9-9148-a1dde8e2bea8",
"connections": {
"HCTI Image": {
"main": [
[
{
"node": "Create Insta post",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Get row(s) in sheet",
"type": "main",
"index": 0
}
]
]
},
"Create Insta post": {
"main": [
[
{
"node": "Post On Instagram",
"type": "main",
"index": 0
}
]
]
},
"Post On Instagram": {
"main": [
[
{
"node": "Update Status Posted",
"type": "main",
"index": 0
}
]
]
},
"Insta post caption": {
"main": [
[
{
"node": "HCTI Image",
"type": "main",
"index": 0
}
]
]
},
"Get row(s) in sheet": {
"main": [
[
{
"node": "Post on Twitter",
"type": "main",
"index": 0
},
{
"node": "Insta post caption",
"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.
googleSheetsOAuth2ApihttpBasicAuth
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow automatically: Pulls rows marked as from a Google Sheet. Generates a formatted Instagram caption and HTML preview. Converts the HTML into an image via HCTI.io. Posts the content: As a tweet (text only) to Twitter (X). As a post (image + caption) to Instagram via…
Source: https://n8n.io/workflows/6342/ — 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.
This workflow automates trend extraction and social media content creation for businesses and marketers. It eliminates manual trend research and content generation by fetching trends, scoring them wit
Managing content for multiple social media platforms manually is time-consuming and error-prone. This workflow automates content creation, image generation, approval flows, and publishing for LinkedIn
AI Posts Content Machine. Uses agent, stickyNote, outputParserStructured, lmChatAnthropic. Scheduled trigger; 28 nodes.
How it works
This n8n workflow automates the creation and publishing of social media content directly to Instagram, using ideas stored in a Google Sheet. It leverages AI (Google Gemini and Replicate Flux) to gener