{
  "id": "BijNqDaifx2Qa6KX",
  "meta": {
    "templateId": "9384",
    "templateCredsSetupCompleted": true
  },
  "name": "AI News Digest Bot (HN \u2192 GPT \u2192 Telegram)",
  "tags": [
    {
      "id": "0E8zgjFel4Zqxtac",
      "name": "HN",
      "createdAt": "2026-08-06T12:24:18.701Z",
      "updatedAt": "2026-08-06T12:24:18.701Z"
    },
    {
      "id": "BFNwRV7LzKC28opK",
      "name": "news",
      "createdAt": "2026-08-06T12:24:46.924Z",
      "updatedAt": "2026-08-06T12:24:46.924Z"
    },
    {
      "id": "F4HO6Cis9tKT4G2c",
      "name": "Openrouter",
      "createdAt": "2026-08-06T12:24:40.984Z",
      "updatedAt": "2026-08-06T12:24:40.984Z"
    },
    {
      "id": "sEu2x1X1LZKJv823",
      "name": "Telegram",
      "createdAt": "2026-08-06T12:24:03.023Z",
      "updatedAt": "2026-08-06T12:24:03.023Z"
    }
  ],
  "nodes": [
    {
      "id": "2a57c491-15f9-4035-854f-9bc410e9fe5e",
      "name": "Filter Last 24 Hours",
      "type": "n8n-nodes-base.filter",
      "position": [
        1520,
        624
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "f59903f3-835c-407a-a930-060d20c8abdf",
              "operator": {
                "type": "dateTime",
                "operation": "afterOrEquals"
              },
              "leftValue": "={{ $json.created_at }}",
              "rightValue": "={{ $now.minus({days: 1}).toISO() }}"
            }
          ]
        }
      },
      "typeVersion": 2.2,
      "alwaysOutputData": true
    },
    {
      "id": "960d99c5-3bfa-4baa-b9eb-4cc41e6ad961",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        2416,
        608
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "9bf34ea7-64ad-4bc5-b4f7-af3a1d1fa0a0",
      "name": "Scrape Article URL",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        2624,
        624
      ],
      "parameters": {
        "url": "={{ $json.url }}",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "714804a1-ebc4-474a-9de0-4e8785086129",
      "name": "Convert to Markdown",
      "type": "n8n-nodes-base.markdown",
      "onError": "continueRegularOutput",
      "position": [
        3040,
        720
      ],
      "parameters": {
        "html": "={{ $json.data }}",
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "030bc0bb-c0ae-4234-9a9e-720c86ba3f0c",
      "name": "Daily Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        976,
        624
      ],
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "ad52ef72-db1e-43c2-8ec7-4335416b5e82",
      "name": "HTTP Request",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1168,
        624
      ],
      "parameters": {
        "url": "= http://hn.algolia.com/api/v1/search_by_date?query=AI&tags=story&numericFilters=created_at_i%3E{{ Math.floor(($now.minus({days:1})).toSeconds()) }} ",
        "options": {}
      },
      "typeVersion": 4.5
    },
    {
      "id": "729ca0ff-0947-48c7-8f75-221d94d97cb4",
      "name": "Split Out",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1344,
        624
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "hits"
      },
      "typeVersion": 1
    },
    {
      "id": "aa963b1f-0d0d-44d2-bf17-e07eced0bde5",
      "name": "Limit",
      "type": "n8n-nodes-base.limit",
      "position": [
        1712,
        624
      ],
      "parameters": {
        "maxItems": 3
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "a06a6a67-464a-4870-8efd-a383b0340b05",
      "name": "Edit Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        2848,
        672
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "352e7cd4-a293-41c7-b179-cc840ba0aff2",
              "name": "title",
              "type": "string",
              "value": "={{ $('Loop Over Items').item.json.title }} "
            },
            {
              "id": "1b4bacd2-13f6-4dcb-9a08-54e84b4c2273",
              "name": "url",
              "type": "string",
              "value": "={{ $('Loop Over Items').item.json.url }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.5
    },
    {
      "id": "fcd54a80-903d-458e-98a7-f2b89f6c6b6e",
      "name": "Basic LLM Chain",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        2816,
        256
      ],
      "parameters": {
        "text": "={{ JSON.stringify($json.articles) }}",
        "batching": {},
        "messages": {
          "messageValues": [
            {
              "message": "You will receive a JSON array of articles, each with id, title, url, and text. For EACH article, write a heading and a 2-sentence summary in Russian. Return ONLY a valid JSON array, no markdown fences, no extra text: [{\"id\": 0, \"heading\": \"...\", \"summary\": \"...\"}, ...]"
            }
          ]
        },
        "promptType": "define",
        "needsFallback": true,
        "hasOutputParser": true
      },
      "typeVersion": 1.9
    },
    {
      "id": "cf5bfde3-44b0-4c17-b1d2-0d95503d608f",
      "name": "Collect Articles",
      "type": "n8n-nodes-base.code",
      "position": [
        2544,
        256
      ],
      "parameters": {
        "jsCode": "const articles = items\n  .filter(item => item.json.data)\n  .map((item, i) => ({\n    id: i,\n    title: item.json.title,\n    url: item.json.url,\n    text: item.json.data.slice(0, 1500)\n  }));\nreturn [{ json: { articles } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "35db5025-fb1a-46f6-86cf-0335b658ffee",
      "name": "Format for Telegram",
      "type": "n8n-nodes-base.code",
      "position": [
        3168,
        256
      ],
      "parameters": {
        "jsCode": "const summaries = $json.output;\nconst articles = $('Collect Articles').item.json.articles;\n\nconst text = summaries.map(s => {\n  const article = articles.find(a => a.id === s.id);\n  return `*${s.heading}*\\n${s.summary}\\n${article ? article.url : ''}`;\n}).join('\\n\\n');\n\nreturn [{ json: { text } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "1d21e0f1-bbce-46d6-96e2-4a9015b7e8ce",
      "name": "OpenRouter GPT5",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        2656,
        464
      ],
      "parameters": {
        "model": "openai/gpt-5",
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "692237d0-3837-4e2e-aacd-2b94f2f57d23",
      "name": "OpenRouter GPT4",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        2864,
        464
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "9ecaa4cf-1b7a-484d-8c8b-98114c754146",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        3088,
        464
      ],
      "parameters": {
        "jsonSchemaExample": "[\n  {\n    \"id\": 0,\n    \"heading\": \"Example heading\",\n    \"summary\": \"Example two-sentence summary of the article.\"\n  }\n]"
      },
      "typeVersion": 1.3
    },
    {
      "id": "52e811ca-9d4e-4531-a219-c7e2067a8aaa",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1024,
        800
      ],
      "parameters": {
        "color": "#2BB607",
        "width": 384,
        "height": 384,
        "content": "SEARCH\n\nDaily Schedule Trigger: runs once a day on a schedule.\n\nHTTP Request: queries the Hacker News Algolia API\n(search_by_date endpoint \u2014 sorted by publish date,\nnot relevance, so we get the freshest posts).\n\nSplit Out: splits the hits array from the API response\ninto individual items to work with downstream."
      },
      "typeVersion": 1
    },
    {
      "id": "f98dfe0e-f592-4111-aba5-86c60dc0d97e",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1456,
        400
      ],
      "parameters": {
        "content": "FILTERING\n\nFilter Last 24 Hours: keeps only posts whose created_at\nis no earlier than 24 hours ago (date comparison).\n\nLimit: caps the list at 3 articles max \u2014 keeps the digest\nmanageable and avoids wasting GPT tokens on articles\nthat wouldn't make it into the final message anyway."
      },
      "typeVersion": 1
    },
    {
      "id": "9e85909b-e2b9-4a87-b97b-2142b92b62ef",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2512,
        928
      ],
      "parameters": {
        "color": "#560F9D",
        "width": 480,
        "height": 544,
        "content": "LOOP: SCRAPING AND TEXT PREP\n\nLoop Over Items: processes articles one at a time\n(protects against rate limits on source sites).\n\nScrape Article URL: HTTP request to the link from the\nHN post, fetches the source page's HTML. On Error \u2192\nContinue (using error output): if a site blocks scraping\n(403, captcha, etc.), that article is simply skipped\nand the loop doesn't break.\n\nEdit Fields: re-attaches title and url as explicit fields\nright after scraping \u2014 otherwise the HTTP Request node\noverwrites the item's original data with the site's response.\n\nConvert to Markdown: strips the HTML and converts it to\nmarkdown, ready to feed into GPT.\n\nBoth outputs (Success and the Error path) loop back into\nthe input of Loop Over Items \u2014 the loop continues to the\nnext article either way."
      },
      "typeVersion": 1
    },
    {
      "id": "97ba31f1-0eda-485f-81c8-6f78bef31554",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2640,
        -272
      ],
      "parameters": {
        "color": "#A42694",
        "width": 528,
        "height": 480,
        "content": "FORMAT CONVERSION: MARKDOWN \u2192 GPT SUMMARY \u2192 TELEGRAM\n\nCollect Articles: gathers all articles (title, url, text)\ninto a single array once the loop finishes (the 'done' output).\n\nBasic LLM Chain: ONE request to the model for the whole\nbatch of articles at once (instead of one call per article \u2014\nsaves tokens and time). Model: OpenRouter GPT5 (primary),\nOpenRouter GPT4 (fallback if the primary is unavailable).\n\nStructured Output Parser: guarantees the model's response\nis a valid JSON array of {id, heading, summary} per article,\nno manual cleanup of markdown fences needed.\n\nFormat for Telegram: matches GPT's summaries back to the\noriginal urls by id, and assembles the final text in\nTelegram Markdown formatting (*bold heading*, summary,\nlink), ready to send."
      },
      "typeVersion": 1
    },
    {
      "id": "cd06cb2e-ad71-4396-9105-1f181047c38b",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3296,
        448
      ],
      "parameters": {
        "color": "#2BB607",
        "width": 272,
        "height": 224,
        "content": "DELIVERY\n\nSend news: sends the finished text to Telegram\n(parse_mode: Markdown). The \"sent automatically with n8n\"\nattribution is disabled in Additional Fields."
      },
      "typeVersion": 1
    },
    {
      "id": "c49a7943-75c6-494c-8806-5bd7056ef937",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        192,
        128
      ],
      "parameters": {
        "color": 3,
        "width": 640,
        "height": 704,
        "content": "What this workflow does\n\nThis workflow automatically curates a daily digest of AI-related news from Hacker News, summarizes each article with GPT, and delivers it straight to a Telegram chat \u2014 no manual reading or copy-pasting required. Every day it searches Hacker News for AI-tagged stories, filters out anything older than 24 hours, keeps only the top 3, scrapes the linked articles, converts them to clean text, sends the whole batch to GPT in a single request for concise summaries, and posts the result as a formatted message in Telegram with clickable links back to each source.\n\n\nHow to set it up\n\nAdd your Hacker News search query and tags in the HTTP Request node's URL (currently set to search_by_date with tags=story); \n\nconnect your OpenRouter (or other LLM provider) credentials to the Chat Model nodes feeding Basic LLM Chain, and optionally set a fallback model in case the primary is unavailable; \n\nadjust the Limit node if you want more or fewer than 3 articles per digest;\n\nadd your Telegram Bot credentials and chat ID to the Send a text message node\n\nfinally, set your preferred run time in the Daily Schedule Trigger node and activate the workflow."
      },
      "typeVersion": 1
    },
    {
      "id": "c856940e-82ca-47c9-af55-2457400bf670",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        2080,
        624
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "b1e40df9-84cf-44ba-9608-5f8415c965a6",
              "operator": {
                "type": "boolean",
                "operation": "notExists",
                "singleValue": true
              },
              "leftValue": "={{ $json.empty }}",
              "rightValue": {}
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "e226538f-9e4c-4f55-904d-ece731d5afca",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1712,
        800
      ],
      "parameters": {
        "width": 400,
        "height": 512,
        "content": "EMPTY CHECK\n\nCode in JavaScript: filters out any placeholder items \n(injected by \"Always Output Data\" on Filter/Limit when \n0 real articles pass through) and checks if any real \narticles remain. If none, returns a single item with \nan \"empty\" flag instead of the article list.\n\nIf: routes based on that flag.\n \u2192 false (real articles exist): continues into the full \n   pipeline \u2014 Loop Over Items, scraping, GPT summary, \n   Telegram digest.\n \u2192 true (no articles found): skips scraping and GPT \n   entirely, sends a short \"no news today\" message \n   straight to Telegram \u2014 saves time and API costs."
      },
      "typeVersion": 1
    },
    {
      "id": "097fea49-6792-488a-b55c-386e49280a3a",
      "name": "Guard Empty",
      "type": "n8n-nodes-base.code",
      "position": [
        1888,
        624
      ],
      "parameters": {
        "jsCode": "const realItems = items.filter(item => item.json && item.json.title); if (realItems.length === 0) { return [{ json: { empty: true } }]; } return realItems;"
      },
      "typeVersion": 2
    },
    {
      "id": "80764c25-742f-48b8-909a-7dccb710e741",
      "name": "Send news",
      "type": "n8n-nodes-base.telegram",
      "onError": "continueRegularOutput",
      "position": [
        3376,
        256
      ],
      "parameters": {
        "text": "={{ $json.text }}",
        "chatId": "YOUR_TELEGRAM_CHAT_ID",
        "additionalFields": {
          "parse_mode": "Markdown",
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": false,
      "typeVersion": 1.2
    },
    {
      "id": "ff191f37-aa3f-43dc-8076-7820d8893190",
      "name": "Notify No News",
      "type": "n8n-nodes-base.telegram",
      "position": [
        2192,
        1008
      ],
      "parameters": {
        "text": "\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u0441\u0432\u0435\u0436\u0438\u0445 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439 \u043f\u043e \u0418\u0418 \u043d\u0430 Hacker News \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e. \ud83e\udd37",
        "chatId": "YOUR_TELEGRAM_CHAT_ID",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    }
  ],
  "active": true,
  "settings": {
    "binaryMode": "separate",
    "callerPolicy": "workflowsFromSameOwner",
    "timeSavedMode": "fixed",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "e2728e86-b1cf-4f06-8c1b-33db14e34fa4",
  "nodeGroups": [],
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Notify No News",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Limit": {
      "main": [
        [
          {
            "node": "Guard Empty",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out": {
      "main": [
        [
          {
            "node": "Filter Last 24 Hours",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields": {
      "main": [
        [
          {
            "node": "Convert to Markdown",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Guard Empty": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request": {
      "main": [
        [
          {
            "node": "Split Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Basic LLM Chain": {
      "main": [
        [
          {
            "node": "Format for Telegram",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [
          {
            "node": "Collect Articles",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Scrape Article URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter GPT4": {
      "ai_languageModel": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "ai_languageModel",
            "index": 1
          }
        ]
      ]
    },
    "OpenRouter GPT5": {
      "ai_languageModel": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Collect Articles": {
      "main": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Article URL": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert to Markdown": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format for Telegram": {
      "main": [
        [
          {
            "node": "Send news",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Last 24 Hours": {
      "main": [
        [
          {
            "node": "Limit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daily Schedule Trigger": {
      "main": [
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    }
  }
}