This workflow corresponds to n8n.io template #8332 — we link there as the canonical source.
This workflow follows the Agent → 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": "U1oAcmg6sXQaCOKm",
"name": "Linkedin Auto",
"tags": [],
"nodes": [
{
"id": "c5a09a2f-88af-414e-87b9-055731b13fd1",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
688,
224
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "gpt-4o-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "24115efb-96bc-48cb-9748-b6753c74ced4",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
816,
224
],
"parameters": {
"schemaType": "manual",
"inputSchema": "{\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"post\": {\n\t\t\t\"type\": \"string\"\n\t\t}\n}\n}"
},
"typeVersion": 1.2
},
{
"id": "af2e19c8-4921-4c61-b6ce-1661e04b6baf",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
0,
0
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": [
1,
3,
5
],
"triggerAtHour": 9,
"triggerAtMinute": 30
}
]
}
},
"typeVersion": 1.2
},
{
"id": "958d6aba-08be-46d5-8441-232c6085b63e",
"name": "writing the post",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
672,
0
],
"parameters": {
"text": "=You are a professional LinkedIn content writer helping a technical writer build thought-leadership posts that maximize impressions and engagement.\n\n**Context & Quality Principles**\n\n* Clarify the topic before writing; if anything is unclear, ask follow-up questions first.\n* Write **only in active voice**.\n* Fact-check every statement; avoid ambiguity.\n* Keep the tone professional, direct, and slightly conversational (not stiff, not overly casual).\n* Do **not** use these words or phrases: meticulous, meticulously, navigating, complexities, realm, bespoke, tailored, towards, underpins, everchanging, ever-evolving, the world of, not only, seeking more than just, designed to enhance, it\u2019s not merely, our suite, it is advisable, daunting, dive into, unique, ensure, utmost, in the heart of, when it comes to, in the realm of, amongst, unlock the secrets, unveil the secrets, robust.\n* If the topic is highly technical, adopt a developer-centric voice.\n* Aim for very high readability: varied sentence lengths, mostly short, crisp lines.\n* Cut all fluff; every sentence must add value.\n* Sprinkle **1\u20132 engagement cues mid-post** (e.g., \u201cEver faced this?\u201d \u201cWould you have done the same?\u201d).\n* Encourage reflection and conversation; posts should feel like they invite community input.\n\n**Output Requirements**\n\n1. Start with 2\u20133 **hook variations** for the first line. The main post should pick the best one, but show the alternates.\n2. Write 3\u20135 short paragraphs that are concise, engaging, and rich in practical insights or reflections that people can apply or debate.\n3. End with a thought-provoking or community-driven question that drives comments.\n4. Add 4\u20136 relevant hashtags that balance **broad reach (e.g., #AI, #Startups)** with **niche visibility** (#TechnicalWriting, #DecisionAutomation).\n5. Use 2\u20134 natural, well-placed emojis to break monotony and add emphasis.\n6. Keep total length under 2500 characters (shorter posts often perform better).\n\n**Formatting Rules**\n\n* Do **not** use double quotes, special characters, or Markdown symbols in the post text.\n* Escape the text so it is JSON-compatible.\n* Provide the output in JSON format with fields: `hook_variations`, `post`, `hashtags`.\n\n**Post Input**\nUse this title:\n{{ $json['Post title'] }}",
"options": {
"systemMessage": "=You are an expert LinkedIn content strategist and copywriter.\nYour job is to generate thought-leadership posts for a technical writer that maximize impressions, engagement, and community interaction.\n\n## **Principles to Follow**\n\n* Always clarify the topic first if unclear.\n* Write only in **active voice**.\n* Fact-check every statement. Avoid vague or unverified claims.\n* Maintain a tone that is professional, direct, and slightly conversational. Never stiff, never overly casual.\n* If the topic is technical, adopt a **developer-centric voice**.\n* Keep posts highly readable: mix sentence lengths, but favor short, crisp lines.\n* Eliminate fluff: every sentence must provide value.\n* Include 1\u20132 **engagement cues mid-post** (e.g., Ever faced this? Would you have done the same?).\n* Posts should encourage reflection and conversation, not just broadcasting.\n\n## **Banned Words & Phrases**\n\nDo not use:\nmeticulous, meticulously, navigating, complexities, realm, bespoke, tailored, towards, underpins, everchanging, ever-evolving, the world of, not only, seeking more than just, designed to enhance, it\u2019s not merely, our suite, it is advisable, daunting, dive into, unique, ensure, utmost, in the heart of, when it comes to, amongst, unlock the secrets, unveil the secrets, robust.\n\n## **Output Rules**\n\n1. Provide 2\u20133 strong **hook variations** for the opening line.\n2. Write the post in **3\u20135 short paragraphs**. Each must be concise, engaging, and packed with practical insights or reflections.\n3. End with a **thought-provoking, community-driven question** that invites comments.\n4. Add 4\u20136 relevant hashtags: balance broad reach (#AI, #Startups) with niche visibility (#TechnicalWriting, #DecisionAutomation).\n5. Use 2\u20134 natural emojis to add emphasis without overloading the text.\n6. Keep the post under **2500 characters**.\n\n## **Formatting Rules**\n\n* Do not use quotes, special characters, or Markdown formatting inside the post.\n* Escape all text so it is JSON-compatible.\n* Final output must be in strict **JSON format** with the following fields:\n\n```json\n{\n \"hook_variations\": [],\n \"post\": \"\",\n \"hashtags\": []\n}\n```\n\n## **Post Input**\n\nUse this title as the seed topic:\n`{{ $json['Post title'] }}`\n"
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.8
},
{
"id": "66c2ef92-3d87-4e3c-a6d4-fd336824e5b8",
"name": "Create a post",
"type": "n8n-nodes-base.linkedIn",
"position": [
1248,
-16
],
"parameters": {
"text": "={{ $json.output.post }}",
"person": "ioXQWCBoFo",
"additionalFields": {}
},
"credentials": {
"linkedInOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "22f5b4da-9ac9-46f0-88e2-f8c96c872d12",
"name": "Fetch the pending contents from the sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
224,
0
],
"parameters": {
"options": {},
"filtersUI": {
"values": [
{
"lookupValue": "Pending",
"lookupColumn": "Status"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1KeZa_v-ayxEAkCYUdMsH9GPmjCp7yTnBkG6J4f1gQJQ/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1KeZa_v-ayxEAkCYUdMsH9GPmjCp7yTnBkG6J4f1gQJQ",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1KeZa_v-ayxEAkCYUdMsH9GPmjCp7yTnBkG6J4f1gQJQ/edit?usp=drivesdk",
"cachedResultName": "Linkedin Plan"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6
},
{
"id": "1f57c9e8-1a65-4193-8221-58c56a8f72cb",
"name": "Selecting the first one only",
"type": "n8n-nodes-base.limit",
"position": [
448,
0
],
"parameters": {},
"typeVersion": 1
},
{
"id": "9f83d2cb-bd60-4d3b-9887-cc5a6bf45f07",
"name": "Update row to Done in sheet1",
"type": "n8n-nodes-base.googleSheets",
"position": [
1472,
-16
],
"parameters": {
"columns": {
"value": {
"id": "={{ $('Selecting the first one only').item.json.id }}",
"Status": "Done",
"Column 5": "={{ $('writing the post').item.json.output.post }}"
},
"schema": [
{
"id": "id",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "id",
"defaultMatch": true,
"canBeUsedToMatch": true
},
{
"id": "Post title",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Post title",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Post description",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Post description",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Column 5",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Column 5",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "number",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"id"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1KeZa_v-ayxEAkCYUdMsH9GPmjCp7yTnBkG6J4f1gQJQ/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1KeZa_v-ayxEAkCYUdMsH9GPmjCp7yTnBkG6J4f1gQJQ",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1KeZa_v-ayxEAkCYUdMsH9GPmjCp7yTnBkG6J4f1gQJQ/edit?usp=drivesdk",
"cachedResultName": "Linkedin Plan"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.5
},
{
"id": "10a4a1de-3b90-45ee-b8d1-feeacae5ab34",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-32,
-256
],
"parameters": {
"width": 608,
"height": 512,
"content": "## Note: Fetch topics from Google Sheets\n\n* **Credentials:** Google Sheets (OAuth2)\n* **Node:** Google Sheets \u2192 Get Rows (Spreadsheet ID/URL, Tab = `Posts`)\n* **Filter:** IF \u2192 `Status` equals `Pending`\n* **Limit:** 1 item per run\n* **Fields to keep:** `id`, `Status`, `Post title`, optional `Hashtags`, `Notes`"
},
"typeVersion": 1
},
{
"id": "52081427-4a81-47ca-a9a1-fafca4d6026c",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1152,
-272
],
"parameters": {
"color": 2,
"width": 1040,
"height": 1264,
"content": "\n\n## Step-by-step\n\n1. **Schedule Trigger**\n Runs on **Mon/Wed/Fri at 09:30**.\n2. **Fetch pending rows (Google Sheets \u2192 Get Rows)**\n Reads the sheet and filters rows where **Status = Pending**.\n3. **Limit**\n Keeps only the first pending row so one post goes out per run.\n4. **Writing the post (Agent + OpenAI Chat Model + Structured Output Parser)**\n Uses **Post title** (and optional `Notes`/`Hashtags`) as input. The agent returns JSON with a `post` field. Model set to **gpt-4o-mini** by default.\n5. **Create a post (LinkedIn)**\n Publishes `{{$json.output.post}}` to the configured **person** (your profile URN).\n6. **Update the sheet (Google Sheets \u2192 Update)**\n Matches by `id`, sets **Status = Done**, and writes the generated text into **Output post** (or your existing output column).\n\n## Customization\n\n* **Schedule** \u2014 change days/time in the Schedule node. Consider your n8n server timezone.\n* **Posts per run** \u2014 remove or raise the **Limit** to post more than one item.\n* **Style and tone** \u2014 edit the Agent\u2019s system prompt. Add rules for line breaks, hashtags, or a closing CTA.\n* **Hashtags handling** \u2014 parse the `Hashtags` column in the prompt so the model appends them cleanly.\n* **Media posts** \u2014 add a branch that attaches `Image URL` (requires LinkedIn media upload endpoints).\n* **Company Page** \u2014 switch the **person** field to an **organization** URN tied to your LinkedIn app scope.\n\n## Troubleshooting\n\n* **No post created**\n\n * Check the **If/Limit** path: is there any row with `Status = Pending`?\n * Confirm the sheet **ID** and **tab name** in the Google Sheets nodes.\n* **Sheet not updating**\n\n * The **Update** node must receive the original `id`. If you changed field names, remap them.\n * Make sure `id` values are unique.\n* **LinkedIn errors (403/401/404)**\n\n * Refresh **LinkedIn OAuth2** in Credentials.\n * The **person/organization URN** is wrong or missing. Copy the exact URN from the LinkedIn node helper.\n * App lacks required permissions for posting.\n* **Rate limit (429) or model errors**\n\n * Add a short **Wait** before retries.\n * Switch to a lighter model or simplify the prompt.\n* **Post too long or broken formatting**\n\n * LinkedIn hard limit is \\~3,000 characters. Add a truncation step in Code or instruct the prompt to cap length.\n * Replace double line breaks in the LinkedIn node if you see odd spacing.\n* **Timezone mismatch**\n\n * The Schedule node uses the n8n instance timezone. Adjust or move to a Cron with explicit TZ if needed.\n\nNeed to post at a different cadence, or push two posts per day? Tweak the **Schedule** and **Limit** nodes and you\u2019re set.\n"
},
"typeVersion": 1
},
{
"id": "5b4554b6-5841-4ad2-b167-1da7db6e8d4c",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
624,
-288
],
"parameters": {
"color": 6,
"width": 480,
"height": 688,
"content": "## Note: AI post generation\n\n* **Credentials:** OpenAI\n* **Nodes:** Agent \u2192 OpenAI Chat Model\n* **Prompt (brief):** 3\u20136 short lines, \u22641200 chars, append provided hashtags, no new emojis\n* **Inputs:** `{{$json[\"Post title\"]}}`, `{{$json[\"Hashtags\"]||\"\"}}`, `{{$json[\"Notes\"]||\"\"}}`\n* **Model:** `gpt-4o-mini`\n* **Output path:** `{{$json.output.post}}`"
},
"typeVersion": 1
},
{
"id": "c1c7bbdb-a5e6-409d-9ebc-ff8e89a7f690",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1184,
-288
],
"parameters": {
"color": 4,
"width": 480,
"height": 496,
"content": "## Note: Publish to LinkedIn\n\n* **Credentials:** LinkedIn OAuth2\n* **Node:** LinkedIn \u2192 Create Post\n* **Person URN:** your profile URN (e.g., `urn:li:person:XXXX`)\n* **Text:** `{{$json.output.post}}` ; **Visibility:** PUBLIC\n* **Optional media:** add upload step for image URL\n* **After publish:** Google Sheets \u2192 Update by `id` \u2192 set `Status=Done`, write to `Output post`"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "41a299af-ba00-42f3-ab42-e65cc4a081e7",
"connections": {
"Create a post": {
"main": [
[
{
"node": "Update row to Done in sheet1",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Fetch the pending contents from the sheet",
"type": "main",
"index": 0
}
]
]
},
"writing the post": {
"main": [
[
{
"node": "Create a post",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "writing the post",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "writing the post",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Selecting the first one only": {
"main": [
[
{
"node": "writing the post",
"type": "main",
"index": 0
}
]
]
},
"Fetch the pending contents from the sheet": {
"main": [
[
{
"node": "Selecting the first one only",
"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.
googleSheetsOAuth2ApilinkedInOAuth2ApiopenAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Solo creators, PMs, and content teams who queue LinkedIn ideas in Google Sheets and want them posted on a fixed schedule with AI-generated copy.
Source: https://n8n.io/workflows/8332/ — 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 n8n workflow is designed for content creators, digital marketers, and social media managers who want to automate their entire content creation and publishing process across multiple platforms. It
Automate LinkedIn content creation by managing ideas in Google Sheets, generating professional AI-written posts, intelligently selecting relevant Unsplash images, sending drafts for email approval, an
This workflow is designed for content creators, social media managers, digital marketers, and business owners who want to automate their LinkedIn content creation and publishing process. It's especial
Build a completely automated LinkedIn content engine using n8n, OpenAI, Google Sheets, and the LinkedIn API. This workflow reads unpublished topics from a Google Sheet, generates engaging AI-powered p
⚠️ DISCLAIMER: This workflow uses the AnySite LinkedIn community node, which is only available on self-hosted n8n instances. It will not work on n8n.cloud.