{
  "nodes": [
    {
      "id": "05bbe7a5-800b-4ae7-b698-1369614ddd0d",
      "name": "Weekly Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "notes": "Triggers every Monday at 09:00 JST",
      "position": [
        -272,
        320
      ],
      "noteColor": "#aaffaa",
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 9
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 1.2
    },
    {
      "id": "b727b9d8-f2d5-4f24-97dc-fba8133079c0",
      "name": "Function: Create Slack Message",
      "type": "n8n-nodes-base.code",
      "notes": "Format the analysis results into a Slack message.",
      "position": [
        1648,
        320
      ],
      "noteColor": "#aaaaff",
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Create the message payload for Slack\n\nconst item = $input.item.json;\nconst keywords = item.keywordsArray.join(', ');\nconst url = item.url || item.link || 'No URL found';\n\nconst message = `\n:bulb: *[New Content Idea]*\n\n*Theme:* ${item.llmTheme || 'Uncategorized'}\n*Keywords:* ${keywords}\n*Source:* ${url}\n\n_${item.summary || item.text || 'No summary available'}_ \n`;\n\nreturn { \"json\": { \"message\": message } };"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "0f9bea5d-e3a8-4b44-ae13-799bc1b05af2",
      "name": "Workflow Configuration",
      "type": "n8n-nodes-base.set",
      "notes": "REQUIRED: Set your Apify API Token and OpenRouter API Key here.",
      "position": [
        -48,
        320
      ],
      "noteColor": "#aaaaff",
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "apifyToken",
              "type": "string",
              "value": "YOUR_API_TOKEN"
            },
            {
              "id": "id-2",
              "name": "openRouterApiKey",
              "type": "string",
              "value": "YOUR_API_KEY"
            }
          ]
        },
        "includeOtherFields": true
      },
      "notesInFlow": true,
      "typeVersion": 3.4
    },
    {
      "id": "6337c790-9809-4480-9277-dae578cc67b7",
      "name": "Merge Data",
      "type": "n8n-nodes-base.merge",
      "notes": "Merges results from Google and Facebook.",
      "position": [
        624,
        320
      ],
      "noteColor": "#ff77ff",
      "parameters": {},
      "notesInFlow": true,
      "typeVersion": 3.2
    },
    {
      "id": "d05be230-4199-4b0b-b071-61d2a97981c2",
      "name": "Function: Parse LLM Response",
      "type": "n8n-nodes-base.code",
      "notes": "Parses the JSON response from the LLM.",
      "position": [
        1424,
        320
      ],
      "noteColor": "#ff77ff",
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Parse LLM response and extract theme and keywords\n\n// Assuming the AI Agent node outputs a JSON object\nconst parsedResponse = $input.item.json.output || $input.item.json; \n\nlet llmTheme = 'Uncategorized';\nlet keywordsArray = [];\n\ntry {\n  // Attempt to parse if the output is a string\n  const content = (typeof parsedResponse === 'string') ? JSON.parse(parsedResponse) : parsedResponse;\n  llmTheme = content.theme || content.llmTheme || 'Uncategorized';\n  keywordsArray = content.keywords || content.keywordsArray || [];\n  \n  if (!Array.isArray(keywordsArray)) {\n    keywordsArray = [keywordsArray];\n  }\n} catch (error) {\n  console.log('Error parsing LLM response:', error);\n}\n\n// Merge with original item data\nconst enhancedItem = {\n  ...$input.item.json, \n  llmTheme: llmTheme,\n  keywordsArray: keywordsArray\n};\n\nreturn enhancedItem;"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "b6618e44-58ac-4dd8-bf63-447e840b139c",
      "name": "Apify Facebook Scraper",
      "type": "@apify/n8n-nodes-apify.apify",
      "position": [
        176,
        416
      ],
      "parameters": {
        "actorId": {
          "__rl": true,
          "mode": "list",
          "value": "KoJrdxJCTtpon81KY",
          "cachedResultUrl": "https://console.apify.com/actors/KoJrdxJCTtpon81KY/input",
          "cachedResultName": "Facebook Posts Scraper (apify/facebook-posts-scraper)"
        },
        "timeout": {},
        "operation": "Run actor and get dataset",
        "customBody": "{\n  \"startUrls\": [\n    { \"url\": \"https://www.facebook.com/AIShift.Inc/\" }\n  ],\n  \"resultsLimit\": 50,\n  \"minimumLikes\": 50\n}",
        "authentication": "apifyOAuth2Api"
      },
      "typeVersion": 1
    },
    {
      "id": "c5b4a93d-ad0b-487f-a15d-cb9ab8eb3218",
      "name": "Apify Google News Scraper",
      "type": "@apify/n8n-nodes-apify.apify",
      "position": [
        176,
        224
      ],
      "parameters": {
        "actorId": {
          "__rl": true,
          "mode": "list",
          "value": "nFJndFXA5zjCTuudP",
          "cachedResultUrl": "https://console.apify.com/actors/nFJndFXA5zjCTuudP/input",
          "cachedResultName": "Google Search Results Scraper (apify/google-search-scraper)"
        },
        "timeout": {},
        "operation": "Run actor and get dataset",
        "customBody": "{\n  \"queries\": \"Top News AI\",\n  \"maxResultsPerQuery\": 50,\n  \"gl\": \"us\",\n  \"tbm\": \"nws\"\n}",
        "authentication": "apifyOAuth2Api"
      },
      "typeVersion": 1
    },
    {
      "id": "f073f978-4a09-44e9-b006-99d34eeb6039",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1072,
        320
      ],
      "parameters": {
        "text": "=You are a professional content planner. Based on the provided article information, please perform the following tasks:\n\n1. Select the most appropriate category from the Theme List below.\n2. Extract up to 3 keywords that attract readers' interest, suitable for a blog post title.\n3. The output must strictly follow the JSON format below.\n\nTheme List: [Market Trends/Stats, Tech/Product, Legal/Regulation, Strategy, Marketing/PR, Society/Culture]\n\n---\nAnalyze the following article info:\nTitle: {{ $json.title || $json.text }}\nSummary: {{ $json.summary || $json.text }}\nAuthor: {{ $json.author || 'Unknown'}}\nURL: {{ $json.url || $json.link }}\n\nJSON Output Example: {\"theme\": \"Tech/Product\", \"keywords\": [\"AI Use Cases\", \"Efficiency\", \"LLM Trends\"]}",
        "options": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3
    },
    {
      "id": "1d2336ee-7d6d-48b5-bbbf-2385ecc69449",
      "name": "OpenRouter Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        1152,
        544
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "76e6788c-2266-48ee-b82d-2e2e668bb296",
      "name": "Function: Limit to 5 Items",
      "type": "n8n-nodes-base.code",
      "notes": "Limits the dataset to 5 items to save AI tokens.",
      "position": [
        848,
        320
      ],
      "noteColor": "#ffaaaa",
      "parameters": {
        "jsCode": "// Limit the total input items from the Merge Data node to 5\n\nconst allItems = $input.all();\n\n// Return only the first 5 items to reduce LLM costs\nreturn allItems.slice(0, 5);"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "8e673121-0397-45e4-bae7-17ccc1e78806",
      "name": "Function: Extract Google Data",
      "type": "n8n-nodes-base.code",
      "position": [
        400,
        224
      ],
      "parameters": {
        "jsCode": "// Extract array of articles from the Apify node output\n\nconst json = $input.item.json;\nlet extractedItems = [];\n\n// Logic adapted for Apify Google News Scraper output structure\nif (json.organicResults && Array.isArray(json.organicResults)) {\n  extractedItems = json.organicResults;\n} else if (Array.isArray(json)) {\n  extractedItems = json;\n} else if (json.data && json.data.defaultDataset && Array.isArray(json.data.defaultDataset.items)) {\n  extractedItems = json.data.defaultDataset.items;\n} else if (Array.isArray(json.results) || Array.isArray(json.output)) {\n  extractedItems = json.results || json.output;\n} else if (Array.isArray(json.items)) {\n  extractedItems = json.items;\n} else if (Array.isArray(json.body)) {\n  extractedItems = json.body;\n}\n\n// Pass the extracted array of articles to the next node\nreturn extractedItems;"
      },
      "typeVersion": 2
    },
    {
      "id": "ddb1d4da-a2dc-4b9c-9419-631704a97848",
      "name": "Function: Extract Facebook Data",
      "type": "n8n-nodes-base.code",
      "position": [
        400,
        416
      ],
      "parameters": {
        "jsCode": "// Extract array of articles from the Apify node output\n\nconst json = $input.item.json;\nlet extractedItems = [];\n\n// General logic to extract dataset items from Apify output\nif (Array.isArray(json)) {\n  extractedItems = json;\n} \n// 2. Apify standard dataset path (data.defaultDataset.items)\nelse if (json.data && json.data.defaultDataset && Array.isArray(json.data.defaultDataset.items)) {\n  extractedItems = json.data.defaultDataset.items;\n} \n// 3. Shallow paths (results, output, items, body)\nelse if (Array.isArray(json.results) || Array.isArray(json.output)) {\n  extractedItems = json.results || json.output;\n} else if (Array.isArray(json.items)) {\n  extractedItems = json.items;\n} else if (Array.isArray(json.body)) {\n  extractedItems = json.body;\n}\n\n// Pass the extracted array of articles to the next node\nreturn extractedItems;"
      },
      "typeVersion": 2
    },
    {
      "id": "836ca5e7-2edf-436c-bacf-1010bc59a919",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -688,
        192
      ],
      "parameters": {
        "width": 352,
        "height": 558,
        "content": "![Banner Image](https://example.com/replace-with-your-image.png)\n\n## Description \nThis workflow automates the process of finding new content ideas by scraping trending news and social media posts, analyzing them with AI, and delivering a summarized report to Slack.\nIt is perfect for content marketers, social media managers, and strategists who spend hours researching trending topics manually.\n\n## Requirements\n* **n8n Self-hosted**: This workflow uses the `@apify/n8n-nodes-apify` node which requires installation on a self-hosted n8n instance.\n* **Apify Account**: You need an API token and access to the Google Search Results Scraper and Facebook Posts Scraper actors.\n* **OpenRouter API Key**: Used to power the AI analysis (can be swapped for OpenAI/Anthropic if preferred).\n* **Slack Account**: To receive the notifications."
      },
      "typeVersion": 1
    },
    {
      "id": "85427af8-623b-46d7-9e70-f0427c18c8d6",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -208,
        -16
      ],
      "parameters": {
        "color": 7,
        "width": 2128,
        "height": 704,
        "content": "## How to set up\n**Configure Credentials:**\nOpen the **Workflow Configuration** node and paste your Apify API Token and OpenRouter API Key.\nConnect your Slack account in the **Slack Post Content Ideas** node.\n\n**Adjust Apify Settings:**\nIn the **Apify Google News Scraper** node, change the search query (currently set to \"Top News AI\") to your desired topic.\nIn the **Apify Facebook Scraper** node, update the `startUrls` to the Facebook pages you want to monitor.\n\n**Customize AI Prompt:**\n(Optional) Open the **AI Agent** node to adjust the language or the specific themes you want the AI to classify."
      },
      "typeVersion": 1
    },
    {
      "id": "9237b661-be7d-48ac-bbf9-a07888fa47ef",
      "name": "Slack Post Content Ideas",
      "type": "n8n-nodes-base.slack",
      "position": [
        1872,
        320
      ],
      "parameters": {
        "text": "={{ $json.message }}",
        "user": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": ""
        },
        "select": "user",
        "otherOptions": {
          "mrkdwn": true,
          "includeLinkToWorkflow": false
        },
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    }
  ],
  "connections": {
    "AI Agent": {
      "main": [
        [
          {
            "node": "Function: Parse LLM Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Data": {
      "main": [
        [
          {
            "node": "Function: Limit to 5 Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Apify Facebook Scraper": {
      "main": [
        [
          {
            "node": "Function: Extract Facebook Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Workflow Configuration": {
      "main": [
        [
          {
            "node": "Apify Facebook Scraper",
            "type": "main",
            "index": 0
          },
          {
            "node": "Apify Google News Scraper",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Weekly Schedule Trigger": {
      "main": [
        [
          {
            "node": "Workflow Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Apify Google News Scraper": {
      "main": [
        [
          {
            "node": "Function: Extract Google Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function: Limit to 5 Items": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function: Parse LLM Response": {
      "main": [
        [
          {
            "node": "Function: Create Slack Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function: Extract Google Data": {
      "main": [
        [
          {
            "node": "Merge Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function: Create Slack Message": {
      "main": [
        [
          {
            "node": "Slack Post Content Ideas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function: Extract Facebook Data": {
      "main": [
        [
          {
            "node": "Merge Data",
            "type": "main",
            "index": 1
          }
        ]
      ]
    }
  }
}