This workflow corresponds to n8n.io template #15897 — we link there as the canonical source.
This workflow follows the Emailsend → 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": "7AinkHj2WNEeixb0",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Social analytics",
"tags": [],
"nodes": [
{
"id": "0222e36c-a40a-4f64-b370-242ee629a445",
"name": "Every Monday 9 AM",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
3984,
2864
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": 1,
"triggerAtHour": 9
}
]
}
},
"typeVersion": 1.1
},
{
"id": "75fdb746-6543-4289-8c4b-c63b8d770f51",
"name": "WES Config",
"type": "n8n-nodes-base.set",
"position": [
4208,
2864
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "w1",
"name": "weight_like",
"type": "number",
"value": 1
},
{
"id": "w2",
"name": "weight_comment",
"type": "number",
"value": 3
},
{
"id": "w3",
"name": "weight_share",
"type": "number",
"value": 5
},
{
"id": "w4",
"name": "weight_save",
"type": "number",
"value": 4
}
]
}
},
"typeVersion": 3.4
},
{
"id": "d3645c22-520c-4200-8b7f-97cb7412772c",
"name": "Get LinkedIn Posts",
"type": "n8n-nodes-base.httpRequest",
"position": [
4528,
2608
],
"settings": {
"alwaysOutputData": true
},
"parameters": {
"url": "=https://api.linkedin.com/v2/ugcPosts?q=authors&authors=List({{$env.LINKEDIN_OWNER_URN}})&count=100",
"options": {},
"sendHeaders": true,
"authentication": "predefinedCredentialType",
"headerParameters": {
"parameters": [
{
"name": "LinkedIn-Version",
"value": "202304"
}
]
},
"nodeCredentialType": "linkedInOAuth2Api"
},
"typeVersion": 4.2,
"continueOnFail": true
},
{
"id": "ecd61a8b-c77f-4cc1-b31a-c5fc92656b91",
"name": "Search Tweets",
"type": "n8n-nodes-base.twitter",
"position": [
4528,
2848
],
"settings": {
"alwaysOutputData": true
},
"parameters": {
"limit": 100,
"operation": "search",
"searchText": "={{$env.TWITTER_SEARCH_QUERY}}",
"additionalFields": {
"startTime": "={{$now.minus({days: 7}).toISO()}}"
}
},
"typeVersion": 2,
"continueOnFail": true
},
{
"id": "d8261e5c-934a-4761-ac33-52cb6df0ee46",
"name": "Get media",
"type": "@mookielianhd/n8n-nodes-instagram.instagram",
"position": [
4528,
3040
],
"settings": {
"alwaysOutputData": true
},
"parameters": {
"limit": 100,
"resource": "igUser",
"operation": "getMedia",
"graphApiVersion": "v24.0"
},
"typeVersion": 1,
"continueOnFail": true
},
{
"id": "2caeebbd-37fa-492f-9fcb-09c871782899",
"name": "Merge LI & TW",
"type": "n8n-nodes-base.merge",
"position": [
4800,
2720
],
"parameters": {},
"typeVersion": 2.1
},
{
"id": "0454934a-3f2b-427c-b889-d2ce0fc4531f",
"name": "Merge All Streams",
"type": "n8n-nodes-base.merge",
"position": [
5024,
2848
],
"parameters": {},
"typeVersion": 2.1
},
{
"id": "44a305b6-b7a4-445d-bf48-5e452942e15f",
"name": "Normalize & Validate Posts",
"type": "n8n-nodes-base.code",
"position": [
5328,
2752
],
"parameters": {
"jsCode": "// Weights from WES Config node\nconst weights = $('WES Config').first().json;\nconst wLike = weights.weight_like ?? 1;\nconst wComment = weights.weight_comment ?? 3;\nconst wShare = weights.weight_share ?? 5;\nconst wSave = weights.weight_save ?? 4;\n\n// Use native JS Date.now() \u2014 safe in all n8n hosting environments\nconst weekAgo = Date.now() - (7 * 24 * 60 * 60 * 1000);\n\nreturn $input.all().reduce((acc, item) => {\n const d = item.json;\n if (!d || Object.keys(d).length === 0) return acc;\n\n // Platform detection\n const isLinkedIn = d.firstPublishedAt !== undefined || d.specificContent !== undefined;\n const isInstagram = d.permalink !== undefined && d.timestamp !== undefined;\n const isTwitter = d.public_metrics !== undefined;\n\n // Direct timestamp extraction \u2014 no intermediate ISO string conversion\n let ts = null;\n if (d.firstPublishedAt) ts = new Date(d.firstPublishedAt).getTime();\n else if (d.publishedDate || d.created_at || d.timestamp) ts = new Date(d.publishedDate || d.created_at || d.timestamp).getTime();\n\n if (!ts || isNaN(ts) || ts < weekAgo) return acc;\n\n const platform = d.platform\n || (isLinkedIn ? 'linkedin'\n : isInstagram ? 'instagram'\n : isTwitter ? 'twitter'\n : 'unknown');\n\n const pm = d.public_metrics || {};\n const likes = pm.like_count || d.like_count || d.likes || d.likeCount || 0;\n const comments = pm.reply_count || d.comments_count || d.comments || d.reply_count || 0;\n const shares = pm.retweet_count || d.shares || d.retweet_count || d.shareCount || 0;\n const saves = pm.bookmark_count || d.saves || d.bookmark_count || 0;\n const impressions = pm.impression_count\n || d.impressions || d.view_count || d.reach\n || d.statistics?.totalShareStatistics?.impressionCount\n || null;\n\n const liText = d.specificContent?.['com.linkedin.ugc.ShareContent']?.shareCommentary?.text || '';\n const rawText = liText || d.text || d.caption || '';\n\n const twitterUrl = isTwitter && d.id\n ? 'https://twitter.com/i/web/status/' + d.id\n : null;\n const url = d.url || d.permalink || twitterUrl || '#';\n\n acc.push({\n json: {\n _platform: platform,\n _date: new Date(ts).toISOString(),\n _likes: likes,\n _comments: comments,\n _shares: shares,\n _saves: saves,\n _impressions: impressions,\n _text: rawText.trim(),\n _url: url,\n _wLike: wLike,\n _wComment: wComment,\n _wShare: wShare,\n _wSave: wSave\n }\n });\n\n return acc;\n}, []);"
},
"typeVersion": 2
},
{
"id": "ab264826-54f3-42c9-9cd9-a95d2f31756e",
"name": "Loop Over Batches",
"type": "n8n-nodes-base.splitInBatches",
"position": [
5680,
2560
],
"parameters": {
"options": {},
"batchSize": 50
},
"typeVersion": 3
},
{
"id": "58ea49ce-4ebc-43c3-a959-42b6a060c906",
"name": "Log Raw Posts to Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
5856,
2704
],
"parameters": {
"columns": {
"value": {
"URL": "={{$json._url}}",
"Date": "={{$json._date}}",
"Content": "={{$json._text.slice(0, 100)}}",
"Platform": "={{$json._platform}}",
"Engagement": "={{$json._likes + $json._comments + $json._shares + $json._saves}}",
"Impressions": "={{$json._impressions ?? 'unknown'}}"
},
"mappingMode": "defineBelow"
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "={{$env.ANALYTICS_SPREADSHEET_ID}}"
}
},
"typeVersion": 4.4,
"continueOnFail": true
},
{
"id": "01fbedd7-b27d-457a-937f-b8d9d392bb7d",
"name": "Capture Sheet Errors",
"type": "n8n-nodes-base.code",
"position": [
6192,
2720
],
"parameters": {
"jsCode": "const errors = $input.all()\n .filter(i => i.json.error)\n .map(i => i.json.error?.message || 'Unknown error writing to Sheets');\n\nreturn [{ json: { sheetErrors: errors, sheetErrorCount: errors.length } }];"
},
"typeVersion": 2
},
{
"id": "59b495a0-ba79-4232-b76f-f82d31423f32",
"name": "Calculate Analytics (WES)",
"type": "n8n-nodes-base.code",
"position": [
5664,
3104
],
"parameters": {
"jsCode": "// Use native JS Date.now() \u2014 safe in all n8n hosting environments\nconst items = $input.all();\nlet totalImpressions = 0;\nlet totalWesSum = 0;\nlet postsWithImpressions = 0;\nlet postsWithoutImpressions = 0;\nlet bestPost = null;\nlet worstPost = null;\nconst platformStats = {};\n\nitems.forEach(item => {\n const d = item.json;\n if (!d || Object.keys(d).length === 0) return;\n\n const wLike = d._wLike ?? 1;\n const wComment = d._wComment ?? 3;\n const wShare = d._wShare ?? 5;\n const wSave = d._wSave ?? 4;\n\n const platform = d._platform;\n const likes = d._likes || 0;\n const comments = d._comments || 0;\n const shares = d._shares || 0;\n const saves = d._saves || 0;\n const impressions = d._impressions;\n const wes = (wLike * likes) + (wComment * comments) + (wShare * shares) + (wSave * saves);\n\n if (!platformStats[platform]) {\n platformStats[platform] = { posts: 0, impressions: 0, wesSum: 0, postsWithImpressions: 0 };\n }\n platformStats[platform].posts++;\n\n if (impressions !== null && impressions > 0) {\n const rate = (wes / impressions) * 100;\n platformStats[platform].impressions += impressions;\n platformStats[platform].wesSum += wes;\n platformStats[platform].postsWithImpressions++;\n totalImpressions += impressions;\n totalWesSum += wes;\n postsWithImpressions++;\n\n const postPayload = { platform, text: d._text || 'Media post', rate, url: d._url };\n if (!bestPost || rate > bestPost.rate) bestPost = postPayload;\n if (!worstPost || rate < worstPost.rate) worstPost = postPayload;\n } else {\n postsWithoutImpressions++;\n }\n});\n\nconst platformRankings = Object.entries(platformStats)\n .map(([name, s]) => ({\n name,\n avgEngagementRate: s.postsWithImpressions > 0\n ? ((s.wesSum / s.impressions) * 100).toFixed(2)\n : 'N/A',\n totalPosts: s.posts,\n totalImpressions: s.impressions\n }))\n .sort((a, b) => parseFloat(b.avgEngagementRate) - parseFloat(a.avgEngagementRate));\n\n// Native JS date math \u2014 no Luxon dependency\nconst now = new Date();\nconst weekAgo = new Date(now.getTime() - (7 * 24 * 60 * 60 * 1000));\nconst toISODate = d => d.toISOString().slice(0, 10);\n\nreturn [{\n json: {\n weekStart: toISODate(weekAgo),\n weekEnd: toISODate(now),\n totalPosts: items.length,\n postsWithImpressions,\n postsWithoutImpressions,\n totalImpressions,\n avgEngagementRate: postsWithImpressions > 0\n ? ((totalWesSum / totalImpressions) * 100).toFixed(2)\n : 'N/A',\n platformRankings,\n bestPost,\n worstPost\n }\n}];"
},
"typeVersion": 2
},
{
"id": "e39147ed-6397-42f3-a815-7dba43dc7ef1",
"name": "AI Strategy Insights",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
6000,
3104
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4o"
},
"options": {
"temperature": 0.7
},
"messages": {
"values": [
{
"content": "=Based on this week's content performance data, provide 3 actionable recommendations for improving our social media strategy.\n\n**Overall Stats:**\n- Total Posts: {{$json.totalPosts}} ({{$json.postsWithImpressions}} with impression data, {{$json.postsWithoutImpressions}} without)\n- Avg Engagement Rate (WES): {{$json.avgEngagementRate}}%\n\n**Platform Rankings:**\n{{$json.platformRankings.map(p => `${p.name}: ${p.avgEngagementRate}% (${p.totalPosts} posts, ${p.totalImpressions} impressions)`).join('\\n')}}\n\n**Best Performing Post ({{$json.bestPost ? $json.bestPost.rate.toFixed(2) : 'N/A'}}%):**\n{{$json.bestPost ? $json.bestPost.text : 'No posts with impression data this week'}}\n\n**Worst Performing Post ({{$json.worstPost ? $json.worstPost.rate.toFixed(2) : 'N/A'}}%):**\n{{$json.worstPost ? $json.worstPost.text : 'No posts with impression data this week'}}\n\nCRITICAL OUTPUT FORMATTING:\nReturn your complete response in clean, semantic HTML format.\nUse ONLY <h3> for section titles, <p> for body text, <strong> for emphasis, and <ul>/<li> for action items.\nDo NOT wrap the response in markdown code blocks. Begin output directly with the first HTML tag."
}
]
}
},
"typeVersion": 1.1,
"continueOnFail": true
},
{
"id": "05b5400f-9a6b-4dc1-984c-0b66afd31fea",
"name": "Wait for All Branches",
"type": "n8n-nodes-base.merge",
"position": [
6464,
2656
],
"parameters": {
"mode": "combine",
"options": {},
"combinationMode": "mergeByPosition"
},
"typeVersion": 2.1
},
{
"id": "0faf1bf2-e313-436c-b5a1-fb5709b88242",
"name": "Combine Data & AI Output",
"type": "n8n-nodes-base.set",
"position": [
6720,
2656
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "1",
"name": "weekStart",
"type": "string",
"value": "={{ $('Calculate Analytics (WES)').first().json.weekStart }}"
},
{
"id": "2",
"name": "weekEnd",
"type": "string",
"value": "={{ $('Calculate Analytics (WES)').first().json.weekEnd }}"
},
{
"id": "3",
"name": "totalPosts",
"type": "number",
"value": "={{ $('Calculate Analytics (WES)').first().json.totalPosts }}"
},
{
"id": "4",
"name": "postsWithImpressions",
"type": "number",
"value": "={{ $('Calculate Analytics (WES)').first().json.postsWithImpressions }}"
},
{
"id": "5",
"name": "postsWithoutImpressions",
"type": "number",
"value": "={{ $('Calculate Analytics (WES)').first().json.postsWithoutImpressions }}"
},
{
"id": "6",
"name": "totalImpressions",
"type": "number",
"value": "={{ $('Calculate Analytics (WES)').first().json.totalImpressions }}"
},
{
"id": "7",
"name": "avgEngagementRate",
"type": "string",
"value": "={{ $('Calculate Analytics (WES)').first().json.avgEngagementRate }}"
},
{
"id": "8",
"name": "sheetErrorCount",
"type": "number",
"value": "={{ $('Capture Sheet Errors').all(0, 0).reduce((total, item) => total + (item.json.sheetErrorCount || 0), 0) }}"
},
{
"id": "9",
"name": "sheetErrors",
"type": "array",
"value": "={{ $('Capture Sheet Errors').all(0, 0).flatMap(item => item.json.sheetErrors || []) }}"
},
{
"id": "10",
"name": "aiInsights",
"type": "string",
"value": "={{ $('AI Strategy Insights').first().json.error ? '<p><em>AI insights unavailable this week: ' + $('AI Strategy Insights').first().json.error.message + '</em></p>' : ($('AI Strategy Insights').first().json.message.content || '').replace(/```html|```/g, '') }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "dcda36dd-3c67-4350-97f5-f4da2ae5d2dd",
"name": "Email Weekly Report",
"type": "n8n-nodes-base.emailSend",
"position": [
6928,
2656
],
"parameters": {
"html": "=<html>\n<body style=\"font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto;\">\n <h1>\ud83d\udcca Weekly Content Performance Report</h1>\n <p><strong>Period:</strong> {{$json.weekStart}} to {{$json.weekEnd}}</p>\n ={{ $json.sheetErrorCount > 0 ? '<div style=\"background:#fff3cd;border:1px solid #ffc107;padding:12px;border-radius:4px;margin-bottom:16px;\"><strong>\u26a0\ufe0f Warning:</strong> ' + $json.sheetErrorCount + ' post(s) failed to log to Google Sheets.<br>Errors: ' + ($json.sheetErrors || []).join(', ') + '</div>' : '' }}\n <h2>Key Metrics</h2>\n <table style=\"border-collapse: collapse; width: 100%;\">\n <tr style=\"background-color: #f0f0f0;\">\n <td style=\"padding: 10px; border: 1px solid #ddd;\"><strong>Total Posts</strong></td>\n <td style=\"padding: 10px; border: 1px solid #ddd;\">{{$json.totalPosts}}</td>\n </tr>\n <tr>\n <td style=\"padding: 10px; border: 1px solid #ddd;\"><strong>Posts with impression data</strong></td>\n <td style=\"padding: 10px; border: 1px solid #ddd;\">{{$json.postsWithImpressions}} / {{$json.totalPosts}}</td>\n </tr>\n <tr style=\"background-color: #f0f0f0;\">\n <td style=\"padding: 10px; border: 1px solid #ddd;\"><strong>Total Impressions</strong></td>\n <td style=\"padding: 10px; border: 1px solid #ddd;\">{{Number($json.totalImpressions).toLocaleString()}}</td>\n </tr>\n <tr>\n <td style=\"padding: 10px; border: 1px solid #ddd;\"><strong>Avg Engagement Rate (WES)</strong></td>\n <td style=\"padding: 10px; border: 1px solid #ddd;\">{{$json.avgEngagementRate}}%</td>\n </tr>\n </table>\n <h2>\ud83d\udca1 AI Strategy Recommendations</h2>\n <div style=\"background: #fff3e0; padding: 15px; border-radius: 5px;\">\n {{$json.aiInsights}}\n </div>\n</body>\n</html>",
"options": {},
"subject": "=Weekly Content Performance Report ({{$json.weekStart}} - {{$json.weekEnd}}){{$json.sheetErrorCount > 0 ? ' \u26a0\ufe0f Sheet errors' : ''}}",
"toEmail": "user@example.com",
"fromEmail": "user@example.com"
},
"typeVersion": 2.1
},
{
"id": "b886cc87-5743-47bf-8568-5e63e044bbc9",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
4416,
2480
],
"parameters": {
"color": 7,
"width": 784,
"height": 784,
"content": "### Multi-Platform Data Fetch\nPulls the last 7 days of posts from LinkedIn, X (Twitter), and Instagram in\nparallel, merges LinkedIn and X first, then combines all three streams into\na single unified feed for downstream processing."
},
"typeVersion": 1
},
{
"id": "d5fce582-efcd-4085-891f-07a209ccb200",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
5232,
2576
],
"parameters": {
"color": 7,
"width": 304,
"height": 480,
"content": "### Normalization & Validation\nDetects the platform of each post, extracts engagement metrics into a unified schema, filters out posts older than 7 days, and drops any empty items before passing clean data to both downstream branches."
},
"typeVersion": 1
},
{
"id": "ff20cbd7-5a33-4ba2-b035-474fdd6ab4e2",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
3840,
2720
],
"parameters": {
"color": 7,
"width": 544,
"height": 368,
"content": "### Trigger & Weight Config\nFires every Monday at 9 AM and sets the engagement weights used across the entire pipeline: likes (1), comments (3), shares (5), saves (4)."
},
"typeVersion": 1
},
{
"id": "34c00412-a56f-42ad-92ca-6973a4fb02ea",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
5568,
2944
],
"parameters": {
"color": 7,
"width": 768,
"height": 384,
"content": "### WES Calculation & AI Insights\nCalculates the Weighted Engagement Score for each post and aggregates platform rankings, best and worst performers, and overall stats. GPT-4o then generates 3 actionable strategy recommendations based on the week's performance data."
},
"typeVersion": 1
},
{
"id": "ffbbd2b6-858a-4c20-8a42-b9756199bd43",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
5568,
2416
],
"parameters": {
"color": 7,
"width": 768,
"height": 496,
"content": "### Raw Post Logging\nIterates over normalized posts in batches of 50 and appends each one to a Google Sheets log with date, platform, content preview, impressions, engagement score, and URL. Sheet write errors are captured without crashing the loop."
},
"typeVersion": 1
},
{
"id": "193530a4-e194-4a4b-b45e-fa418995de6a",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
6384,
2416
],
"parameters": {
"color": 7,
"width": 720,
"height": 496,
"content": "### Report Assembly & Delivery\nWaits for both the Sheets logging and AI insights branches to complete, merges all analytics data and AI output into a single payload, and sends a formatted HTML email report with key metrics, platform rankings, and strategy recommendations."
},
"typeVersion": 1
},
{
"id": "5d09c70d-a04c-4172-b92d-a509a0dca327",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
3024,
2416
],
"parameters": {
"width": 768,
"height": 912,
"content": "## Weekly Social Media Analytics: WES Scoring, AI Insights, and Automated Email Report\n\n### Cross-Platform Content Performance Reporting via LinkedIn, X, and Instagram\n\n### How it works\nThis workflow runs every Monday at 9 AM, pulls the last 7 days of posts from LinkedIn, X (Twitter), and Instagram, calculates a Weighted Engagement Score for each post, generates AI strategy recommendations with GPT-4o, logs raw data to Google Sheets, and delivers a formatted HTML report by email.\n\n### Setup steps\n- [ ] Set the LINKEDIN_OWNER_URN environment variable to your LinkedIn URN\n (format: urn:li:person:XXXXXXXX or urn:li:organization:XXXXXXXX).\n- [ ] Set the TWITTER_SEARCH_QUERY environment variable to the search query\n or handle you want to monitor (e.g. from:yourusername).\n- [ ] Set the ANALYTICS_SPREADSHEET_ID environment variable to your Google\n Sheets document ID where raw posts should be logged.\n- [ ] Connect your LinkedIn OAuth2 credential to the Get LinkedIn Posts node.\n- [ ] Connect your X (Twitter) credential to the Search Tweets node.\n- [ ] Connect your Instagram credential to the Get media node.\n- [ ] Connect your OpenAI credential to the AI Strategy Insights node.\n- [ ] Connect your Google Sheets credential to the Log Raw Posts to Sheets node.\n- [ ] Update the fromEmail and toEmail values in the Email Weekly Report node\n to match your sender and recipient addresses.\n- [ ] Adjust the engagement weights in the WES Config node to reflect your\n team's priorities. Default: likes 1, comments 3, shares 5, saves 4.\n\n### Required credentials\n- **LinkedIn OAuth2** (post fetch)\n- **X (Twitter) OAuth2** (tweet search)\n- **Instagram** (media fetch)\n- **OpenAI API** (strategy recommendations via GPT-4o)\n- **Google Sheets** (raw post logging)\n- **SMTP / email** (weekly report delivery)\n\n### Environment variables required\n`LINKEDIN_OWNER_URN` \u00b7 `TWITTER_SEARCH_QUERY` \u00b7 `ANALYTICS_SPREADSHEET_ID`\n\n### Notes\nWES (Weighted Engagement Score) is calculated as:\n`(likes \u00d7 1) + (comments \u00d7 3) + (shares \u00d7 5) + (saves \u00d7 4) / impressions \u00d7 100`\nPosts without impression data are excluded from the engagement rate calculation\nbut still counted in total post volume. Adjust weights in the WES Config node."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "bb8a05fb-fdcc-443e-a8af-88ee2aee37a5",
"connections": {
"Get media": {
"main": [
[
{
"node": "Merge All Streams",
"type": "main",
"index": 1
}
]
]
},
"WES Config": {
"main": [
[
{
"node": "Get LinkedIn Posts",
"type": "main",
"index": 0
},
{
"node": "Search Tweets",
"type": "main",
"index": 0
},
{
"node": "Get media",
"type": "main",
"index": 0
}
]
]
},
"Merge LI & TW": {
"main": [
[
{
"node": "Merge All Streams",
"type": "main",
"index": 0
}
]
]
},
"Search Tweets": {
"main": [
[
{
"node": "Merge LI & TW",
"type": "main",
"index": 1
}
]
]
},
"Every Monday 9 AM": {
"main": [
[
{
"node": "WES Config",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Batches": {
"main": [
[
{
"node": "Wait for All Branches",
"type": "main",
"index": 0
}
],
[
{
"node": "Log Raw Posts to Sheets",
"type": "main",
"index": 0
}
]
]
},
"Merge All Streams": {
"main": [
[
{
"node": "Normalize & Validate Posts",
"type": "main",
"index": 0
}
]
]
},
"Get LinkedIn Posts": {
"main": [
[
{
"node": "Merge LI & TW",
"type": "main",
"index": 0
}
]
]
},
"AI Strategy Insights": {
"main": [
[
{
"node": "Wait for All Branches",
"type": "main",
"index": 1
}
]
]
},
"Capture Sheet Errors": {
"main": [
[
{
"node": "Loop Over Batches",
"type": "main",
"index": 0
}
]
]
},
"Wait for All Branches": {
"main": [
[
{
"node": "Combine Data & AI Output",
"type": "main",
"index": 0
}
]
]
},
"Log Raw Posts to Sheets": {
"main": [
[
{
"node": "Capture Sheet Errors",
"type": "main",
"index": 0
}
]
]
},
"Combine Data & AI Output": {
"main": [
[
{
"node": "Email Weekly Report",
"type": "main",
"index": 0
}
]
]
},
"Calculate Analytics (WES)": {
"main": [
[
{
"node": "AI Strategy Insights",
"type": "main",
"index": 0
}
]
]
},
"Normalize & Validate Posts": {
"main": [
[
{
"node": "Loop Over Batches",
"type": "main",
"index": 0
},
{
"node": "Calculate Analytics (WES)",
"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 every Monday, pulls the last 7 days of posts from LinkedIn, X (Twitter), and Instagram, normalizes engagement metrics, logs raw post data to Google Sheets, calculates a weighted engagement rate, generates strategy recommendations with OpenAI (GPT-4o), and…
Source: https://n8n.io/workflows/15897/ — 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.
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
Instead of manually writing, designing, and posting content, this workflow turns a single Google Sheet row into multi-platform posts plus a custom AI image that matches your message.
This comprehensive n8n workflow automatically transforms trending Google search queries into engaging LinkedIn posts using AI. The system runs autonomously, discovering viral topics, researching conte
AI Social Media Post Creator. Uses googleSheets, openAi, twitter, httpRequest. Scheduled trigger; 7 nodes.
This workflow is ideal for individuals, marketers, agencies, and brands who want to effortlessly automate the entire blogging and social media process—from idea generation to promotion. Its primary go