This workflow follows the Error Trigger → 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 →
{
"name": "Social Content Intelligence \u2014 Weekly Report",
"nodes": [
{
"parameters": {
"content": "# Social Content Intelligence \u2014 Weekly Report\n**Version:** 1.0.0 | **Author:** Otter Labs | **Schedule:** Every Monday 9am\n\n## What This Workflow Does\n1. **Collects** your last 30 days of posts from Twitter/X, Instagram, TikTok, LinkedIn, and YouTube in parallel\n2. **Normalizes** all platform data into a unified engagement format\n3. **Analyzes** your top 25 posts with Claude \u2014 extracting hook patterns, winning formats, audience psychology\n4. **Researches** trending topics across Perplexity AI, Reddit, X Trending, TikTok, and Google Trends simultaneously\n5. **Generates** 15 high-potential content ideas tailored to your niche and audience\n6. **Publishes** a complete Weekly Content Intelligence Report to Notion with individual idea sub-pages\n7. **Notifies** you via Slack with a summary and Notion link\n\n## Required Credentials (create these in n8n Credentials first)\n| Service | Type | Auth Detail |\n|---------|------|-------------|\n| Twitter/X | HTTP Header Auth | Bearer Token (requires Elevated Access \u2014 apply at developer.twitter.com) |\n| Instagram | HTTP Header Auth | Graph API long-lived access token (Business/Creator account required) |\n| TikTok | HTTP Header Auth | Bearer token from TikTok Developer Portal |\n| LinkedIn | OAuth2 API | Client ID + Secret, scopes: r_liteprofile r_ugcposts |\n| YouTube | HTTP Query Auth | name=key, API key from Google Cloud Console |\n| Anthropic | HTTP Header Auth | name=x-api-key, value=your API key from console.anthropic.com |\n| Perplexity | HTTP Header Auth | name=Authorization, value=Bearer YOUR_KEY from perplexity.ai/settings |\n| Reddit | HTTP Header Auth | Access token via Reddit OAuth (script app type) |\n| SerpAPI | HTTP Query Auth | name=api_key from serpapi.com |\n| Notion | Notion API | Integration token from notion.so/my-integrations |\n\n## Configuration\nSet all user-specific values in **\u2699\ufe0f Config** node before activating.\nDo NOT hardcode values anywhere else \u2014 everything flows from Config.\n\n## Output Structure\n- **Notion DB:** 1 Weekly Report parent page + 15 individual content idea child pages\n- **Slack:** Success summary with Notion link, or error alert with failure details\n\n",
"height": 1160,
"width": 1172,
"color": 4
},
"id": "c642a6e2-6ff8-4d80-9f40-d568edc34940",
"name": "\ud83d\udccb Documentation",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-2144,
304
]
},
{
"parameters": {
"content": "## Phase 1 \u2014 Social Media Data Collection\nFetches your recent posts from all 5 platforms in parallel. Each fetch node has `continueOnFail: true` \u2014 if one platform API is down or credentials are wrong, the workflow continues with the others rather than crashing. A tag Set node after each fetch stamps `_platform` onto the response so the Transform node knows where each item came from. The Merge node (mode: append) waits for all 5 branches before continuing.",
"height": 200,
"width": 960,
"color": 5
},
"id": "4ff61d41-a618-41d6-9456-9db456f96de1",
"name": "\ud83d\udcca Phase 1: Social Collection",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-384,
-448
]
},
{
"parameters": {
"content": "## Phase 2 \u2014 AI Performance Analysis\nNormalizes all platform data into a unified engagement schema, then selects the top 25 posts by engagement rate. A Code node builds the Claude prompt \u2014 injecting your niche, audience, and all post data. Claude analyzes hook patterns, content formats, winning themes, platform-specific tactics, audience psychology, and content gaps. Response is parsed JSON.",
"height": 200,
"width": 680,
"color": 6
},
"id": "732c8415-546a-461a-9030-715ecf0cc2cd",
"name": "\ud83e\udd16 Phase 2: AI Analysis",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
1168,
-464
]
},
{
"parameters": {
"content": "## Phase 3 \u2014 Trend Research (5 Sources in Parallel)\nRuns simultaneously after the performance analysis completes. **Perplexity** returns AI-synthesized trend narrative. **Reddit** returns the top 15 trending posts across your configured subreddits. **X Trending** returns top trending topics with tweet volume. **TikTok Trends** returns trending hashtags and sounds. **Google Trends** returns search interest timeline for your keywords. All 5 merge before idea generation.",
"height": 200,
"width": 960,
"color": 7
},
"id": "b65c7d7a-5f19-4909-b91a-f05eb0cac313",
"name": "\ud83d\udcc8 Phase 3: Trend Research",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
2016,
-464
]
},
{
"parameters": {
"content": "## Phase 4 \u2014 Notion Publishing\nCreates a parent Weekly Report page in your Notion database (rich blocks: theme, priority ideas, quick wins). Then creates 15 child pages under it \u2014 one per content idea \u2014 each with: hook, sub-hook, angle, full outline, CTA, platform recommendation, effort level, repurpose suggestions, and trending connection. Aggregates results into one summary item, then sends Slack notification.",
"height": 200,
"width": 700,
"color": 3
},
"id": "f69f628c-4d27-4586-a50c-c9ffe7875590",
"name": "\ud83d\udcd3 Phase 4: Notion Output",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
3152,
-448
]
},
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 9 * * 1"
}
]
}
},
"id": "de2731b5-daa4-43df-aff9-0dd5c4c5b052",
"name": "\ud83d\udd50 Weekly Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
-816,
592
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "cfg-01",
"name": "twitterUserId",
"value": "YOUR_TWITTER_USER_ID",
"type": "string"
},
{
"id": "cfg-02",
"name": "instagramUserId",
"value": "YOUR_INSTAGRAM_BUSINESS_USER_ID",
"type": "string"
},
{
"id": "cfg-03",
"name": "linkedinAuthorUrn",
"value": "urn:li:person:YOUR_LINKEDIN_PERSON_ID",
"type": "string"
},
{
"id": "cfg-04",
"name": "youtubeChannelId",
"value": "YOUR_YOUTUBE_CHANNEL_ID",
"type": "string"
},
{
"id": "cfg-05",
"name": "niche",
"value": "entrepreneurship, personal finance, productivity",
"type": "string"
},
{
"id": "cfg-06",
"name": "targetAudience",
"value": "ambitious 25-40 year olds building wealth and businesses online",
"type": "string"
},
{
"id": "cfg-07",
"name": "contentGoal",
"value": "grow social following and drive newsletter signups",
"type": "string"
},
{
"id": "cfg-08",
"name": "redditSubreddits",
"value": "Entrepreneur+startups+personalfinance+productivity+SideProject",
"type": "string"
},
{
"id": "cfg-09",
"name": "googleTrendKeywords",
"value": "entrepreneurship,side hustle,passive income,financial freedom",
"type": "string"
},
{
"id": "cfg-10",
"name": "trendResearchQuery",
"value": "What are the biggest trending topics and conversations happening right now in entrepreneurship, personal finance, and productivity in 2025? Focus on emerging trends, viral discussions, and rising topics.",
"type": "string"
},
{
"id": "cfg-11",
"name": "notionDatabaseId",
"value": "YOUR_NOTION_DATABASE_ID",
"type": "string"
},
{
"id": "cfg-12",
"name": "slackWebhookUrl",
"value": "YOUR_SLACK_WEBHOOK_URL",
"type": "string"
},
{
"id": "cfg-13",
"name": "claudeModel",
"value": "claude-opus-4-6",
"type": "string"
},
{
"id": "cfg-14",
"name": "perplexityModel",
"value": "sonar-pro",
"type": "string"
},
{
"id": "cfg-15",
"name": "postsPerPlatform",
"value": "50",
"type": "string"
},
{
"id": "cfg-16",
"name": "contentIdeasCount",
"value": "15",
"type": "string"
},
{
"id": "cfg-17",
"name": "lookbackDays",
"value": "30",
"type": "string"
},
{
"id": "cfg-18",
"name": "tiktokHashtagsToTrack",
"value": "entrepreneur,sidehustle,passiveincome,personaldevelopment",
"type": "string"
}
]
},
"options": {}
},
"id": "e6b0c0d7-f83b-4500-9b76-ec7e44386c48",
"name": "\u2699\ufe0f Config",
"type": "n8n-nodes-base.set",
"typeVersion": 3.3,
"position": [
-576,
592
]
},
{
"parameters": {
"url": "=https://api.twitter.com/2/users/{{ $node['\u2699\ufe0f Config'].json.twitterUserId }}/tweets",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "max_results",
"value": "={{ $node['\u2699\ufe0f Config'].json.postsPerPlatform }}"
},
{
"name": "tweet.fields",
"value": "id,text,created_at,public_metrics,entities,attachments"
},
{
"name": "start_time",
"value": "={{ new Date(Date.now() - parseInt($node['\u2699\ufe0f Config'].json.lookbackDays) * 24 * 60 * 60 * 1000).toISOString() }}"
}
]
},
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"id": "f3429a45-f9dc-4f34-a12f-55e7016a8c25",
"name": "\ud83d\udc26 Fetch Twitter Posts",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-96,
-208
],
"continueOnFail": true
},
{
"parameters": {
"url": "=https://graph.instagram.com/{{ $node['\u2699\ufe0f Config'].json.instagramUserId }}/media",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "fields",
"value": "id,caption,media_type,timestamp,like_count,comments_count,permalink,thumbnail_url"
},
{
"name": "limit",
"value": "={{ $node['\u2699\ufe0f Config'].json.postsPerPlatform }}"
}
]
},
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"id": "0604aa86-3af1-48fb-8b05-2d4d049c2201",
"name": "\ud83d\udcf8 Fetch Instagram Media",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-96,
192
],
"continueOnFail": true
},
{
"parameters": {
"method": "POST",
"url": "https://open.tiktokapis.com/v2/video/list/",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{}
]
},
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"id": "0c3c7d40-56b2-4b38-a599-e76a02999ebb",
"name": "\ud83c\udfb5 Fetch TikTok Videos",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-96,
592
],
"continueOnFail": true
},
{
"parameters": {
"url": "=https://api.linkedin.com/v2/ugcPosts?q=authors&authors=List({{ $node['\u2699\ufe0f Config'].json.linkedinAuthorUrn }})&count={{ $node['\u2699\ufe0f Config'].json.postsPerPlatform }}&sortBy=CREATED&fields=id,created,specificContent,socialDetail",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "LinkedIn-Version",
"value": "202304"
},
{
"name": "X-Restli-Protocol-Version",
"value": "2.0.0"
}
]
},
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"id": "17d14fac-a58e-450e-8efc-0ffabc92d8fe",
"name": "\ud83d\udcbc Fetch LinkedIn Posts",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-96,
992
],
"continueOnFail": true
},
{
"parameters": {
"url": "https://www.googleapis.com/youtube/v3/search",
"authentication": "genericCredentialType",
"genericAuthType": "httpQueryAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "part",
"value": "snippet,statistics"
},
{
"name": "channelId",
"value": "={{ $node['\u2699\ufe0f Config'].json.youtubeChannelId }}"
},
{
"name": "maxResults",
"value": "50"
},
{
"name": "order",
"value": "date"
},
{
"name": "type",
"value": "video"
},
{
"name": "publishedAfter",
"value": "={{ new Date(Date.now() - parseInt($node['\u2699\ufe0f Config'].json.lookbackDays) * 24 * 60 * 60 * 1000).toISOString() }}"
}
]
},
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"id": "9896fc28-4349-48b0-949e-b1c55066ce8a",
"name": "\u25b6\ufe0f Fetch YouTube Videos",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-96,
1392
],
"continueOnFail": true
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "tag-tw",
"name": "_platform",
"value": "twitter",
"type": "string"
}
]
},
"options": {}
},
"id": "791c2dc9-4224-4d97-b4e7-e25205810ee8",
"name": "\ud83c\udff7\ufe0f Tag Twitter",
"type": "n8n-nodes-base.set",
"typeVersion": 3.3,
"position": [
144,
-208
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "tag-ig",
"name": "_platform",
"value": "instagram",
"type": "string"
}
]
},
"options": {}
},
"id": "dfd2a46f-619b-4729-ae24-e227d901c1f4",
"name": "\ud83c\udff7\ufe0f Tag Instagram",
"type": "n8n-nodes-base.set",
"typeVersion": 3.3,
"position": [
144,
192
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "tag-tt",
"name": "_platform",
"value": "tiktok",
"type": "string"
}
]
},
"options": {}
},
"id": "4f8f95ba-4179-45ca-9fe5-6e5ded804baa",
"name": "\ud83c\udff7\ufe0f Tag TikTok",
"type": "n8n-nodes-base.set",
"typeVersion": 3.3,
"position": [
144,
592
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "tag-li",
"name": "_platform",
"value": "linkedin",
"type": "string"
}
]
},
"options": {}
},
"id": "ac8d038c-cef2-44f6-ba45-163389b79074",
"name": "\ud83c\udff7\ufe0f Tag LinkedIn",
"type": "n8n-nodes-base.set",
"typeVersion": 3.3,
"position": [
144,
992
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "tag-yt",
"name": "_platform",
"value": "youtube",
"type": "string"
}
]
},
"options": {}
},
"id": "3d246de5-5b09-47e6-9229-82e7452d83bd",
"name": "\ud83c\udff7\ufe0f Tag YouTube",
"type": "n8n-nodes-base.set",
"typeVersion": 3.3,
"position": [
144,
1392
]
},
{
"parameters": {},
"id": "06c2490a-9ed9-4e3e-b9f7-ba3256b97398",
"name": "\ud83d\udd00 Merge Social Data",
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
384,
592
]
},
{
"parameters": {
"jsCode": "// ============================================================\n// Transform & Normalize Social Media Data\n// Converts all platform API responses into a unified format\n// sorted by engagement rate for AI analysis\n// ============================================================\n\nconst allItems = $input.all();\nconst normalizedPosts = [];\n\nfor (const item of allItems) {\n const d = item.json;\n const platform = d._platform;\n if (!platform) continue;\n\n switch (platform) {\n\n case 'twitter': {\n const tweets = d.data || [];\n for (const t of tweets) {\n const m = t.public_metrics || {};\n const interactions = (m.like_count || 0) + (m.reply_count || 0) + (m.retweet_count || 0) + (m.quote_count || 0);\n const impressions = Math.max(m.impression_count || 0, 1);\n normalizedPosts.push({\n platform: 'twitter',\n id: t.id,\n content: t.text || '',\n hook: (t.text || '').split('\\n')[0].substring(0, 200),\n created_at: t.created_at,\n likes: m.like_count || 0,\n comments: m.reply_count || 0,\n shares: (m.retweet_count || 0) + (m.quote_count || 0),\n views: m.impression_count || 0,\n engagement_rate: parseFloat(((interactions / impressions) * 100).toFixed(4)),\n url: `https://twitter.com/i/web/status/${t.id}`,\n format: (t.text || '').length > 280 ? 'thread' : 'tweet'\n });\n }\n break;\n }\n\n case 'instagram': {\n const posts = d.data || [];\n for (const p of posts) {\n const likes = p.like_count || 0;\n const comments = p.comments_count || 0;\n // Instagram doesn't always return impressions in basic fields\n // Use a conservative estimate of 10x engagement as a fallback\n const impressions = Math.max(likes * 10 + comments * 5, 1);\n normalizedPosts.push({\n platform: 'instagram',\n id: p.id,\n content: p.caption || '',\n hook: (p.caption || '').split('\\n')[0].substring(0, 200),\n created_at: p.timestamp,\n likes,\n comments,\n shares: 0,\n views: impressions,\n engagement_rate: parseFloat((((likes + comments) / impressions) * 100).toFixed(4)),\n url: p.permalink || '',\n format: p.media_type === 'VIDEO' ? 'reel'\n : p.media_type === 'CAROUSEL_ALBUM' ? 'carousel'\n : 'image'\n });\n }\n break;\n }\n\n case 'tiktok': {\n const videos = (d.data && d.data.videos) ? d.data.videos : (d.data || []);\n for (const v of videos) {\n const likes = v.like_count || 0;\n const comments = v.comment_count || 0;\n const shares = v.share_count || 0;\n const views = Math.max(v.view_count || 0, 1);\n normalizedPosts.push({\n platform: 'tiktok',\n id: v.id,\n content: v.video_description || v.title || '',\n hook: (v.video_description || v.title || '').split('\\n')[0].substring(0, 200),\n created_at: new Date((v.create_time || 0) * 1000).toISOString(),\n likes,\n comments,\n shares,\n views,\n engagement_rate: parseFloat((((likes + comments + shares) / views) * 100).toFixed(4)),\n url: v.share_url || '',\n format: 'video'\n });\n }\n break;\n }\n\n case 'linkedin': {\n const posts = d.elements || [];\n for (const p of posts) {\n const shareContent = p.specificContent?.['com.linkedin.ugc.ShareContent'] || {};\n const body = shareContent.shareCommentary?.text || '';\n const stats = p.socialDetail?.totalSocialActivityCounts || {};\n const likes = stats.numLikes || 0;\n const comments = stats.numComments || 0;\n const impressions = Math.max(stats.numImpressions || 0, 1);\n normalizedPosts.push({\n platform: 'linkedin',\n id: p.id,\n content: body,\n hook: body.split('\\n')[0].substring(0, 200),\n created_at: new Date(p.created?.time || 0).toISOString(),\n likes,\n comments,\n shares: stats.numShares || 0,\n views: impressions,\n engagement_rate: parseFloat((((likes + comments) / impressions) * 100).toFixed(4)),\n url: `https://www.linkedin.com/feed/update/${p.id}`,\n format: shareContent.shareMediaCategory === 'VIDEO' ? 'video'\n : shareContent.shareMediaCategory === 'IMAGE' ? 'image'\n : 'post'\n });\n }\n break;\n }\n\n case 'youtube': {\n const videos = d.items || [];\n for (const v of videos) {\n const stats = v.statistics || {};\n const likes = parseInt(stats.likeCount || 0);\n const comments = parseInt(stats.commentCount || 0);\n const views = Math.max(parseInt(stats.viewCount || 0), 1);\n const title = v.snippet?.title || '';\n const description = (v.snippet?.description || '').substring(0, 500);\n normalizedPosts.push({\n platform: 'youtube',\n id: v.id?.videoId || (typeof v.id === 'string' ? v.id : ''),\n content: `${title}\\n\\n${description}`,\n hook: title,\n created_at: v.snippet?.publishedAt,\n likes,\n comments,\n shares: 0,\n views,\n engagement_rate: parseFloat((((likes + comments) / views) * 100).toFixed(4)),\n url: `https://youtube.com/watch?v=${v.id?.videoId || v.id}`,\n format: 'video'\n });\n }\n break;\n }\n }\n}\n\n// Sort by engagement rate descending \u2014 top performers first\nnormalizedPosts.sort((a, b) => b.engagement_rate - a.engagement_rate);\n\n// Build platform breakdown summary\nconst platformCounts = normalizedPosts.reduce((acc, p) => {\n acc[p.platform] = (acc[p.platform] || 0) + 1;\n return acc;\n}, {});\n\n// Select top 25 for AI analysis (keeps Claude prompt lean)\nconst top25 = normalizedPosts.slice(0, 25);\n\nconsole.log(`Normalized ${normalizedPosts.length} posts across ${Object.keys(platformCounts).length} platforms`);\n\nreturn [{\n json: {\n posts: normalizedPosts,\n top25,\n total: normalizedPosts.length,\n platformCounts,\n generatedAt: new Date().toISOString()\n }\n}];"
},
"id": "e354d957-35d6-4b54-afdc-7b050dfbcfbc",
"name": "\ud83d\udd04 Transform & Normalize",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
624,
592
]
},
{
"parameters": {
"jsCode": "// Build the Anthropic API request body for performance analysis.\n// Sends top 25 posts + creator context to Claude for deep pattern extraction.\n\nconst data = $input.first().json;\nconst cfg = $('\u2699\ufe0f Config').first().json;\nconst top25 = data.top25 || [];\n\n// Slim the post data to just what the model needs (saves tokens)\nconst postsForAnalysis = top25.map(p => ({\n platform: p.platform,\n hook: p.hook,\n format: p.format,\n engagement_rate_pct: p.engagement_rate,\n likes: p.likes,\n comments: p.comments,\n shares: p.shares,\n views: p.views\n}));\n\nconst prompt = `You are a world-class content strategist and copywriter who specializes in viral social media growth.\n\nCREATOR CONTEXT\n- Niche: ${cfg.niche}\n- Target Audience: ${cfg.targetAudience}\n- Primary Goal: ${cfg.contentGoal}\n- Total Posts Analyzed: ${data.total}\n- Platform Breakdown: ${JSON.stringify(data.platformCounts)}\n\nTOP ${top25.length} POSTS BY ENGAGEMENT RATE:\n${JSON.stringify(postsForAnalysis, null, 2)}\n\nAnalyze these posts and return a JSON object with EXACTLY this structure. Be specific and data-driven \u2014 cite actual hooks and patterns from the data:\n\n{\n \"top_hook_patterns\": [\n {\n \"pattern_name\": \"e.g. The Uncomfortable Truth\",\n \"description\": \"psychological reason this stops the scroll\",\n \"example_hooks\": [\"exact hook 1 from the data\", \"exact hook 2\"],\n \"avg_engagement_rate\": 0.00,\n \"best_platform\": \"platform name\",\n \"use_when\": \"specific trigger for using this hook\"\n }\n ],\n \"top_content_formats\": [\n {\n \"format\": \"thread|carousel|reel|video|post|tweet\",\n \"why_it_works\": \"mechanism of engagement\",\n \"best_example_hook\": \"top hook using this format\",\n \"avg_engagement_rate\": 0.00,\n \"ideal_length\": \"e.g. 5-7 bullet points, 60-90 second video\"\n }\n ],\n \"winning_themes\": [\n {\n \"theme\": \"theme name\",\n \"description\": \"why this resonates with the specific audience\",\n \"post_count\": 0,\n \"avg_engagement_rate\": 0.00\n }\n ],\n \"platform_insights\": {\n \"twitter\": { \"what_works\": \"\", \"hook_style\": \"\", \"optimal_length\": \"\", \"posting_tip\": \"\" },\n \"instagram\": { \"what_works\": \"\", \"hook_style\": \"\", \"optimal_format\": \"\", \"posting_tip\": \"\" },\n \"tiktok\": { \"what_works\": \"\", \"hook_style\": \"\", \"content_style\": \"\", \"posting_tip\": \"\" },\n \"linkedin\": { \"what_works\": \"\", \"hook_style\": \"\", \"tone\": \"\", \"posting_tip\": \"\" },\n \"youtube\": { \"what_works\": \"\", \"title_pattern\": \"\", \"thumbnail_concept\": \"\", \"posting_tip\": \"\" }\n },\n \"audience_insights\": {\n \"pain_points_that_drive_engagement\": [\"string\"],\n \"desires_that_drive_engagement\": [\"string\"],\n \"emotional_triggers\": [\"string\"],\n \"language_patterns\": [\"exact phrases that appear in high-performing hooks\"]\n },\n \"content_gaps\": [\"topics your audience likely wants that your top posts haven't covered\"],\n \"strategic_summary\": \"3-4 sentences: what's working, why, and the single biggest opportunity to improve performance\"\n}\n\nReturn ONLY the JSON object. No markdown fences, no explanation text outside the JSON.`;\n\nreturn [{\n json: {\n model: cfg.claudeModel || 'claude-opus-4-6',\n max_tokens: 4096,\n messages: [{ role: 'user', content: prompt }]\n }\n}];"
},
"id": "3569087d-28c4-4bb8-93ee-84851fe8487f",
"name": "\ud83d\udccb Prepare Analyze Request",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
864,
592
]
},
{
"parameters": {
"method": "POST",
"url": "https://api.anthropic.com/v1/messages",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "anthropic-version",
"value": "2023-06-01"
},
{
"name": "content-type",
"value": "application/json"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{}
]
},
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"id": "3367c0d9-5d0d-4bca-951c-c4f282d97229",
"name": "\ud83e\udd16 Analyze Top Performers",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1104,
592
]
},
{
"parameters": {
"method": "POST",
"url": "https://api.perplexity.ai/chat/completions",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{}
]
},
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"id": "ae2b3917-c4d6-4d77-a360-6d983dfdd018",
"name": "\ud83d\udd0d Perplexity Research",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1344,
-208
],
"continueOnFail": true
},
{
"parameters": {
"url": "=https://oauth.reddit.com/r/{{ $node['\u2699\ufe0f Config'].json.redditSubreddits }}/hot.json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "limit",
"value": "25"
},
{
"name": "t",
"value": "week"
}
]
},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "User-Agent",
"value": "ContentIntelligence/1.0 (by /u/yourusername)"
}
]
},
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"id": "c80deb4d-e3e5-45c0-95fc-183dffcb7fef",
"name": "\ud83d\udc7d Reddit Trends",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1344,
192
],
"continueOnFail": true
},
{
"parameters": {
"url": "https://api.twitter.com/2/trends/by/woeid/1",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"id": "a7c66123-372f-4411-a017-54d1a6de1dc5",
"name": "\ud83d\udcc8 Fetch X Trending",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1344,
592
],
"continueOnFail": true
},
{
"parameters": {
"method": "POST",
"url": "https://open.tiktokapis.com/v2/research/hashtag/query/",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{}
]
},
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"id": "fa7376c8-81f8-45aa-8e77-f7af2608b95c",
"name": "\ud83c\udfb5 TikTok Trend Research",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1344,
992
],
"continueOnFail": true
},
{
"parameters": {
"url": "https://serpapi.com/search.json",
"authentication": "genericCredentialType",
"genericAuthType": "httpQueryAuth",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "engine",
"value": "google_trends"
},
{
"name": "q",
"value": "={{ $node['\u2699\ufe0f Config'].json.googleTrendKeywords }}"
},
{
"name": "data_type",
"value": "TIMESERIES"
},
{
"name": "date",
"value": "today 1-m"
},
{
"name": "geo",
"value": "US"
}
]
},
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"id": "46d94154-a8c5-4bf1-ad2d-cb51d6e7bdfc",
"name": "\ud83d\udd0e Google Trends via SerpAPI",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1344,
1392
],
"continueOnFail": true
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "tag-px",
"name": "_source",
"value": "perplexity",
"type": "string"
}
]
},
"options": {}
},
"id": "168f9b41-b0f1-4f75-a5ec-c88f4bb23e3f",
"name": "\ud83c\udff7\ufe0f Tag Perplexity",
"type": "n8n-nodes-base.set",
"typeVersion": 3.3,
"position": [
1584,
-208
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "tag-rd",
"name": "_source",
"value": "reddit",
"type": "string"
}
]
},
"options": {}
},
"id": "d8352385-ce7a-4b98-9d20-e9e9d8d2795d",
"name": "\ud83c\udff7\ufe0f Tag Reddit",
"type": "n8n-nodes-base.set",
"typeVersion": 3.3,
"position": [
1584,
192
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "tag-xt",
"name": "_source",
"value": "x_trending",
"type": "string"
}
]
},
"options": {}
},
"id": "72198938-3c6a-42d7-a791-d43a352a1a68",
"name": "\ud83c\udff7\ufe0f Tag X Trending",
"type": "n8n-nodes-base.set",
"typeVersion": 3.3,
"position": [
1584,
592
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "tag-tkt",
"name": "_source",
"value": "tiktok_trends",
"type": "string"
}
]
},
"options": {}
},
"id": "0a8f1f0d-f8d3-4c2c-add5-1bd405020f3d",
"name": "\ud83c\udff7\ufe0f Tag TikTok Trends",
"type": "n8n-nodes-base.set",
"typeVersion": 3.3,
"position": [
1584,
992
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "tag-gt",
"name": "_source",
"value": "google_trends",
"type": "string"
}
]
},
"options": {}
},
"id": "a7c947ea-5ab9-4e1d-9edc-c7d7abe462f6",
"name": "\ud83c\udff7\ufe0f Tag Google Trends",
"type": "n8n-nodes-base.set",
"typeVersion": 3.3,
"position": [
1584,
1392
]
},
{
"parameters": {},
"id": "0ff8bba7-d1c6-4af4-bcb5-7c7d5484aa40",
"name": "\ud83d\udd00 Merge Trend Research",
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
1824,
592
]
},
{
"parameters": {
"jsCode": "// Build the Anthropic API request for content idea generation.\n// Combines performance analysis output + all trend research into one prompt.\n\nconst cfg = $('\u2699\ufe0f Config').first().json;\nconst trendItems = $input.all();\n\n// ---- Parse performance analysis from Claude ----\nlet analysis = {};\ntry {\n const analyzeResponse = $('\ud83e\udd16 Analyze Top Performers').first().json;\n const rawText = analyzeResponse.content?.[0]?.text || '';\n // Try direct parse first, then strip markdown fences if needed\n try {\n analysis = JSON.parse(rawText);\n } catch (e1) {\n const match = rawText.match(/```(?:json)?\\s*([\\s\\S]*?)\\s*```/) || rawText.match(/\\{[\\s\\S]*\\}/);\n analysis = match ? JSON.parse(match[1] || match[0]) : {};\n }\n} catch (e) {\n console.log('Could not parse analysis response, continuing with empty analysis');\n analysis = {};\n}\n\n// ---- Compile trend research from all 5 sources ----\nconst trends = {};\nfor (const item of trendItems) {\n const d = item.json;\n switch (d._source) {\n case 'perplexity':\n trends.perplexity = d.choices?.[0]?.message?.content || '';\n break;\n case 'reddit':\n trends.reddit_hot = (d.data?.children || []).slice(0, 15).map(p => ({\n title: p.data?.title,\n score: p.data?.score,\n subreddit: p.data?.subreddit,\n num_comments: p.data?.num_comments\n }));\n break;\n case 'x_trending':\n trends.x_trending = d.data || [];\n break;\n case 'tiktok_trends':\n trends.tiktok_hashtags = d.data?.hashtags || d;\n break;\n case 'google_trends':\n trends.google_trends = {\n keywords: cfg.googleTrendKeywords,\n timeline: d.interest_over_time?.timeline_data?.slice(-4) || []\n };\n break;\n }\n}\n\nconst prompt = `You are a world-class content strategist. Using our performance data and current trend research, generate exactly ${cfg.contentIdeasCount || 15} high-potential content ideas.\n\nCREATOR CONTEXT\n- Niche: ${cfg.niche}\n- Target Audience: ${cfg.targetAudience}\n- Content Goal: ${cfg.contentGoal}\n\nWHAT WORKS FOR THIS CREATOR (performance analysis)\n${JSON.stringify({\n top_hooks: analysis.top_hook_patterns?.slice(0, 5),\n winning_themes: analysis.winning_themes?.slice(0, 5),\n pain_points: analysis.audience_insights?.pain_points_that_drive_engagement,\n desires: analysis.audience_insights?.desires_that_drive_engagement,\n language_patterns: analysis.audience_insights?.language_patterns,\n content_gaps: analysis.content_gaps,\n summary: analysis.strategic_summary\n}, null, 2)}\n\nCURRENT TREND INTELLIGENCE (this week)\n${JSON.stringify(trends, null, 2)}\n\nGenerate exactly ${cfg.contentIdeasCount || 15} content ideas. For each idea, write the hook as the ACTUAL first sentence/line of the content \u2014 not a description of the hook. Return ONLY this JSON object:\n\n{\n \"weekly_theme\": \"string \u2014 single overarching theme that connects the best ideas this week\",\n \"theme_rationale\": \"string \u2014 why this theme is timely and resonant right now\",\n \"content_ideas\": [\n {\n \"id\": 1,\n \"title\": \"string \u2014 compelling title for the content piece\",\n \"hook\": \"string \u2014 THE ACTUAL FIRST LINE of the content (not a description \u2014 write the real hook)\",\n \"sub_hook\": \"string \u2014 the second sentence that deepens the tension or promise\",\n \"angle\": \"string \u2014 the unique perspective, contrarian take, or unexpected frame\",\n \"format\": \"tweet|thread|carousel|reel|youtube-video|linkedin-post|tiktok-video\",\n \"primary_platform\": \"string\",\n \"secondary_platforms\": [\"string\"],\n \"trending_connection\": \"string \u2014 specific trend/data point from our research this taps into\",\n \"performance_basis\": \"string \u2014 which of our proven patterns this leverages and why it will work\",\n \"outline\": [\"string \u2014 point 1\", \"string \u2014 point 2\", \"string \u2014 point 3\", \"string \u2014 point 4\", \"string \u2014 point 5\"],\n \"cta\": \"string \u2014 exact call-to-action text\",\n \"hook_pattern_used\": \"string \u2014 which top hook pattern from our analysis this uses\",\n \"potential_score\": 8.5,\n \"effort_level\": \"low|medium|high\",\n \"estimated_time_minutes\": 30,\n \"tags\": [\"string\"],\n \"repurpose_ideas\": [\"string \u2014 how to repurpose across other platforms\"]\n }\n ],\n \"priority_ideas\": [1, 3, 7],\n \"quick_wins\": [2, 5],\n \"batch_recording_sets\": [\n {\n \"theme\": \"string \u2014 batch session theme\",\n \"idea_ids\": [1, 4, 8],\n \"rationale\": \"string \u2014 why these work well to record together\"\n }\n ]\n}\n\nReturn ONLY the JSON object. No markdown fences. No text outside the JSON.`;\n\nreturn [{\n json: {\n model: cfg.claudeModel || 'claude-opus-4-6',\n max_tokens: 8192,\n messages: [{ role: 'user', content: prompt }]\n }\n}];"
},
"id": "f42b63cf-e075-4a50-9cec-006a39854e77",
"name": "\ud83d\udccb Prepare Ideas Request",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2064,
592
]
},
{
"parameters": {
"method": "POST",
"url": "https://api.anthropic.com/v1/messages",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "anthropic-version",
"value": "2023-06-01"
},
{
"name": "content-type",
"value": "application/json"
}
]
},
"sendBody": true,
"bodyParameters": {
"parameters": [
{}
]
},
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"id": "c0d83749-b2b8-47ac-88a7-7bc9e43e3916",
"name": "\ud83d\udca1 Generate Content Ideas",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2304,
592
]
},
{
"parameters": {
"jsCode": "// Parse Claude's content ideas response and prepare data for Notion\nconst claudeResponse = $input.first().json;\nconst cfg = $('\u2699\ufe0f Config').first().json;\nconst rawContent = claudeResponse.content?.[0]?.text || '';\n\nlet ideasData = {};\ntry {\n ideasData = JSON.parse(rawContent);\n} catch (e) {\n // Try stripping markdown code fences if present\n const match = rawContent.match(/```(?:json)?\\s*([\\s\\S]*?)\\s*```/) || rawContent.match(/\\{[\\s\\S]*\\}/);\n if (match) {\n try {\n ideasData = JSON.parse(match[1] || match[0]);\n } catch (e2) {\n throw new Error(`Could not parse Claude response as JSON: ${e2.message}\\n\\nRaw response: ${rawContent.substring(0, 500)}`);\n }\n } else {\n throw new Error('No valid JSON found in Claude response');\n }\n}\n\nconst now = new Date();\nconst weekStr = now.toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' });\nconst ideas = ideasData.content_ideas || [];\n\n// Build platform insights summary from Phase 2 analysis\nlet analysisSummary = 'See analysis output for details.';\ntry {\n const analyzeResponse = $('\ud83e\udd16 Analyze Top Performers').first().json;\n const analysisRaw = analyzeResponse.content?.[0]?.text || '';\n const analysisData = JSON.parse(analysisRaw);\n analysisSummary = analysisData.strategic_summary || analysisSummary;\n} catch (e) {\n // Non-fatal \u2014 use fallback\n}\n\nconsole.log(`Parsed ${ideas.length} content ideas. Weekly theme: ${ideasData.weekly_theme}`);\n\nreturn [{\n json: {\n reportTitle: `\ud83d\udcca Content Intelligence Report \u2014 Week of ${weekStr}`,\n weeklyTheme: ideasData.weekly_theme || 'Content Strategy Week',\n themeRationale: ideasData.theme_rationale || '',\n analysisSummary,\n totalIdeas: ideas.length,\n priorityIdeas: ideasData.priority_ideas || [],\n quickWins: ideasData.quick_wins || [],\n batchSets: ideasData.batch_recording_sets || [],\n generatedAt: now.toISOString(),\n ideas,\n notionDatabaseId: cfg.notionDatabaseId,\n niche: cfg.niche,\n targetAudience: cfg.targetAudience\n }\n}];"
},
"id": "961bbf43-65ac-40cf-8d18-c412a52e0f91",
"name": "\ud83d\udcdd Format Notion Report Data",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2544,
592
]
},
{
"parameters": {
"pageId": {
"__rl": true,
"mode": "url",
"value": ""
},
"title": "={{ $json.reportTitle }}",
"blockUi": {
"blockValues": [
{
"type": "callout"
},
{
"type": "heading_2",
"textContent": "\ud83d\uddd3\ufe0f Weekly Theme"
},
{
"type": "quote"
},
{
"textContent": "={{ $json.themeRationale }}"
},
{
"type": "heading_2",
"textContent": "\ud83d\udcca Performance Intelligence Summary"
},
{
"textContent": "={{ $json.analysisSummary }}"
},
{
"type": "heading_2",
"textContent": "\u2b50 Priority Ideas This Week"
},
{
"textContent": "={{ `Ideas #${$json.priorityIdeas.join(', #')} \u2014 highest potential based on performance data + trend alignment` }}"
},
{
"type": "heading_2",
"textContent": "\u26a1 Quick Wins (Low Effort, High Impact)"
},
{
"textContent": "={{ `Ideas #${$json.quickWins.join(', #')} \u2014 can be produced and published within 30-60 minutes` }}"
},
{
"type": "heading_2",
"textContent": "\ud83c\udfac Batch Recording Sets"
},
{
"textContent": "={{ $json.batchSets.map(s => `**${s.theme}** (Ideas ${s.idea_ids.join(', ')}): ${s.rationale}`).join('\\n\\n') }}"
},
{
"type": "divider"
},
{
"type": "heading_2",
"textContent": "={{ `\ud83d\udca1 ${$json.totalIdeas} Content Ideas` }}"
},
{
"textContent": "Individual idea pages are linked below. \u2b50 = Priority \u26a1 = Quick Win"
}
]
},
"options": {}
},
"id": "4442e924-e440-4cde-9c9f-1e2961284663",
"name": "\ud83d\udcd3 Create Notion Report Page",
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
2784,
592
]
},
{
"parameters": {
"jsCode": "// Split the ideas array into individual items.\n// n8n will run the downstream Notion node once per item,\n// creating one child page per content idea.\n\nconst reportData = $('\ud83d\udcdd Format Notion Report Data').first().json;\nconst notionResult = $input.first().json;\n\n// The Notion API returns the created page's ID \u2014 we need this as the parent\nconst parentPageId = notionResult.id || '';\n\nif (!parentPageId) {\n throw new Error('No parent page ID returned from Notion. Check Notion credentials and database ID.');\n}\n\nconst ideas = reportData.ideas || [];\nconst priorityIds = reportData.priorityIdeas || [];\nconst quickWinIds = reportData.quickWins || [];\n\nconsole.log(`Creating ${ideas.length} idea pages as children of page ${parentPageId}`);\n\n// Return one item per idea \u2014 each becomes one Notion child page\nreturn ideas.map(idea => ({\n json: {\n parentPageId,\n ...idea,\n isPriority: priorityIds.includes(idea.id),\n isQuickWin: quickWinIds.includes(idea.id),\n weeklyTheme: reportData.weeklyTheme,\n niche: reportData.niche\n }\n}));"
},
"id": "d0689e13-3895-44b5-ad7b-2126fd05c2a4",
"name": "\ud83d\uddc2\ufe0f Prepare Idea Items",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
3024,
592
]
},
{
"parameters": {
"pageId": "={{ $json.parentPageId }}",
"title": "={{ `${$json.isPriority ? '\u2b50 ' : ''}${$json.isQuickWin ? '\u26a1 ' : ''}#${$json.id} \u2014 ${$json.title}` }}",
"blockUi": {
"blockValues": [
{
"type": "callout"
},
{
"type": "quote"
},
{
"type": "heading_3",
"textContent": "\ud83d\udcd0 Angle"
},
{
"textContent": "={{ $json.angle }}"
},
{
"type": "heading_3",
"textContent": "\ud83d\udccb Outline"
},
{
"type": "bulleted_list_item",
"textContent": "={{ $json.outline[0] || '' }}"
},
{
"type": "bulleted_list_item",
"textContent": "={{ $json.outline[1] || '' }}"
},
{
"type": "bulleted_list_item",
"textContent": "={{ $json.outline[2] || '' }}"
},
{
"type": "bulleted_list_item",
"textContent": "={{ $json.outline[3] || '' }}"
},
{
"type": "bulleted_list_item",
"textContent": "={{ $json.outline[4] || '' }}"
},
{
"type": "heading_3",
"textContent": "\ud83d\udd27 Production Details"
},
{
"textContent": "={{ `\ud83d\udce3 CTA: ${$json.cta}` }}"
},
{
"textContent": "={{ `\ud83c\udfaf Primary Platform: ${$json.primary_platform} | Format: ${$json.format}` }}"
},
{
"textContent": "={{ `\ud83d\udd01 Also Post On: ${($json.secondary_platforms || []).join(', ')}` }}"
},
{
"textContent": "={{ `\u23f1 Effort: ${$json.effort_level} | Est. Time: ${$json.estimated_time_minutes} min` }}"
},
{
"textContent": "={{ `\ud83c\udfa3 Hook Pattern: ${$json.hook_pattern_used}` }}"
},
{
"textContent": "={{ `\u2b50 Potential Score: ${$json.potential_score}/10` }}"
},
{
"type": "heading_3",
"textContent": "\ud83d\udcc8 Why This Will Work"
},
{
"textContent": "={{ $json.performance_basis }}"
},
{
"textContent": "={{ `\ud83d\udd25 Trending Connection: ${$json.trending_connection}` }}"
},
{
"type": "heading_3",
"textContent": "\u267b\ufe0f Repurpose Ideas"
},
{
"textContent": "={{ ($json.repurpose_ideas || []).join('\\n\u2022 ') }}"
},
{
"type": "heading_3",
"textContent": "\ud83c\udff7\ufe0f Tags"
},
{
"textContent": "={{ ($json.tags || []).map(t => `#${t}`).join(' ') }}"
}
]
},
"options": {}
},
"id": "3d25716c-4d83-4691-957a-b239cfc75c93",
"name": "\ud83d\udcc4 Create Notion Idea Page",
"type": "n8n-nodes-base.notion",
"typeVersion": 2.2,
"position": [
3264,
592
]
},
{
"parameters": {
"jsCode": "// Collapse N idea-creation results (one per idea) back into\n// a single summary item for the Slack notification.\n\nconst items = $input.all();\nconst cfg = $('\u2699\ufe0f Config').first().json;\nconst reportData = $('\ud83d\udcdd Format Notion Report Data').first().json;\nconst parentPage = $('\ud83d\udcd3 Create Notion Report Page').first().json;\n\nconst successfulPages = items.filter(i => i.json.object === 'page' || i.json.id);\nconst notionUrl = parentPage.url || `https://notion.so/${(parentPage.id || '').replace(/-/g, '')}`;\n\nconsole.log(`Successfully created ${successfulPages.length}/${items.length} idea pages`);\n\nreturn [{\n json: {\n success: true,\n reportTitle: reportData.reportTitle,\n weeklyTheme: reportData.weeklyTheme,\n ideasCreated: successfulPages.length,\n ideasRequested: items.length,\n notionUrl,\n generatedAt: new Date().toISOString(),\n slackMessage: `*\u2705 Weekly Content Intelligence Report Ready*\\n\\n*Theme:* ${reportData.weeklyTheme}\\n*Ideas Created:* ${successfulPages.length}/${items.length}\\n*Notion Report:* ${notionUrl}\\n\\n_Generated ${new Date().toLocaleString()}_`\n }\n}];"
},
"id": "181b2260-594b-4bc9-8097-b304392ac555",
"name": "\ud83d\udcca Aggregate Results",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
3504,
592
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $node['\u2699\ufe0f Config'].json.slackWebhookUrl }}",
"sendBody": true,
"bodyParameters": {
"parameters": [
{}
]
},
"options": {}
},
"id": "1efe4f57-fce9-4d98-9920-6940f4588716",
"name": "\u2705 Success Notification",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
3744,
592
]
},
{
"parameters": {},
"id": "c9b08620-62a0-4a53-9f87-fefee9159483",
"name": "\ud83d\udea8 Error Trigger",
"type": "n8n-nodes-base.errorTrigger",
"typeVersion": 1,
"position": [
-816,
1200
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $node['\u2699\ufe0f Config'].json.slackWebhookUrl }}",
"sendBody": true,
"bodyParameters": {
"parameters": [
{}
]
},
"options": {}
},
"id": "ce7ad89b-074f-4356-a255-2575b2da75c7",
"name": "\ud83d\udd34 Send Error Alert",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-576,
1200
]
}
],
"connections": {
"\ud83d\udd50 Weekly Trigger": {
"main": [
[
{
"node": "\u2699\ufe0f Config",
"type": "main",
"index": 0
}
]
]
},
"\u2699\ufe0f Config": {
"main": [
[
{
"node": "\ud83d\udc26 Fetch Twitter Posts",
"type": "main",
"index": 0
},
{
"node": "\ud83d\udcf8 Fetch Instagram Media",
"type": "main",
"index": 0
},
{
"node": "\ud83c\udfb5 Fetch TikTok Videos",
"type": "main",
"index": 0
},
{
"node": "\ud83d\udcbc Fetch LinkedIn Posts",
"type": "main",
"index": 0
},
{
"node": "\u25b6\ufe0f Fetch YouTube Videos",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\udc26 Fetch Twitter Posts": {
"main": [
[
{
"node": "\ud83c\udff7\ufe0f Tag Twitter",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\udcf8 Fetch Instagram Media": {
"main": [
[
{
"node": "\ud83c\udff7\ufe0f Tag Instagram",
"type": "main",
"index": 0
}
]
]
},
"\ud83c\udfb5 Fetch TikTok Videos": {
"main": [
[
{
"node": "\ud83c\udff7\ufe0f Tag TikTok",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\udcbc Fetch LinkedIn Posts": {
"main": [
[
{
"node": "\ud83c\udff7\ufe0f Tag LinkedIn",
"type": "main",
"index": 0
}
]
]
},
"\u25b6\ufe0f Fetch YouTube Videos": {
"main": [
[
{
"node": "\ud83c\udff7\ufe0f Tag YouTube",
"type": "main",
"index": 0
}
]
]
},
"\ud83c\udff7\ufe0f Tag Twitter": {
"main": [
[
{
"node": "\ud83d\udd00 Merge Social Data",
"type": "main",
"index": 0
}
]
]
},
"\ud83c\udff7\ufe0f Tag Instagram": {
"main": [
[
{
"node": "\ud83d\udd00 Merge Social Data",
"type": "main",
"index": 1
}
]
]
},
"\ud83d\udd00 Merge Social Data": {
"main": [
[
{
"node": "\ud83d\udd04 Transform & Normalize",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\udd04 Transform & Normalize": {
"main": [
[
{
"node": "\ud83d\udccb Prepare Analyze Request",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\udccb Prepare Analyze Request": {
"main": [
[
{
"node": "\ud83e\udd16 Analyze Top Performers",
"type": "main",
"index": 0
}
]
]
},
"\ud83e\
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Social Content Intelligence — Weekly Report. Uses httpRequest, notion, errorTrigger. Scheduled trigger; 42 nodes.
Source: https://github.com/jslizar/builder-lab/blob/dac901bc94368095e42e48185c9bb3f1c5c8e529/automations/n8n-workflows/social-content-intelligence.json — 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.
Daily Business Report Generator. Uses googleSheets, httpRequest, slack, gmail. Scheduled trigger; 17 nodes.
Security teams, DevOps engineers, vulnerability analysts, and automation builders who want to eliminate repetitive Nessus scan parsing, AI-based risk triage, and manual reporting. Designed for orgs fo
This workflow triggers when a HubSpot deal stage changes to Closed Won and automatically generates an invoice. It collects deal and contact data, builds a styled invoice, converts it into a PDF, and s
Generate market research reports from news and competitor sites to Notion and Slack. Uses errorTrigger, httpRequest, notion, googleSheets. Event-driven trigger; 19 nodes.
This workflow automates the daily reporting of Google Ads campaign performance. It pulls click and conversion data from the Google Ads API, merges both datasets, and stores the results into Notion dat