guides/workflow: miniflux news
Threat Intel · n8n · Miniflux → Mistral

News screening
from Miniflux

An n8n workflow that periodically fetches unread articles from Miniflux, lets a Mistral model decide relevance, enriches the relevant ones into short threat-intel summaries, and marks everything as read. A reference pattern with importable JSON — adapt to your own feeds and nodes.

n8n Reference template Miniflux API + Mistral
7nodes
2-stepscreen → enrich
RESTMiniflux API

What it does

Miniflux gathers your curated security feeds, but raw feeds are noisy. This workflow puts an intelligent filter on top: a cheap model screens for relevance, and only what passes goes on to more expensive enrichment. The result is a low-noise flow of relevant, summarized security news.

Prerequisites: Miniflux running with an API token, and n8n with Mistral credentials. This is a reference pattern — node types and parameters can differ from your n8n version, so verify against your editor.

Flow overview

Two-step screening: a cheap model filters out, an expensive model enriches only what is relevant.

triggerSchedule
(1t)
httpGet Unread
splitSplit Entries
mistral SScreen
ifRelevant?
mistral LEnrich
httpMark Read
Branching at "Relevant?": true → enrich with Mistral Large → mark read. false → mark read directly (skipped). Both branches end by closing the article so it isn't screened again.

Node-by-node

#NodeTypeFunction
1Schedule TriggerscheduleTriggerRuns every hour (adjust the interval to feed volume)
2Get UnreadhttpRequestGET /v1/entries?status=unread with an X-Auth-Token header
3Split EntriessplitOutSplits the entries array into one item per article
4ScreenmistralAi (Small)Cheap relevance assessment, replies with structured JSON
5Relevant?ifParses the screening JSON and branches on relevant
6EnrichmistralAi (Large)Summarizes relevant articles into an intel summary + IOCs
7Mark ReadhttpRequestPUT /v1/entries sets status read
Tune the screening prompt: Node 4's system prompt determines the quality. Be specific about what "relevant" means to you (e.g. only actively exploited vulnerabilities, only certain sectors) — the sharper the prompt, the less noise gets through to the expensive Enrich node.

Importable JSON

n8n import

Copy the below and paste into n8n via Workflows → ⋯ → Import from clipboard. Replace the credential references and prompts with your own.

news_workflow.json
{
  "name": "Miniflux News Screening",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 1
            }
          ]
        }
      },
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        240,
        300
      ]
    },
    {
      "parameters": {
        "url": "=https://rss.defencia.dk/v1/entries?status=unread&limit=100&direction=asc",
        "options": {
          "response": {
            "response": {
              "fullResponse": false
            }
          }
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Auth-Token",
              "value": "={{ $credentials.minifluxToken }}"
            }
          ]
        }
      },
      "name": "Get Unread (Miniflux)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        460,
        300
      ]
    },
    {
      "parameters": {
        "fieldToSplitOut": "entries",
        "options": {}
      },
      "name": "Split Entries",
      "type": "n8n-nodes-base.splitOut",
      "typeVersion": 1,
      "position": [
        680,
        300
      ]
    },
    {
      "parameters": {
        "modelId": "mistral-small-latest",
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You are a security analyst. Assess whether the article is relevant for threat monitoring. Reply ONLY with JSON: {\"relevant\": true/false, \"category\": \"...\", \"reasoning\": \"...\"}"
            },
            {
              "role": "user",
              "content": "=Title: {{ $json.title }}\nContent: {{ $json.content }}"
            }
          ]
        }
      },
      "name": "Screen (Mistral Small)",
      "type": "n8n-nodes-base.mistralAi",
      "typeVersion": 1,
      "position": [
        900,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true
          },
          "conditions": [
            {
              "leftValue": "={{ JSON.parse($json.choices[0].message.content).relevant }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ]
        }
      },
      "name": "Relevant?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1120,
        300
      ]
    },
    {
      "parameters": {
        "modelId": "mistral-large-latest",
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "Summarize the article into a short threat-intel summary with IOCs if present."
            },
            {
              "role": "user",
              "content": "={{ $json.title }}\n{{ $json.content }}"
            }
          ]
        }
      },
      "name": "Enrich (Mistral Large)",
      "type": "n8n-nodes-base.mistralAi",
      "typeVersion": 1,
      "position": [
        1340,
        220
      ]
    },
    {
      "parameters": {
        "method": "PUT",
        "url": "=https://rss.defencia.dk/v1/entries",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-Auth-Token",
              "value": "={{ $credentials.minifluxToken }}"
            }
          ]
        },
        "sendBody": true,
        "jsonBody": "={ \"entry_ids\": [ {{ $json.id }} ], \"status\": \"read\" }"
      },
      "name": "Mark Read (Miniflux)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1560,
        300
      ]
    }
  ],
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Get Unread (Miniflux)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Unread (Miniflux)": {
      "main": [
        [
          {
            "node": "Split Entries",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Entries": {
      "main": [
        [
          {
            "node": "Screen (Mistral Small)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Screen (Mistral Small)": {
      "main": [
        [
          {
            "node": "Relevant?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Relevant?": {
      "main": [
        [
          {
            "node": "Enrich (Mistral Large)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Mark Read (Miniflux)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Enrich (Mistral Large)": {
      "main": [
        [
          {
            "node": "Mark Read (Miniflux)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}
After import — always check: credential bindings (Mistral + an optional generic header auth for the Miniflux token), that node type versions match your n8n, and that the API URLs point to rss.defencia.dk. The embedded token reference is a placeholder — bind it to a real n8n credential, never put it in cleartext.

Credentials

CredentialSetup
Miniflux tokenGenerate in Miniflux (Settings → API Keys). Store as an n8n header-auth credential or env variable — not inline in the node
Mistral APIn8n's Mistral credential with your API key; used by both the Screen and Enrich nodes

Tuning & extensions

AdjustmentEffect
IntervalLower = fresher news, but more API calls. 1h is a good balance for ~71 feeds
limitRaise if feeds pile up between runs; watch out for Mistral rate limits
BatchingScreen multiple articles in one Mistral call to save tokens (requires an array prompt)
OutputAdd a node after Enrich: send to the dashboard, Slack, email or a database table
IOC extractionAdd a regex/Code node that extracts IPs, domains, hashes from the summary
DedupMiniflux's read status is your dedup — that's why everything is marked read in both branches
Link to the CVE flow: This handles news/articles. Vulnerabilities follow a separate pattern via OpenCVE webhooks — see the CVE enrichment workflow.