n8n workflow: AI-Powered Information Monitoring with OpenAI, Google Sheets, Jina AI and Slack

Nodes:
name: OpenAI Chat Model
type: @n8n/n8n-nodes-langchain.lmChatOpenAi
name: Basic LLM Chain
type: @n8n/n8n-nodes-langchain.chainLlm
parameters: text: ={{ $json.data }}
messages: messageValues: =You are an AI assistant responsible for summarizing articles **in English** and formatting them into Slack-compatible messages.  
Your job is to create a clear and concise summary following the guidelines below and format it in Slack-specific Markdown format.  

---

## 1. Title with Link  

- Format the article title as a **clickable link** using Slack's Markdown syntax:  
  `<URL|*Title of the article*>`.  
- The title should be clear and engaging to encourage readers to click.  

---

## 2. Section Headings  

- Use **bold text** to introduce different sections of the summary by wrapping the text with `*` symbols.  
- Ensure headings are descriptive and guide the reader through the content effectively.  

---

## 3. Key Points  

- Present key insights using **bullet points**, using the `•` symbol for listing important information.  
- Each point should be concise, informative, and directly related to the article's topic.  

---

## 4. Content Summary  

- Provide a brief but comprehensive overview of the article's content.  
- Use plain text and line breaks to separate paragraphs for improved readability.  
- Focus on the most important aspects without unnecessary details.  

---

## 5. Context and Relevance  

- Explain why the article is important and how it relates to the reader's interests.  
- Highlight its relevance to ongoing trends or industry developments.  

---

## Message Structure  

The output should follow this structured format:  

1. **Title with link** – Present the article as a clickable link formatted in Slack Markdown.  
2. **Summary sections** – Organized under clear headings to enhance readability.  
3. **Key insights** – Presented as bullet points for quick scanning.  
4. **Contextual analysis** – A brief explanation of the article's relevance and importance.  

---

## Slack Markdown Formatting Guide  

Ensure the message follows Slack's Markdown syntax for proper display:  

- **Bold text:** Use `*bold text*`.  
- **Italic text:** Use `_italic text_`.  
- **Bullet points:** Use `•` or `-` for lists.  
- **Links:** Format as `<URL|*text*>` to create clickable links.  
- **Line breaks:** Use a blank line to separate paragraphs for readability.  

---

## Example of Slack-formatted Output  

🔔 *New article from n8n Blog*  

<https://blog.n8n.io/self-hosted-ai/|*Introducing the Self-hosted AI Starter Kit: Run AI locally for privacy-first solutions*>  

*Summary of the article*  
n8n has launched the Self-hosted AI Starter Kit, a Docker Compose template designed to simplify the deployment of local AI tools. This initiative addresses the growing need for on-premise AI solutions that enhance data privacy and reduce reliance on external APIs. The starter kit includes tools like Ollama, Qdrant, and PostgreSQL, providing a foundation for building self-hosted AI workflows. While it's tailored for proof-of-concept projects, users can customize it to fit specific requirements.  

*Key Points*  
• The Self-hosted AI Starter Kit facilitates quick setup of local AI environments using Docker Compose.  
• It includes preconfigured AI workflow templates and essential tools such as Ollama, Qdrant, and PostgreSQL.  
• Running AI on-premise offers benefits like improved data privacy and cost savings by minimizing dependence on external API calls.  
• The kit is designed for easy deployment on local machines or personal cloud instances like Digital Ocean and runpod.io.  
• n8n emphasizes the flexibility of their platform, allowing integration with over 400 services, including Google, Slack, Twilio, and JIRA, to streamline AI application development.  

*Context and Relevance*  
This article introduces a practical solution for organizations and developers seeking to implement AI workflows locally. By providing a ready-to-use starter kit, n8n addresses common challenges associated with setting up and maintaining on-premise AI systems, promoting greater control over data and potential cost efficiencies.
 
---

Ensure that the message is formatted according to Slack's requirements to improve readability and engagement.  

promptType: define
name: Schedule Trigger
type: n8n-nodes-base.scheduleTrigger
parameters: rule: interval: field: minutes
minutesInterval: 15
name: RSS Read
type: n8n-nodes-base.rssFeedRead
onError: continueRegularOutput
parameters: url: ={{ $json.rss_feed_url }}
options: ignoreSSL: no
executeOnce: no
name: Relevance Classification for Topic Monitoring
type: @n8n/n8n-nodes-langchain.textClassifier
parameters: options: fallback: discard
inputText: ={{ $json.title }}
{{ $json.contentSnippet }}
categories: categories: category: relevant
description: Articles related to artificial intelligence (AI), data science, machine learning, algorithms, big data, or innovations in these fields.
category: not_relevant
description: Articles not directly related to  artificial intelligence (AI), data science, machine learning, algorithms, big data, or innovations in these fields.
name: Sticky Note
type: n8n-nodes-base.stickyNote
parameters: color: 7
width: 600
height: 960
content: ## LLM Call 1 - Article Topic Relevance Classification  

This **LLM call** is used to **classify** whether the articles published on the website are **relevant** to the **topics and interests** you want to monitor.  
It analyzes the **title** and the **content snippet** retrieved from the **RSS Read** node.  

In this template, the monitored articles are related to **data and AI.**  
The classification is done into **two categories**, which you should modify in the `Description` field under the **Categories** section of the node:

### Relevant  
`Description`: Articles related to **[The topics you want to monitor]**.  

### Not Relevant  
`Description`: Articles that are not directly related to **[The topics you want to monitor]**.

By default, this template monitors topics related to artificial intelligence (AI), data science, machine learning, algorithms, big data, and innovations in these fields.

name: Sticky Note3
type: n8n-nodes-base.stickyNote
parameters: color: 7
width: 600
height: 680
content: ## LLM Call 2 - Summarize and Format in Slack Markdown 

This node **uses OpenAI's GPT-4o-mini model** to **summarize the article content**, which is provided as **Markdown text** from Jina AI, and formats it in **Slack Markdown** to enhance readability within Slack.  

### Customize to fit your needs  

Here are two examples of how you can modify the **System Prompt** of this node to better suit your requirements:  

- **Language customization:**  
  You can modify the **System Prompt** to instruct the LLM to generate the summary in a specific language (e.g., French or Italian).  
  However, consider the option of adding a separate LLM node **dedicated to translation** if the model cannot handle **summarization, formatting, and translation** simultaneously while maintaining high output quality.

- **Changing the summary structure:**  
  You can adjust the prompt to modify how the summary is structured to better match your preferred format and style.

name: Google Sheets - Get RSS Feed url followed
type: n8n-nodes-base.googleSheets
parameters: sheetName: __rl: yes
mode: list
value: gid=0
cachedResultUrl: https://docs.google.com/spreadsheets/d/1F2FzWt9FMkA5V5i9d_hBJRahLDvxs3DQBOLkLYowXbY/edit#gid=0
cachedResultName: rss_feed
documentId: __rl: yes
mode: list
value: 1F2FzWt9FMkA5V5i9d_hBJRahLDvxs3DQBOLkLYowXbY
cachedResultUrl: https://docs.google.com/spreadsheets/d/1F2FzWt9FMkA5V5i9d_hBJRahLDvxs3DQBOLkLYowXbY/edit?usp=drivesdk
cachedResultName: Template - AI-Powered Information Monitoring
authentication: serviceAccount
executeOnce: yes
name: Sticky Note4
type: n8n-nodes-base.stickyNote
parameters: color: 7
width: 460
height: 960
content: ## Google Sheets - Get RSS Feed URLs Followed  
This node **retrieves rows** from the Google Sheet that contains the **RSS feed URLs** you follow.  
It is configured to run only once per execution, meaning that even if the previous node outputs many items, this node will execute only once.  

You can **add more URLs** to your sheet, but keep in mind that following **more RSS feeds** will increase the **cost of LLM API usage** (e.g., OpenAI).  

You can access the **Google Sheet template** to copy and use in this workflow [here](https://docs.google.com/spreadsheets/d/1F2FzWt9FMkA5V5i9d_hBJRahLDvxs3DQBOLkLYowXbY/).  
(*This is the same template used in the previous node.*)

In this node, make sure to select the **"rss_feed"** sheet from your **copied version of the Google Sheet template**.  
This sheet contains the list of RSS feed URLs that the workflow will process.
name: Sticky Note6
type: n8n-nodes-base.stickyNote
parameters: color: 7
width: 460
height: 960
content: ## RSS Read  
This node **reads** the RSS feed.  
The RSS URL is **retrieved** from the data you have entered in **Google Sheets**, so make sure the URL provided is indeed a **valid RSS feed**.  

### What is an RSS feed?  
An **RSS feed** is a **web feed** that allows users to **automatically receive updates** from websites, such as **news sites** or **blogs**, in a **standardized format**.

name: Sticky Note5
type: n8n-nodes-base.stickyNote
parameters: color: 7
width: 960
height: 500
content: ## Jina AI - Read URL

This node **uses the Jina AI API** to **retrieve the content** of articles that were classified as **"relevant"** in the previous step.  
Since this process **involves web scraping**, ensure that it complies with the **scraping regulations** in your country.  

### What is Jina AI?  
**Jina AI** is an API that allows you to **extract webpage content** and convert it into a format that is **ready for LLM processing**, such as **Markdown**.  

You can create an account [here](https://jina.ai/) and receive **1,000,000 free tokens** for testing.  
However, the service can also be used **without an API key** (without an account), though with **reduced RPM (requests per minute)**.  
For this workflow, the default RPM limits should generally be sufficient.

name: Slack1
type: n8n-nodes-base.slack
parameters: text: ={{ $json.text }}
select: channel
channelId: __rl: yes
mode: list
value: C0898R9G7JP
cachedResultName: topic-monitoring
authentication: oAuth2
name: Sticky Note8
type: n8n-nodes-base.stickyNote
parameters: color: 7
width: 460
height: 960
content: ## Google Sheets - Get Article Monitored Database  
This node **retrieves rows** from the Google Sheet that contains articles **already monitored and summarized** by the workflow.  
Depending on the RSS feed you monitor, **URLs may remain in the feed for a long time**, and you don't want to monitor the same URL **twice**.  
You can find the **Google Sheet template** that you can copy and use in this workflow [here](https://docs.google.com/spreadsheets/d/1F2FzWt9FMkA5V5i9d_hBJRahLDvxs3DQBOLkLYowXbY/edit?gid=1966921272#gid=1966921272).

In this node, make sure to select the **"article_database"** sheet from your **copied version of the Google Sheet template**.  
This sheet is used to store and manage the articles processed by the workflow.


---

## Set Field - existing_url  

This node sets the **"existing_url"** field with the value from **"article_url"** in the Google Sheets database.  
During the **first execution** of the workflow, this field will be **empty**, as no articles are present in Google Sheets yet.  
An error may occur in this case; however, the workflow will **continue running** without interruption.

name: Sticky Note9
type: n8n-nodes-base.stickyNote
parameters: color: 7
width: 980
height: 960
content: ## Code Node to Filter Existing URLs

This code node filters URLs that have **not yet been summarized by AI.**  
It outputs:

- A **list of URLs** following the RSS Read schema if new URLs are found.
- An item called **"message"** with the value **"No new articles found"** if no new articles are available in your RSS feed.

---

## IF Node

The condition for this node is: `{{ $json.message }}` *not equal to* **"No new articles found"**.

- **False** → The workflow executes the "No Operation, do nothing" node.
- **True** → The workflow proceeds to process the new articles for your web development industry monitoring.

name: Sticky Note10
type: n8n-nodes-base.stickyNote
parameters: color: 7
width: 960
height: 580
content: ## Set Fields - Not Relevant Articles  

This node prepares the data to be added to the Google Sheet by defining the following fields:  

- **`article_url`** – The article's URL.
- **`summarized`** – Always set to `"NO (not relevant)"`, as it belongs to the **"not_relevant"** path.  
- **`website`** – The website where the article URL was published.  
- **`fetched_at`** – The timestamp when the URL was processed by the workflow.  
  > *(Note: This timestamp reflects when the scenario was triggered, as obtained from the **Schedule Trigger** node, not the exact fetch time.)*  
- **`publish_date`** – The date the article was published.  

---

## Google Sheets - Add Not Relevant Articles

This node adds the prepared data to the **"article_database"** sheet in your copied Google Sheet template.  
Ensure that you select the **"article_database"** sheet when configuring this node.  

name: Sticky Note2
type: n8n-nodes-base.stickyNote
parameters: color: 5
width: 600
height: 440
content: ## OpenAI Chat Model  

This node specifies the **AI model** to be used for processing.  
The default model is **GPT-4o-mini**, which has been **tested** and proven to perform well for this task.  

**GPT-4o-mini** is a **cost-efficient** model, offering a good balance between **performance and affordability**, making it suitable for regular usage without incurring high costs.

name: Sticky Note11
type: n8n-nodes-base.stickyNote
parameters: color: 7
width: 600
height: 680
content: ## Slack - Send Article Summary  

This node **posts the message** to the designated Slack channel, containing the **output generated by the LLM.**  

For better organization and accessibility, it is recommended to use a **dedicated Slack channel** specifically for topic monitoring.  
This ensures that team members can easily access relevant summaries without cluttering other discussions.  


### Why not use Slack Tool Calling?  

After extensive testing, the output from the previous node has proven to be **highly effective**, making it unnecessary to use **tool calling** or an **AI agent.** 😀  
Keeping things simple **streamlines the workflow** and reduces complexity.

name: Sticky Note12
type: n8n-nodes-base.stickyNote
parameters: color: 7
width: 1260
height: 560
content: ## Set Fields - Relevant Articles  

This node prepares the data to be added to the Google Sheet by defining the following fields:  

- **`article_url`** – The article's URL.  
- **`summarized`** – Always set to `"YES"`, as it follows the **"relevant"** path.  
- **`summary`** – The article summary that was posted to Slack.  
- **`website`** – The source website where the article was published.  
- **`fetched_at`** – The timestamp indicating when the URL was processed by the workflow.  
  > *(Note: This timestamp reflects when the data was added to Google Sheets, not the actual fetch time.)*  
- **`publish_date`** – The date the article was published.  

---

## Google Sheets - Add Relevant Articles

This node adds the prepared data to the **"article_database"** sheet in your copied Google Sheet template.  
Make sure to select the **"article_database"** sheet when configuring this node.  

name: Sticky Note1
type: n8n-nodes-base.stickyNote
parameters: color: 7
width: 460
height: 600
content: ## Scheduler 
This **trigger** is a **scheduler** that defines **how often the workflow is executed**.  
By default, the **template is set to every 1 hour**, meaning the workflow will check **every hour** if **new articles** have been added to the **RSS feed** you follow.

name: Sticky Note7
type: n8n-nodes-base.stickyNote
parameters: color: 6
width: 780
height: 1300
content: # Workflow Overview

## Check Legal Regulations:
This workflow involves scraping, so ensure you comply with the legal regulations in your country before getting started. Better safe than sorry!

## 📌 Purpose  
This workflow enables **automated and AI-driven topic monitoring**, delivering **concise article summaries** directly to a **Slack channel** in a structured and easy-to-read format.  
It allows users to stay informed on specific topics of interest effortlessly, without manually checking multiple sources, ensuring a **time-efficient and focused** monitoring experience.  

**To get started, copy the Google Sheets template required for this workflow from [here](https://docs.google.com/spreadsheets/d/1F2FzWt9FMkA5V5i9d_hBJRahLDvxs3DQBOLkLYowXbY).**  


## 🎯 Target Audience  
This workflow is designed for:  
- **Industry professionals** looking to track key developments in their field.  
- **Research teams** who need up-to-date insights on specific topics.  
- **Companies** aiming to keep their teams informed with relevant content.  

## ⚙️ How It Works  
1. **Trigger:** A **Scheduler** initiates the workflow at regular intervals (default: every hour).  
2. **Data Retrieval:**  
   - RSS feeds are fetched using the **RSS Read** node.  
   - Previously monitored articles are checked in **Google Sheets** to avoid duplicates.  
3. **Content Processing:**  
   - The article relevance is assessed using **OpenAI (GPT-4o-mini)**.  
   - Relevant articles are scraped using **Jina AI** to extract content.  
   - Summaries are generated and formatted for Slack.  
4. **Output:**  
   - Summaries are posted to the specified Slack channel.  
   - Article metadata is stored in **Google Sheets** for tracking.  

## 🛠️ Key APIs and Nodes Used  
- **Scheduler Node:** Triggers the workflow periodically.  
- **RSS Read:** Fetches the latest articles from defined RSS feeds.  
- **Google Sheets:** Stores monitored articles and manages feed URLs.  
- **OpenAI API (GPT-4o-mini):** Classifies article relevance and generates summaries.  
- **Jina AI API:** Extracts the full content of relevant articles.  
- **Slack API:** Posts formatted messages to Slack channels.  

---

This workflow provides an **efficient and intelligent way** to stay informed about your topics of interest, directly within Slack.

name: Google Sheets - Get article monitored database
type: n8n-nodes-base.googleSheets
parameters: sheetName: __rl: yes
mode: list
value: 1966921272
cachedResultUrl: https://docs.google.com/spreadsheets/d/1F2FzWt9FMkA5V5i9d_hBJRahLDvxs3DQBOLkLYowXbY/edit#gid=1966921272
cachedResultName: article_database
documentId: __rl: yes
mode: list
value: 1F2FzWt9FMkA5V5i9d_hBJRahLDvxs3DQBOLkLYowXbY
cachedResultUrl: https://docs.google.com/spreadsheets/d/1F2FzWt9FMkA5V5i9d_hBJRahLDvxs3DQBOLkLYowXbY/edit?usp=drivesdk
cachedResultName: Template - AI-Powered Information Monitoring
authentication: serviceAccount
executeOnce: yes
alwaysOutputData: yes
name: Code
type: n8n-nodes-base.code
parameters: jsCode: // Retrieve data from RSS feed and Google Sheets
const rssItems = items; // Contains RSS articles
const sheetItems = $items("Set field - existing_url", 0);

// Extract the links of articles present in Google Sheets
const existingUrls = sheetItems.map(entry => entry.json.existing_url);

// Filter RSS articles to keep only those not present in Google Sheets
const newArticles = rssItems.filter(rssItem => {
    return !existingUrls.includes(rssItem.json.link);
});

// If new articles are found, return them
if (newArticles.length > 0) {
    return newArticles;
}

// If no new articles, return an informational message
return [{ json: { message: "No new articles found." } }];


name: No Operation, do nothing
type: n8n-nodes-base.noOp
name: If
type: n8n-nodes-base.if
parameters: conditions: options: version: 2
caseSensitive: yes
typeValidation: strict
combinator: and
conditions: operator: type: string
operation: notEquals
leftValue: ={{ $json.message }}
rightValue: No new articles found.
name: Jina AI - Read URL
type: n8n-nodes-base.httpRequest
parameters: url: =https://r.jina.ai/{{ $json.link }}
retryOnFail: yes
waitBetweenTries: 5000
name: Set field - existing_url
type: n8n-nodes-base.set
onError: continueRegularOutput
parameters: assignments: assignments: name: existing_url
type: string
value: ={{ $json.article_url.extractUrl() }}
alwaysOutputData: yes
name: OpenAI Chat Model1
type: @n8n/n8n-nodes-langchain.lmChatOpenAi
name: Set fields - Not relevant articles
type: n8n-nodes-base.set
parameters: assignments: assignments: name: article_url
type: string
value: ={{ $json.link }}
name: summarized
type: string
value: NO (not relevant)
name: website
type: string
value: ={{ $('Google Sheets - Get RSS Feed url followed').item.json.website }}
name: fetched_at
type: string
value: ={{$now}}
name: publish_date
type: string
value: ={{ $('Relevance Classification for Topic Monitoring').item.json.pubDate.toDateTime().format('yyyy-MM-dd') }}
name: Google Sheets - Add relevant articles
type: n8n-nodes-base.googleSheets
parameters: columns: schema: type: string
display: yes
required: no
displayName: article_url
defaultMatch: no
canBeUsedToMatch: yes
type: string
display: yes
required: no
displayName: summarized
defaultMatch: no
canBeUsedToMatch: yes
type: string
display: yes
required: no
displayName: summary
defaultMatch: no
canBeUsedToMatch: yes
type: string
display: yes
required: no
displayName: website
defaultMatch: no
canBeUsedToMatch: yes
type: string
display: yes
required: no
displayName: fetched_at
defaultMatch: no
canBeUsedToMatch: yes
type: string
display: yes
required: no
displayName: publish_date
defaultMatch: no
canBeUsedToMatch: yes
mappingMode: autoMapInputData
attemptToConvertTypes: no
convertFieldsToString: no
operation: append
sheetName: __rl: yes
mode: list
value: 1966921272
cachedResultUrl: https://docs.google.com/spreadsheets/d/1F2FzWt9FMkA5V5i9d_hBJRahLDvxs3DQBOLkLYowXbY/edit#gid=1966921272
cachedResultName: article_database
documentId: __rl: yes
mode: list
value: 1F2FzWt9FMkA5V5i9d_hBJRahLDvxs3DQBOLkLYowXbY
cachedResultUrl: https://docs.google.com/spreadsheets/d/1F2FzWt9FMkA5V5i9d_hBJRahLDvxs3DQBOLkLYowXbY/edit?usp=drivesdk
cachedResultName: Template - AI-Powered Information Monitoring
authentication: serviceAccount
name: Google Sheets - Add relevant article
type: n8n-nodes-base.googleSheets
parameters: columns: schema: type: string
display: yes
required: no
displayName: article_url
defaultMatch: no
canBeUsedToMatch: yes
type: string
display: yes
required: no
displayName: summarized
defaultMatch: no
canBeUsedToMatch: yes
type: string
display: yes
required: no
displayName: summary
defaultMatch: no
canBeUsedToMatch: yes
type: string
display: yes
required: no
displayName: website
defaultMatch: no
canBeUsedToMatch: yes
type: string
display: yes
required: no
displayName: fetched_at
defaultMatch: no
canBeUsedToMatch: yes
type: string
display: yes
required: no
displayName: publish_date
defaultMatch: no
canBeUsedToMatch: yes
mappingMode: autoMapInputData
attemptToConvertTypes: no
convertFieldsToString: no
operation: append
sheetName: __rl: yes
mode: list
value: 1966921272
cachedResultUrl: https://docs.google.com/spreadsheets/d/1F2FzWt9FMkA5V5i9d_hBJRahLDvxs3DQBOLkLYowXbY/edit#gid=1966921272
cachedResultName: article_database
documentId: __rl: yes
mode: list
value: 1F2FzWt9FMkA5V5i9d_hBJRahLDvxs3DQBOLkLYowXbY
cachedResultUrl: https://docs.google.com/spreadsheets/d/1F2FzWt9FMkA5V5i9d_hBJRahLDvxs3DQBOLkLYowXbY/edit?usp=drivesdk
cachedResultName: Template - AI-Powered Information Monitoring
authentication: serviceAccount
name: Set Fields - Relevant Articles
type: n8n-nodes-base.set
parameters: assignments: assignments: name: article_url
type: string
value: ={{ $('Relevance Classification for Topic Monitoring').item.json.link }}
name: summarized
type: string
value: YES
name: summary
type: string
value: ={{ $json.text }}
name: website
type: string
value: ={{ $('Google Sheets - Get RSS Feed url followed').item.json.website }}
name: fetched_at
type: string
value: ={{$now}}
name: publish_date
type: string
value: ={{ $('Relevance Classification for Topic Monitoring').item.json.pubDate.toDateTime().format('yyyy-MM-dd') }}

Connections:
If: main: node: Relevance Classification for Topic Monitoring
type: main
node: No Operation, do nothing
type: main
Code: main: node: If
type: main
RSS Read: main: node: Code
type: main
Basic LLM Chain: main: node: Slack1
type: main
node: Set Fields - Relevant Articles
type: main
Schedule Trigger: main: node: Google Sheets - Get article monitored database
type: main
OpenAI Chat Model: ai_languageModel: node: Basic LLM Chain
type: ai_languageModel
Jina AI - Read URL: main: node: Basic LLM Chain
type: main
OpenAI Chat Model1: ai_languageModel: node: Relevance Classification for Topic Monitoring
type: ai_languageModel
Set field - existing_url: main: node: Google Sheets - Get RSS Feed url followed
type: main
Set Fields - Relevant Articles: main: node: Google Sheets - Add relevant article
type: main
Set fields - Not relevant articles: main: node: Google Sheets - Add relevant articles
type: main
Google Sheets - Get RSS Feed url followed: main: node: RSS Read
type: main
Relevance Classification for Topic Monitoring: main: node: Jina AI - Read URL
type: main
node: Set fields - Not relevant articles
type: main
Google Sheets - Get article monitored database: main: node: Set field - existing_url
type: main