AutomationFlowsSocial Media › Discover Viral Content Opportunities From Twitter, Reddit and Google Trends…

Discover Viral Content Opportunities From Twitter, Reddit and Google Trends…

Original n8n title: Discover Viral Content Opportunities From Twitter, Reddit and Google Trends with Claude AI

ByOneclick AI Squad @oneclick-ai on n8n.io

Automatically discovers trending topics in your niche and generates ready-to-use content ideas with AI. Twitter/X trending topics and hashtags Reddit hot posts from niche subreddits Google Trends daily search trends Runs every 2 hours for fresh opportunities Filters by your…

Cron / scheduled trigger★★★★☆ complexity29 nodesHTTP RequestEmail SendSlackPostgres
Social Media Trigger: Cron / scheduled Nodes: 29 Complexity: ★★★★☆ Added:
Discover Viral Content Opportunities From Twitter, Reddit and Google Trends… — n8n workflow card showing HTTP Request, Email Send, Slack integration

This workflow corresponds to n8n.io template #13707 — we link there as the canonical source.

This workflow follows the Emailsend → 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 →

Download .json
{
  "id": "NgPUu4IA2QDZRRVT",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Smart Viral Content Opportunity Spotter",
  "tags": [],
  "nodes": [
    {
      "id": "3a3acceb-dd95-47a3-a71a-b6560d364690",
      "name": "Every 2 Hours - Trend Scanner",
      "type": "n8n-nodes-base.scheduleTrigger",
      "notes": "Runs every 2 hours to capture fresh trending topics",
      "position": [
        800,
        512
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 2
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 1.2
    },
    {
      "id": "3a1f497e-7af6-4876-812a-11ca06a4f56e",
      "name": "Fetch Twitter/X Trends",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Gets trending topics and hashtags from Twitter API",
      "position": [
        1024,
        320
      ],
      "parameters": {
        "url": "https://api.twitter.com/2/trends/place",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        },
        "sendQuery": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "id",
              "value": "1"
            }
          ]
        },
        "nodeCredentialType": "twitterOAuth2Api"
      },
      "credentials": {
        "twitterOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 4.2
    },
    {
      "id": "03636a38-7087-4f03-a381-603343601e9c",
      "name": "Fetch Reddit Hot Topics",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Retrieves trending posts from relevant subreddits",
      "position": [
        1024,
        512
      ],
      "parameters": {
        "url": "https://oauth.reddit.com/r/{{$node[\"Load Niche Config\"].json.subreddits}}/hot",
        "options": {},
        "sendQuery": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "limit",
              "value": "25"
            },
            {
              "name": "t",
              "value": "day"
            }
          ]
        },
        "nodeCredentialType": "redditOAuth2Api"
      },
      "credentials": {
        "redditOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 4.2
    },
    {
      "id": "65318f86-fefb-4d1f-92e2-1cfda5e1947d",
      "name": "Fetch Google Trends",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Gets trending searches from Google Trends API",
      "position": [
        1024,
        704
      ],
      "parameters": {
        "url": "https://trends.google.com/trends/api/dailytrends",
        "options": {},
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "geo",
              "value": "US"
            },
            {
              "name": "hl",
              "value": "en-US"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 4.2
    },
    {
      "id": "79d27f62-ed94-4a9d-a2eb-f441f328a7f1",
      "name": "Load Niche Config",
      "type": "n8n-nodes-base.code",
      "notes": "Defines your niche keywords, subreddits, and tracking parameters",
      "position": [
        4832,
        416
      ],
      "parameters": {
        "jsCode": "// Configure your niche settings here\nconst nicheConfig = {\n  // Your niche/industry\n  niche: 'AI & Technology',\n  \n  // Primary keywords to track\n  keywords: [\n    'artificial intelligence',\n    'machine learning',\n    'AI tools',\n    'chatgpt',\n    'claude',\n    'automation',\n    'generative ai',\n    'deep learning',\n    'neural networks',\n    'ai ethics'\n  ],\n  \n  // Related subreddits (comma-separated for multi-reddit)\n  subreddits: 'artificial+machinelearning+technology+Futurology',\n  \n  // Twitter accounts to monitor (optional)\n  twitterAccounts: [\n    'OpenAI',\n    'AnthropicAI',\n    'GoogleAI',\n    'DeepMind'\n  ],\n  \n  // Minimum engagement thresholds\n  thresholds: {\n    minTwitterLikes: 1000,\n    minRedditUpvotes: 500,\n    minComments: 50\n  },\n  \n  // Content formats to suggest\n  contentFormats: [\n    'Thread',\n    'Carousel Post',\n    'Video Script',\n    'Long-form Article',\n    'Infographic Outline',\n    'Short-form Video'\n  ],\n  \n  // Target platforms\n  platforms: ['Twitter', 'LinkedIn', 'Instagram', 'TikTok', 'YouTube'],\n  \n  // Time window (hours)\n  timeWindow: 48\n};\n\nreturn [{ json: nicheConfig }];"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "8528d5bc-b800-466a-980b-70d59c518c49",
      "name": "Parse Twitter Data",
      "type": "n8n-nodes-base.code",
      "notes": "Normalizes Twitter trend data into standard format",
      "position": [
        1248,
        320
      ],
      "parameters": {
        "jsCode": "// Parse Twitter API response\nconst response = $input.first().json;\nconst trends = response.data || [];\n\nconst parsed = trends.map(trend => ({\n  source: 'Twitter',\n  topic: trend.name || trend.query || '',\n  description: trend.tweet_volume ? `${trend.tweet_volume} tweets` : 'Trending',\n  url: trend.url || `https://twitter.com/search?q=${encodeURIComponent(trend.name)}`,\n  engagement: trend.tweet_volume || 0,\n  timestamp: new Date().toISOString(),\n  raw: trend\n}));\n\nreturn parsed.map(item => ({ json: item }));"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "30cce528-0118-4a0b-8f78-806562d4b88e",
      "name": "Parse Reddit Data",
      "type": "n8n-nodes-base.code",
      "notes": "Normalizes Reddit post data into standard format",
      "position": [
        1248,
        512
      ],
      "parameters": {
        "jsCode": "// Parse Reddit API response\nconst response = $input.first().json;\nconst posts = response.data?.children || [];\n\nconst parsed = posts.map(post => {\n  const data = post.data;\n  return {\n    source: 'Reddit',\n    topic: data.title,\n    description: data.selftext?.substring(0, 200) || '',\n    url: `https://reddit.com${data.permalink}`,\n    engagement: data.ups + data.num_comments,\n    upvotes: data.ups,\n    comments: data.num_comments,\n    subreddit: data.subreddit,\n    timestamp: new Date(data.created_utc * 1000).toISOString(),\n    raw: data\n  };\n});\n\nreturn parsed.map(item => ({ json: item }));"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "f8fe24fa-9e91-4bd4-9d4d-a048f43d7fb7",
      "name": "Parse Google Trends",
      "type": "n8n-nodes-base.code",
      "notes": "Normalizes Google Trends data into standard format",
      "position": [
        1248,
        704
      ],
      "parameters": {
        "jsCode": "// Parse Google Trends response (remove leading characters)\nlet response = $input.first().json.toString();\nif (response.startsWith(')]}\\',\\n')) {\n  response = response.substring(6);\n}\n\ntry {\n  const data = JSON.parse(response);\n  const trends = data.default?.trendingSearchesDays?.[0]?.trendingSearches || [];\n  \n  const parsed = trends.map(trend => {\n    const articles = trend.articles || [];\n    const totalTraffic = parseInt(trend.formattedTraffic?.replace(/[^0-9]/g, '') || '0');\n    \n    return {\n      source: 'Google Trends',\n      topic: trend.title?.query || '',\n      description: articles[0]?.title || '',\n      url: articles[0]?.url || `https://trends.google.com/trends/trendingsearches/daily?geo=US`,\n      engagement: totalTraffic,\n      traffic: trend.formattedTraffic || 'N/A',\n      timestamp: new Date().toISOString(),\n      raw: trend\n    };\n  });\n  \n  return parsed.map(item => ({ json: item }));\n  \n} catch (error) {\n  console.error('Failed to parse Google Trends:', error);\n  return [];\n}"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "f0f79024-acfe-47d5-89d1-73355a2db52f",
      "name": "Merge All Trend Sources",
      "type": "n8n-nodes-base.merge",
      "notes": "Combines data from Twitter, Reddit, and Google Trends",
      "position": [
        1472,
        416
      ],
      "parameters": {},
      "notesInFlow": true,
      "typeVersion": 3
    },
    {
      "id": "2a9d4fa8-704b-4176-a44f-d98a3d20a135",
      "name": "Filter by Niche Keywords",
      "type": "n8n-nodes-base.code",
      "notes": "Matches trends against your niche keywords for relevance",
      "position": [
        1696,
        416
      ],
      "parameters": {
        "jsCode": "// Filter trends by niche relevance\nconst items = $input.all();\nconst config = $node['Load Niche Config'].json;\nconst keywords = config.keywords.map(k => k.toLowerCase());\n\nconst relevantTrends = items.filter(item => {\n  const text = `${item.json.topic} ${item.json.description}`.toLowerCase();\n  \n  // Check if any keyword matches\n  return keywords.some(keyword => text.includes(keyword));\n}).map(item => ({\n  json: {\n    ...item.json,\n    relevanceScore: 0 // Will be calculated in next node\n  }\n}));\n\nreturn relevantTrends;"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "aefdb520-4fe3-44f2-9272-d65b6703dcd6",
      "name": "Remove Duplicate Topics",
      "type": "n8n-nodes-base.code",
      "notes": "Deduplicates similar trends from different sources",
      "position": [
        1920,
        416
      ],
      "parameters": {
        "jsCode": "// Remove duplicate or very similar topics\nconst items = $input.all();\nconst seen = new Map();\n\nfunction similarity(str1, str2) {\n  const s1 = str1.toLowerCase().split(' ');\n  const s2 = str2.toLowerCase().split(' ');\n  const intersection = s1.filter(word => s2.includes(word));\n  return intersection.length / Math.max(s1.length, s2.length);\n}\n\nconst unique = [];\n\nfor (const item of items) {\n  const topic = item.json.topic;\n  let isDuplicate = false;\n  \n  for (const [seenTopic, seenItem] of seen.entries()) {\n    if (similarity(topic, seenTopic) > 0.7) {\n      // Keep the one with higher engagement\n      if (item.json.engagement > seenItem.json.engagement) {\n        seen.delete(seenTopic);\n        seen.set(topic, item);\n      }\n      isDuplicate = true;\n      break;\n    }\n  }\n  \n  if (!isDuplicate) {\n    seen.set(topic, item);\n  }\n}\n\nreturn Array.from(seen.values()).map(item => ({ json: item.json }));"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "3f532e9e-b713-4f5c-a97c-4f92d6e7a92e",
      "name": "Calculate Viral Potential Score",
      "type": "n8n-nodes-base.code",
      "notes": "Scores each trend based on engagement, recency, and growth",
      "position": [
        2144,
        416
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Calculate viral potential score (0-100)\nconst trend = $input.item.json;\nconst config = $node['Load Niche Config'].json;\n\nlet score = 0;\n\n// Engagement score (0-40 points)\nlet engagementScore = 0;\nif (trend.source === 'Twitter') {\n  engagementScore = Math.min(40, (trend.engagement / 10000) * 40);\n} else if (trend.source === 'Reddit') {\n  engagementScore = Math.min(40, (trend.engagement / 1000) * 40);\n} else if (trend.source === 'Google Trends') {\n  engagementScore = Math.min(40, (trend.engagement / 100000) * 40);\n}\nscore += engagementScore;\n\n// Recency score (0-30 points)\nconst hoursSincePost = (Date.now() - new Date(trend.timestamp).getTime()) / (1000 * 60 * 60);\nconst recencyScore = Math.max(0, 30 - (hoursSincePost / config.timeWindow) * 30);\nscore += recencyScore;\n\n// Source credibility (0-15 points)\nconst sourceScore = {\n  'Google Trends': 15,\n  'Twitter': 12,\n  'Reddit': 10\n}[trend.source] || 5;\nscore += sourceScore;\n\n// Keyword relevance (0-15 points)\nconst text = `${trend.topic} ${trend.description}`.toLowerCase();\nconst matchCount = config.keywords.filter(k => text.includes(k.toLowerCase())).length;\nconst relevanceScore = Math.min(15, matchCount * 5);\nscore += relevanceScore;\n\n// Determine opportunity level\nlet opportunityLevel = 'LOW';\nif (score >= 75) opportunityLevel = 'HIGH';\nelse if (score >= 50) opportunityLevel = 'MEDIUM';\n\nreturn {\n  json: {\n    ...trend,\n    viralScore: Math.round(score),\n    opportunityLevel,\n    scoreBreakdown: {\n      engagement: Math.round(engagementScore),\n      recency: Math.round(recencyScore),\n      source: sourceScore,\n      relevance: Math.round(relevanceScore)\n    }\n  }\n};"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "5fc00882-9c04-42f9-b3d9-6fd1e1a2fd01",
      "name": "Filter High Potential Only",
      "type": "n8n-nodes-base.filter",
      "notes": "Only keeps trends with viral score above 40",
      "position": [
        2368,
        416
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "score-threshold",
              "operator": {
                "type": "number",
                "operation": "largerEqual"
              },
              "leftValue": "={{ $json.viralScore }}",
              "rightValue": 40
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "7e266831-96a7-48d0-b556-068b479f278b",
      "name": "Sort by Viral Score",
      "type": "n8n-nodes-base.code",
      "notes": "Ranks opportunities by score (highest first)",
      "position": [
        2592,
        416
      ],
      "parameters": {
        "jsCode": "// Sort trends by viral score descending\nconst items = $input.all();\nconst sorted = items.sort((a, b) => b.json.viralScore - a.json.viralScore);\n\n// Take top 10\nreturn sorted.slice(0, 10);"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "2a029ebb-ba06-45c9-8c55-4b14e9257217",
      "name": "Check Already Covered",
      "type": "n8n-nodes-base.code",
      "notes": "Prevents suggesting topics you've already created content about",
      "position": [
        2816,
        416
      ],
      "parameters": {
        "jsCode": "// Check against previously covered topics\nconst items = $input.all();\nconst staticData = $getWorkflowStaticData('global');\n\n// Initialize covered topics tracker\nif (!staticData.coveredTopics) {\n  staticData.coveredTopics = {};\n}\n\n// Clean up old entries (older than 30 days)\nconst thirtyDaysAgo = Date.now() - (30 * 24 * 60 * 60 * 1000);\nfor (const key in staticData.coveredTopics) {\n  if (staticData.coveredTopics[key].timestamp < thirtyDaysAgo) {\n    delete staticData.coveredTopics[key];\n  }\n}\n\n// Filter out already covered topics\nconst newOpportunities = items.filter(item => {\n  const topicKey = item.json.topic.toLowerCase().replace(/[^a-z0-9]/g, '');\n  return !staticData.coveredTopics[topicKey];\n}).map(item => ({\n  json: {\n    ...item.json,\n    isNew: true\n  }\n}));\n\nreturn newOpportunities;"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "935c1484-dd12-4015-bad5-5896deeee4ad",
      "name": "AI - Generate Content Ideas",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Uses Claude AI to generate creative content ideas for each trend",
      "position": [
        3040,
        416
      ],
      "parameters": {
        "url": "https://api.anthropic.com/v1/messages",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "model",
              "value": "claude-sonnet-4-20250514"
            },
            {
              "name": "max_tokens",
              "value": "2000"
            },
            {
              "name": "messages",
              "value": "={{ [{role: 'user', content: `You are a viral content strategist. Analyze this trending topic and generate 5 unique, high-engagement content ideas.\n\nTrending Topic: ${$json.topic}\nSource: ${$json.source}\nEngagement: ${$json.engagement}\nContext: ${$json.description}\nNiche: ${$node['Load Niche Config'].json.niche}\n\nFor each idea, provide:\n1. Content Format (Thread, Carousel, Video, Article, etc.)\n2. Hook/Title (attention-grabbing)\n3. Key Points (3-5 bullet points)\n4. Platform Recommendation\n5. Viral Potential Reason\n\nMake ideas actionable, specific, and optimized for virality. Return as JSON array with keys: format, hook, keyPoints (array), platform, viralReason.`}] }}"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "x-api-key",
              "value": "={{ $credentials.apiKey }}"
            },
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            }
          ]
        },
        "nodeCredentialType": "anthropicApi"
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 4.2
    },
    {
      "id": "347f0ef9-3842-4cac-b493-42145afdc67b",
      "name": "Parse AI Content Ideas",
      "type": "n8n-nodes-base.code",
      "notes": "Extracts and structures AI-generated content ideas",
      "position": [
        3264,
        416
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Parse Claude AI response\nconst response = $input.item.json;\nconst trend = $node['Check Already Covered'].all().find(i => i.json.topic === $json.topic).json;\n\ntry {\n  const aiContent = response.content?.[0]?.text || '';\n  \n  // Try to extract JSON from response\n  let ideas = [];\n  const jsonMatch = aiContent.match(/\\[\\s*\\{[\\s\\S]*\\}\\s*\\]/);\n  \n  if (jsonMatch) {\n    ideas = JSON.parse(jsonMatch[0]);\n  } else {\n    // Fallback: create structured response from text\n    ideas = [{\n      format: 'Mixed Content',\n      hook: `${trend.topic} - Viral Opportunity`,\n      keyPoints: [aiContent.substring(0, 200)],\n      platform: 'Multi-platform',\n      viralReason: 'High engagement trend'\n    }];\n  }\n  \n  return {\n    json: {\n      ...trend,\n      contentIdeas: ideas,\n      aiGenerated: true,\n      generatedAt: new Date().toISOString()\n    }\n  };\n  \n} catch (error) {\n  console.error('Failed to parse AI response:', error);\n  return {\n    json: {\n      ...trend,\n      contentIdeas: [],\n      aiGenerated: false,\n      error: error.message\n    }\n  };\n}"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "842024ea-fd0b-4298-b565-6f412a861771",
      "name": "Add Research Links",
      "type": "n8n-nodes-base.code",
      "notes": "Adds relevant research and reference links for each opportunity",
      "position": [
        3488,
        416
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Add research resources\nconst opportunity = $input.item.json;\n\nconst researchLinks = [\n  {\n    type: 'Google Search',\n    url: `https://www.google.com/search?q=${encodeURIComponent(opportunity.topic)}`,\n    purpose: 'General research and fact-checking'\n  },\n  {\n    type: 'Twitter Search',\n    url: `https://twitter.com/search?q=${encodeURIComponent(opportunity.topic)}&f=live`,\n    purpose: 'Real-time conversations and reactions'\n  },\n  {\n    type: 'YouTube',\n    url: `https://www.youtube.com/results?search_query=${encodeURIComponent(opportunity.topic)}`,\n    purpose: 'Video content inspiration'\n  },\n  {\n    type: 'Reddit',\n    url: `https://www.reddit.com/search/?q=${encodeURIComponent(opportunity.topic)}&sort=hot`,\n    purpose: 'Community discussions and insights'\n  }\n];\n\nreturn {\n  json: {\n    ...opportunity,\n    researchLinks,\n    originalSourceUrl: opportunity.url\n  }\n};"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "091c53de-1c97-46f7-97db-4be61d9ebddd",
      "name": "Create Opportunity Report",
      "type": "n8n-nodes-base.code",
      "notes": "Generates comprehensive report for each content opportunity",
      "position": [
        3712,
        416
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Generate detailed opportunity report\nconst opp = $input.item.json;\nconst config = $node['Load Niche Config'].json;\n\nconst report = {\n  // Summary\n  opportunityId: `OPP-${Date.now()}-${Math.random().toString(36).substr(2, 6).toUpperCase()}`,\n  detectedAt: new Date().toISOString(),\n  \n  // Trend Details\n  trend: {\n    topic: opp.topic,\n    source: opp.source,\n    description: opp.description,\n    sourceUrl: opp.url,\n    engagement: opp.engagement,\n    timestamp: opp.timestamp\n  },\n  \n  // Scoring\n  analysis: {\n    viralScore: opp.viralScore,\n    opportunityLevel: opp.opportunityLevel,\n    scoreBreakdown: opp.scoreBreakdown,\n    niche: config.niche\n  },\n  \n  // Content Ideas\n  contentSuggestions: opp.contentIdeas.map((idea, idx) => ({\n    ideaNumber: idx + 1,\n    format: idea.format,\n    hook: idea.hook,\n    keyPoints: idea.keyPoints,\n    platform: idea.platform,\n    viralReason: idea.viralReason,\n    estimatedCreationTime: '2-4 hours'\n  })),\n  \n  // Research Resources\n  resources: opp.researchLinks,\n  \n  // Action Items\n  nextSteps: [\n    '1. Review all content ideas and select the best fit',\n    '2. Conduct additional research using provided links',\n    '3. Create content outline based on selected idea',\n    '4. Develop and publish content within 24-48 hours',\n    '5. Track performance and engagement metrics'\n  ],\n  \n  // Timing\n  urgency: opp.viralScore >= 75 ? 'HIGH - Create within 24 hours' : \n           opp.viralScore >= 50 ? 'MEDIUM - Create within 48 hours' : \n           'LOW - Create when ready',\n  \n  // Metadata\n  metadata: {\n    aiGenerated: opp.aiGenerated,\n    generatedAt: opp.generatedAt,\n    workflowVersion: 'v1.0'\n  }\n};\n\nreturn { json: report };"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "7d064533-3081-4cd9-90a9-b82719cc17e2",
      "name": "Aggregate All Opportunities",
      "type": "n8n-nodes-base.code",
      "notes": "Combines all opportunities into a single digest",
      "position": [
        3936,
        416
      ],
      "parameters": {
        "jsCode": "// Create aggregated report\nconst opportunities = $input.all().map(i => i.json);\n\nconst digest = {\n  scanDate: new Date().toISOString(),\n  totalOpportunities: opportunities.length,\n  \n  summary: {\n    high: opportunities.filter(o => o.analysis.opportunityLevel === 'HIGH').length,\n    medium: opportunities.filter(o => o.analysis.opportunityLevel === 'MEDIUM').length,\n    low: opportunities.filter(o => o.analysis.opportunityLevel === 'LOW').length\n  },\n  \n  topOpportunities: opportunities.slice(0, 5).map(o => ({\n    topic: o.trend.topic,\n    score: o.analysis.viralScore,\n    level: o.analysis.opportunityLevel,\n    source: o.trend.source,\n    bestIdea: o.contentSuggestions[0]?.hook || 'See full report'\n  })),\n  \n  opportunities: opportunities,\n  \n  stats: {\n    averageScore: Math.round(opportunities.reduce((sum, o) => sum + o.analysis.viralScore, 0) / opportunities.length),\n    sources: {\n      twitter: opportunities.filter(o => o.trend.source === 'Twitter').length,\n      reddit: opportunities.filter(o => o.trend.source === 'Reddit').length,\n      googleTrends: opportunities.filter(o => o.trend.source === 'Google Trends').length\n    },\n    totalContentIdeas: opportunities.reduce((sum, o) => sum + o.contentSuggestions.length, 0)\n  }\n};\n\nreturn [{ json: digest }];"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "10104634-bdac-43c9-85ee-de8f3f999171",
      "name": "Send Email Digest",
      "type": "n8n-nodes-base.emailSend",
      "notes": "Sends comprehensive email with all content opportunities",
      "position": [
        4160,
        320
      ],
      "parameters": {
        "options": {},
        "subject": "=\ud83d\ude80 {{ $json.totalOpportunities }} New Viral Content Opportunities Detected",
        "toEmail": "user@example.com",
        "fromEmail": "user@example.com"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 2.1
    },
    {
      "id": "aff49db2-c405-4cb3-8bb5-940daabb2ab8",
      "name": "Send Slack Summary",
      "type": "n8n-nodes-base.slack",
      "notes": "Posts quick summary to Slack channel",
      "position": [
        4160,
        512
      ],
      "parameters": {
        "resource": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 2.1
    },
    {
      "id": "2d9c82ad-9fea-4ef9-82c3-90a06b2f51c6",
      "name": "Log to Content Database",
      "type": "n8n-nodes-base.postgres",
      "notes": "Stores opportunities in database for tracking and analytics",
      "position": [
        4384,
        416
      ],
      "parameters": {
        "table": "viral_opportunities",
        "schema": "content",
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 2.4
    },
    {
      "id": "6ef0386d-b622-4e27-ab11-0a7bb86185cd",
      "name": "Mark Topic as Suggested",
      "type": "n8n-nodes-base.code",
      "notes": "Updates workflow memory to track suggested topics",
      "position": [
        4608,
        416
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Mark topic as suggested to prevent future duplicates\nconst opportunity = $input.item.json;\nconst staticData = $getWorkflowStaticData('global');\n\nif (!staticData.coveredTopics) {\n  staticData.coveredTopics = {};\n}\n\nconst topicKey = opportunity.trend.topic.toLowerCase().replace(/[^a-z0-9]/g, '');\nstaticData.coveredTopics[topicKey] = {\n  opportunityId: opportunity.opportunityId,\n  topic: opportunity.trend.topic,\n  suggestedAt: opportunity.detectedAt,\n  timestamp: Date.now()\n};\n\nconsole.log(`\u2705 Marked as suggested: ${opportunity.trend.topic}`);\n\nreturn { json: opportunity };"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "f451f6db-e55f-4e6d-a198-28b1677f1784",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        -240
      ],
      "parameters": {
        "width": 720,
        "height": 1264,
        "content": "Automatically discovers trending topics in your niche and generates ready-to-use content ideas with AI.\n\n## \ud83c\udfaf How It Works\n\n### 1. **Multi-Source Trend Monitoring**\n   - Twitter/X trending topics and hashtags\n   - Reddit hot posts from niche subreddits\n   - Google Trends daily search trends\n   - Runs every 2 hours for fresh opportunities\n\n### 2. **Smart Filtering & Scoring**\n   - Filters by your niche keywords\n   - Removes duplicates across sources\n   - Calculates viral potential score (0-100)\n   - Ranks by engagement, recency, and relevance\n   - Prevents suggesting already-covered topics\n\n### 3. **AI Content Generation**\n   - Uses Claude AI to analyze each trend\n   - Generates 5 unique content ideas per trend\n   - Provides hooks, key points, and platform recommendations\n   - Explains why each idea has viral potential\n\n### 4. **Comprehensive Delivery**\n   - Beautiful HTML email digest with all opportunities\n   - Slack summary for quick review\n   - Database logging for tracking\n   - Research links for deeper investigation\n\n\n## \ud83c\udfa8 Customization Options\n\n### Adjust Scan Frequency\nEdit \"Every 2 Hours\" trigger:\n- More frequent: Every 1 hour\n- Less frequent: Every 4-6 hours\n- Consider API rate limits\n\n### Tune Viral Score Algorithm\nEdit \"Calculate Viral Potential Score\" node:\n- Adjust engagement weight (currently 40%)\n- Change recency importance (currently 30%)\n- Modify threshold in \"Filter High Potential Only\" (currently 40)\n\n### Customize Content Ideas\nModify the AI prompt in \"AI - Generate Content Ideas\":\n- Change number of ideas (currently 5)\n- Add specific format requirements\n- Include brand voice guidelines\n- Target specific platforms\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "4a320c45-d7f3-46e1-a647-5bb4ea1627cd",
      "name": "Sticky Note - Collection",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        736,
        176
      ],
      "parameters": {
        "color": 6,
        "width": 640,
        "height": 688,
        "content": "## \ud83d\udce1 TREND COLLECTION\nFetch from multiple sources, parse, and normalize data"
      },
      "typeVersion": 1
    },
    {
      "id": "f809d301-6b66-4e15-b8c9-15c104eb5263",
      "name": "Sticky Note - Analysis",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1440,
        256
      ],
      "parameters": {
        "color": 4,
        "width": 1056,
        "height": 336,
        "content": "## \ud83d\udd0d FILTERING & SCORING\nKeyword filtering, deduplication, viral potential scoring, ranking"
      },
      "typeVersion": 1
    },
    {
      "id": "842ffdfa-ea0a-4d66-bb90-6804892fb698",
      "name": "Sticky Note - AI",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2552,
        240
      ],
      "parameters": {
        "color": 5,
        "width": 1088,
        "height": 368,
        "content": "## \ud83e\udd16 AI CONTENT GENERATION\nCheck history, generate ideas with AI, enrich with research"
      },
      "typeVersion": 1
    },
    {
      "id": "8053a523-abbc-4101-9812-17253970237f",
      "name": "Sticky Note - Delivery",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3680,
        224
      ],
      "parameters": {
        "width": 1328,
        "height": 448,
        "content": "## \ud83d\udce8 REPORTING & DELIVERY\nCreate reports, send digest, notify team, log to database"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "b0ea2038-51da-44a7-8151-adf6dd960eaa",
  "connections": {
    "Parse Reddit Data": {
      "main": [
        [
          {
            "node": "Merge All Trend Sources",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Send Email Digest": {
      "main": [
        [
          {
            "node": "Log to Content Database",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Research Links": {
      "main": [
        [
          {
            "node": "Create Opportunity Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Twitter Data": {
      "main": [
        [
          {
            "node": "Merge All Trend Sources",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Slack Summary": {
      "main": [
        [
          {
            "node": "Log to Content Database",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Google Trends": {
      "main": [
        [
          {
            "node": "Parse Google Trends",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Google Trends": {
      "main": [
        [
          {
            "node": "Merge All Trend Sources",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sort by Viral Score": {
      "main": [
        [
          {
            "node": "Check Already Covered",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Already Covered": {
      "main": [
        [
          {
            "node": "AI - Generate Content Ideas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Twitter/X Trends": {
      "main": [
        [
          {
            "node": "Parse Twitter Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse AI Content Ideas": {
      "main": [
        [
          {
            "node": "Add Research Links",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Reddit Hot Topics": {
      "main": [
        [
          {
            "node": "Parse Reddit Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log to Content Database": {
      "main": [
        [
          {
            "node": "Mark Topic as Suggested",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark Topic as Suggested": {
      "main": [
        [
          {
            "node": "Load Niche Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge All Trend Sources": {
      "main": [
        [
          {
            "node": "Filter by Niche Keywords",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Remove Duplicate Topics": {
      "main": [
        [
          {
            "node": "Calculate Viral Potential Score",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter by Niche Keywords": {
      "main": [
        [
          {
            "node": "Remove Duplicate Topics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Opportunity Report": {
      "main": [
        [
          {
            "node": "Aggregate All Opportunities",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter High Potential Only": {
      "main": [
        [
          {
            "node": "Sort by Viral Score",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI - Generate Content Ideas": {
      "main": [
        [
          {
            "node": "Parse AI Content Ideas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate All Opportunities": {
      "main": [
        [
          {
            "node": "Send Email Digest",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send Slack Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Every 2 Hours - Trend Scanner": {
      "main": [
        [
          {
            "node": "Fetch Twitter/X Trends",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch Reddit Hot Topics",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch Google Trends",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Viral Potential Score": {
      "main": [
        [
          {
            "node": "Filter High Potential 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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Automatically discovers trending topics in your niche and generates ready-to-use content ideas with AI. Twitter/X trending topics and hashtags Reddit hot posts from niche subreddits Google Trends daily search trends Runs every 2 hours for fresh opportunities Filters by your…

Source: https://n8n.io/workflows/13707/ — original creator credit. Request a take-down →

More Social Media workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Social Media

This workflow monitors brand mentions across multiple platforms (Twitter/X, Reddit, News) and automatically detects reputation crises based on sentiment analysis and trend detection. Multi-platform mo

Twitter, Reddit, HTTP Request +3
Social Media

Marketing teams and social media managers in Japan who want to automate content creation while maintaining high quality standards and cultural appropriateness. Perfect for businesses that need consist

HTTP Request, Notion, Email Send
Social Media

This template is ideal for sales teams, recruiters, business development professionals, and relationship managers who need to monitor changes in their network's LinkedIn profiles. Perfect for agencies

Google Sheets, HTTP Request, Slack
Social Media

Social media managers, creators, and brand accounts that rely on retweets for reach but want an automated, hands-off cleanup after campaigns to keep profiles tidy and on-brand.

HTTP Request, Twitter, Slack +1
Social Media

Convert your customer satisfaction into high-converting social media content with this fully automated social proof pipeline. This workflow scans your database for top-tier reviews, generates a brande

Airtable, HTTP Request, Slack +1