This workflow corresponds to n8n.io template #15670 — we link there as the canonical source.
This workflow follows the Agent → Gmail 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 →
{
"id": "GJFkNrN20sj0s5Y4",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "AI Portfolio Analysis & Reporting",
"tags": [],
"nodes": [
{
"id": "d68fe1dd-3f16-4a04-8a47-84558b3b14c3",
"name": "Fetch Portfolio (Google Sheets)",
"type": "n8n-nodes-base.googleSheets",
"position": [
-16,
-800
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": 2038550601,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1b5Th5axHDdj0L1xX8QUDmNeeV7jdapWGPeXxJcoXOPk/edit#gid=2038550601",
"cachedResultName": "Portfolio"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1b5Th5axHDdj0L1xX8QUDmNeeV7jdapWGPeXxJcoXOPk",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1b5Th5axHDdj0L1xX8QUDmNeeV7jdapWGPeXxJcoXOPk/edit?usp=drivesdk",
"cachedResultName": "sample_portfolio"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "646c2c19-0343-4490-9809-357ed80ad65c",
"name": "Iterate Stocks",
"type": "n8n-nodes-base.splitInBatches",
"position": [
432,
-624
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "22ef2a13-f3d5-4106-a325-19075347d535",
"name": "Fetch Stock News (RSS)",
"type": "n8n-nodes-base.rssFeedRead",
"position": [
688,
-608
],
"parameters": {
"url": "=https://news.google.com/rss/search?q={{ $json.symbol }}%20stock",
"options": {}
},
"typeVersion": 1.2
},
{
"id": "494a20d1-90b7-49e3-9a49-e7645079dd40",
"name": "Sort News by Date",
"type": "n8n-nodes-base.sort",
"position": [
912,
-608
],
"parameters": {
"options": {},
"sortFieldsUi": {
"sortField": [
{
"order": "descending",
"fieldName": "isoDate"
}
]
}
},
"typeVersion": 1
},
{
"id": "202b2f85-2916-47fc-b5f6-4e386e28532f",
"name": "Limit News (Top 5)",
"type": "n8n-nodes-base.limit",
"position": [
1168,
-608
],
"parameters": {
"maxItems": 5
},
"typeVersion": 1
},
{
"id": "7d51d54c-6886-47db-945d-820e232846be",
"name": "Merge Stock Data + News",
"type": "n8n-nodes-base.code",
"position": [
1424,
-608
],
"parameters": {
"jsCode": "const symbol = $('Iterate Stocks').first().json.symbol;\nconst quantity = $('Iterate Stocks').first().json.quantity;\nconst avg_price = $('Iterate Stocks').first().json.avg_price;\nconst current_price = $('Iterate Stocks').first().json.current_price;\nconst invested = $('Iterate Stocks').first().json.invested;\nconst value = $('Iterate Stocks').first().json.value;\nconst pnl = $('Iterate Stocks').first().json.pnl;\nconst return_pct = $('Iterate Stocks').first().json.return_pct;\n\nconst portfolio = {\n quantity,\n avg_price,\n current_price,\n invested,\n value,\n pnl,\n return_pct\n}\n\nlet news = [];\n\nitems.forEach(element=>{\n news.push(\n {\n title: element.json.title,\n link: element.json.link\n }\n );\n});\n\nreturn [{\n json: {\n symbol,\n portfolio,\n news\n }\n}];"
},
"typeVersion": 2
},
{
"id": "ed8ff42b-0f9e-40a0-98e5-1bfad11d54a2",
"name": "Generate Stock Insight",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
1696,
-608
],
"parameters": {
"text": "=You are an experienced Portfolio Manager managing equity portfolios in the Indian stock market.\n\nAnalyze the following SINGLE STOCK strictly based on:\n1. Its performance metrics\n2. Recent news headlines\n3. Portfolio impact\n\nINPUT:\n- Stock: {{ $json.symbol }}\n- Performance Data: {{ JSON.stringify($json) }}\n\nINSTRUCTIONS:\n\n1. PERFORMANCE ANALYSIS:\n- Evaluate return %, pnl and position size\n- Classify performance as Strong / Moderate / Weak\n\n2. NEWS INTERPRETATION:\n- Identify overall sentiment (Positive / Negative / Neutral)\n- Extract key themes (e.g., earnings, market fall, sector pressure)\n\n3. INSIGHT GENERATION:\n- Explain WHY the stock is moving (connect data + news)\n- Mention if news supports or contradicts performance\n\n4. PORTFOLIO IMPACT:\n- Assess if this stock is helping or hurting the portfolio\n- Highlight risk if negative trend continues\n\n5. ACTIONABLE VIEW:\n- Give a professional stance: Hold / Monitor / Caution / Positive Bias\n- Do NOT give direct buy/sell advice\n\nRULES:\n- Be concise (80\u2013120 words)\n- No generic statements\n- No repetition\n- Sound like a real fund manager note\n\nOUTPUT FORMAT (STRICT JSON ONLY):\n{\n \"symbol\": \"{{ $json.symbol }}\",\n \"performance_label\": \"\",\n \"sentiment\": \"\",\n \"insight\": \"\",\n \"portfolio_impact\": \"\",\n \"action\": \"\"\n}",
"options": {},
"promptType": "define"
},
"typeVersion": 3.1
},
{
"id": "7d6f0e09-c41a-4573-8105-ebef9c0a5152",
"name": "LLM (Stock Analysis)",
"type": "@n8n/n8n-nodes-langchain.lmChatGroq",
"position": [
1760,
-368
],
"parameters": {
"model": "openai/gpt-oss-120b",
"options": {}
},
"credentials": {
"groqApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "4f4078f3-0e8a-4cf5-85cb-5c6c0d5b2a32",
"name": "Rate Limit (Wait)",
"type": "n8n-nodes-base.wait",
"position": [
2096,
-608
],
"parameters": {
"amount": 10
},
"typeVersion": 1.1
},
{
"id": "87add841-89ad-412a-85de-04feda51018d",
"name": "Aggregate Stock Insights",
"type": "n8n-nodes-base.aggregate",
"position": [
656,
-1184
],
"parameters": {
"options": {},
"fieldsToAggregate": {
"fieldToAggregate": [
{
"fieldToAggregate": "output"
}
]
}
},
"typeVersion": 1
},
{
"id": "64993235-88c2-4fe0-bc86-d9c3286073e8",
"name": "Parse Stock AI Output",
"type": "n8n-nodes-base.code",
"position": [
880,
-1184
],
"parameters": {
"jsCode": "const rawOutputs = $json.output;\n\n// Convert string \u2192 JSON\nconst parsed = rawOutputs.map(str => JSON.parse(str));\n\nreturn [{\n json: {\n stocks: parsed\n }\n}];"
},
"typeVersion": 2
},
{
"id": "400e3f83-e865-4093-97ce-9ce08f7e1adf",
"name": "Generate Portfolio Insight",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
1088,
-1184
],
"parameters": {
"text": "=You are a senior portfolio manager.\n\nYou are given structured stock-level insights.\n\nINPUT:\n{{ JSON.stringify($json.stocks) }}\n\nTASK:\n\n1. Classify overall portfolio performance (Positive / Mixed / Negative)\n2. Identify:\n - Top contributors\n - Key laggards\n3. Extract common themes (sector trends, risks, sentiment shifts)\n4. Highlight risks (negative sentiment, weak stocks)\n5. Provide a professional strategy view\n\nRULES:\n- 120 words max\n- No repetition\n- No listing each stock\n- Think like a hedge fund PM\n\nOUTPUT STRICT JSON:\n{\n \"portfolio_view\": \"\",\n \"drivers\": \"\",\n \"risks\": \"\",\n \"strategy\": \"\"\n}",
"options": {},
"promptType": "define"
},
"typeVersion": 3.1
},
{
"id": "96e514cf-0a6a-46f7-8087-64af7a04d50d",
"name": "LLM (Portfolio Analysis)",
"type": "@n8n/n8n-nodes-langchain.lmChatGroq",
"position": [
976,
-976
],
"parameters": {
"model": "openai/gpt-oss-20b",
"options": {}
},
"credentials": {
"groqApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "2de431f0-5e67-4397-b7f7-1900d7623cd2",
"name": "Parse Portfolio AI Output",
"type": "n8n-nodes-base.code",
"position": [
1392,
-1184
],
"parameters": {
"jsCode": "const aiRaw = $json.output;\n\n// Remove markdown formatting\nconst clean = aiRaw\n .replace(/```json/g, '')\n .replace(/```/g, '')\n .trim();\n\nconst ai = JSON.parse(clean);\n\nreturn [{\n json: {\n portfolio_ai: ai\n }\n}];"
},
"typeVersion": 2
},
{
"id": "6a8163a8-7b04-4244-ab62-8db131160bd6",
"name": "Merge Stocks + Portfolio Insight",
"type": "n8n-nodes-base.merge",
"position": [
1712,
-1024
],
"parameters": {},
"typeVersion": 3.2
},
{
"id": "7a428ce5-e672-4f3b-beac-c32d614fcbc4",
"name": "Format Email Report",
"type": "n8n-nodes-base.code",
"position": [
1952,
-1024
],
"parameters": {
"jsCode": "const items = $input.all();\n\n// Extract portfolio AI (first item)\nconst ai = items[0].json.portfolio_ai || {};\n\n// Extract stocks (second item)\nconst stocks = items[1].json.stocks || [];\n\nlet report = `Portfolio Report\\n\\n`;\n\n// Portfolio Section\nreport += `Portfolio Insights\\n`;\nreport += `\u2022 View: ${ai.portfolio_view || 'N/A'}\\n`;\nreport += `\u2022 Drivers: ${ai.drivers || 'N/A'}\\n`;\nreport += `\u2022 Risks: ${ai.risks || 'N/A'}\\n`;\nreport += `\u2022 Strategy: ${ai.strategy || 'N/A'}\\n\\n`;\n\n// Stock Section\nreport += `Stock-wise Analysis\\n`;\n\nstocks.forEach(s => {\n\n report += `\\n${s.symbol}\\n`;\n report += `Sentiment: ${s.sentiment || 'N/A'}\\n`;\n report += `${s.insight || 'No insight available'}\\n`;\n});\n\nreturn [{\n json: {\n report_text: report\n }\n}];"
},
"typeVersion": 2
},
{
"id": "33b6885f-6594-4f88-b008-571652545c34",
"name": "Send Email (Gmail)",
"type": "n8n-nodes-base.gmail",
"position": [
2208,
-1024
],
"parameters": {
"sendTo": "user@example.com",
"message": "={{ $json.report_text }}",
"options": {},
"subject": "Portfolio Performance Update",
"emailType": "text"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "da3e30d1-b102-4e18-8b10-67f3bcfc8ced",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-976,
-1664
],
"parameters": {
"width": 656,
"height": 576,
"content": "## AI Portfolio Performance & Insight Workflow\n\nThis workflow analyzes a stock portfolio using Google Sheets data and enhances it with AI-driven insights and market news.\n\n### How it works:\nThe workflow runs automatically every day at 4 PM using a schedule trigger, then reads portfolio data from Google Sheets. It calculates key metrics such as invested value, current value, profit/loss and return percentage. Each stock is processed individually, where recent news is fetched via RSS, filtered and combined with stock data. An AI model then generates professional stock-level insights.\n\nAfter all stocks are processed, the results are aggregated and passed to another AI step that generates an overall portfolio-level summary including performance view, key drivers, risks and strategy.\n\nFinally, both stock-level and portfolio-level insights are merged and formatted into a structured report, which is sent via email.\n\n### Setup steps:\n1. Configure Schedule Trigger (set time to 4 PM daily)\n2. Connect your Google Sheets account and update sheet structure\n3. Configure Groq/OpenAI credentials for AI nodes\n4. Verify RSS feed access (no auth required)\n5. Set your email in the final Gmail node"
},
"typeVersion": 1
},
{
"id": "266ec9c5-35ce-4df5-90d5-c603e4fce165",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-288,
-1296
],
"parameters": {
"color": 7,
"width": 416,
"height": 1040,
"content": "## Data Source & Trigger\nRuns automatically every day at 4 PM and fetches portfolio data (symbols, quantity, pricing) from Google Sheets."
},
"typeVersion": 1
},
{
"id": "02c3db0c-783b-4e95-a398-859fa48ecc66",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
144,
-1296
],
"parameters": {
"color": 7,
"width": 224,
"height": 1040,
"content": "## Portfolio Metrics Calculation\nComputes invested value, current value, profit/loss and return percentage for each stock."
},
"typeVersion": 1
},
{
"id": "d6837552-1a77-4b3e-acd1-d98643d61110",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
384,
-816
],
"parameters": {
"color": 7,
"width": 1216,
"height": 560,
"content": "## Stock Enrichment Pipeline\nProcesses each stock, fetches latest news, filters relevant articles and combines it with stock performance data."
},
"typeVersion": 1
},
{
"id": "b706522f-7183-4ed6-9fb3-bbf076f3af7c",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1616,
-1296
],
"parameters": {
"color": 7,
"width": 784,
"height": 464,
"content": "## Reporting & Delivery\nMerges all insights into a final report, formats it and sends it via email automatically after execution."
},
"typeVersion": 1
},
{
"id": "dede6972-7e50-439c-91e6-7e1eba4e5464",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1616,
-816
],
"parameters": {
"color": 7,
"width": 784,
"height": 560,
"content": "## Stock Enrichment Pipeline\nProcesses each stock, fetches latest news, filters relevant articles and combines it with stock performance data."
},
"typeVersion": 1
},
{
"id": "44004e67-e6e9-420a-b53e-dd322c63fe92",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
384,
-1296
],
"parameters": {
"color": 7,
"width": 1216,
"height": 464,
"content": "## Aggregation & Portfolio Analysis\nCombines all stock insights and generates an overall portfolio view, key drivers, risks and strategy."
},
"typeVersion": 1
},
{
"id": "1214021a-b82a-492d-bf7b-ac0eb3e9fa9d",
"name": "Calculate Portfolio Metrics",
"type": "n8n-nodes-base.set",
"position": [
192,
-800
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "89d24755-f2c8-4619-8bf0-9b7c5cb88bbe",
"name": "symbol",
"type": "string",
"value": "={{ $json.Symbol }}"
},
{
"id": "cf279431-dc12-40cb-9af0-f866ab58d291",
"name": "quantity",
"type": "number",
"value": "={{ $json.Quantity }}"
},
{
"id": "3b7b1037-9dfa-4ec1-9792-7bd4a2b8bd9f",
"name": "avg_price",
"type": "number",
"value": "={{ $json[\"Avg Price\"] }}"
},
{
"id": "9774e298-f994-48f5-a8b1-aec27e54aa43",
"name": "current_price",
"type": "number",
"value": "={{ $json[\"Current Price\"] }}"
},
{
"id": "14bca858-c7b3-4b69-833e-81f9bdad5eed",
"name": "invested",
"type": "number",
"value": "={{ $json.Quantity * $json[\"Avg Price\"] }}"
},
{
"id": "4996082e-4bcc-4a69-a20e-683847e14d1f",
"name": "value",
"type": "number",
"value": "={{ $json.Quantity * $json[\"Current Price\"]}}"
},
{
"id": "15e1b7c6-d0c4-41d9-ac32-d1ab56288f6f",
"name": "pnl",
"type": "number",
"value": "={{ ($json.Quantity * $json[\"Current Price\"]) - ($json.Quantity * $json[\"Avg Price\"]) }}"
},
{
"id": "2ca8751e-8ae3-42e3-abac-52539982aa14",
"name": "return_pct",
"type": "number",
"value": "={{ ((($json.Quantity * $json[\"Current Price\"]) - ($json.Quantity * $json[\"Avg Price\"])) / ($json.Quantity * $json[\"Avg Price\"])) * 100 }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "b2a6d137-ce11-4f93-a7b5-ca0329498bad",
"name": "Executes everyday at 4 PM",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-240,
-800
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 16
}
]
}
},
"typeVersion": 1.3
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "9e77af2e-3f29-4334-b170-66952128179a",
"connections": {
"Iterate Stocks": {
"main": [
[
{
"node": "Aggregate Stock Insights",
"type": "main",
"index": 0
}
],
[
{
"node": "Fetch Stock News (RSS)",
"type": "main",
"index": 0
}
]
]
},
"Rate Limit (Wait)": {
"main": [
[
{
"node": "Iterate Stocks",
"type": "main",
"index": 0
}
]
]
},
"Sort News by Date": {
"main": [
[
{
"node": "Limit News (Top 5)",
"type": "main",
"index": 0
}
]
]
},
"Limit News (Top 5)": {
"main": [
[
{
"node": "Merge Stock Data + News",
"type": "main",
"index": 0
}
]
]
},
"Format Email Report": {
"main": [
[
{
"node": "Send Email (Gmail)",
"type": "main",
"index": 0
}
]
]
},
"LLM (Stock Analysis)": {
"ai_languageModel": [
[
{
"node": "Generate Stock Insight",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Parse Stock AI Output": {
"main": [
[
{
"node": "Generate Portfolio Insight",
"type": "main",
"index": 0
},
{
"node": "Merge Stocks + Portfolio Insight",
"type": "main",
"index": 1
}
]
]
},
"Fetch Stock News (RSS)": {
"main": [
[
{
"node": "Sort News by Date",
"type": "main",
"index": 0
}
]
]
},
"Generate Stock Insight": {
"main": [
[
{
"node": "Rate Limit (Wait)",
"type": "main",
"index": 0
}
]
]
},
"Merge Stock Data + News": {
"main": [
[
{
"node": "Generate Stock Insight",
"type": "main",
"index": 0
}
]
]
},
"Aggregate Stock Insights": {
"main": [
[
{
"node": "Parse Stock AI Output",
"type": "main",
"index": 0
}
]
]
},
"LLM (Portfolio Analysis)": {
"ai_languageModel": [
[
{
"node": "Generate Portfolio Insight",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Executes everyday at 4 PM": {
"main": [
[
{
"node": "Fetch Portfolio (Google Sheets)",
"type": "main",
"index": 0
}
]
]
},
"Parse Portfolio AI Output": {
"main": [
[
{
"node": "Merge Stocks + Portfolio Insight",
"type": "main",
"index": 0
}
]
]
},
"Generate Portfolio Insight": {
"main": [
[
{
"node": "Parse Portfolio AI Output",
"type": "main",
"index": 0
}
]
]
},
"Calculate Portfolio Metrics": {
"main": [
[
{
"node": "Iterate Stocks",
"type": "main",
"index": 0
}
]
]
},
"Fetch Portfolio (Google Sheets)": {
"main": [
[
{
"node": "Calculate Portfolio Metrics",
"type": "main",
"index": 0
}
]
]
},
"Merge Stocks + Portfolio Insight": {
"main": [
[
{
"node": "Format Email Report",
"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.
gmailOAuth2googleSheetsOAuth2ApigroqApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This n8n workflow automatically analyzes your stock portfolio every day at 4 PM. It fetches portfolio data from Google Sheets, enriches it with latest market news via RSS, generates AI-powered stock insights using LLM models and sends a professional portfolio report directly to…
Source: https://n8n.io/workflows/15670/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
How it works: Daily Trigger: Every morning at 8 AM, the workflow is automatically triggered. Fetch Trending Topics: The workflow collects trending topics from external sources, such as news RSS feeds
This workflow automatically generates 2–3 high-quality Indian stock investment ideas daily by combining trending stock data + latest market news, processing it with AI (Groq/OpenAI), avoiding duplicat
Categories Content Creation AI Automation Publishing Social Media
This workflow automates the process of generating, reviewing, and publishing blog posts across multiple platforms, now enhanced with support for RSS Feeds as a content source. It streamlines the manag
This workflow automatically monitors competitor product prices stored in Google Sheets. It scrapes product pages, extracts pricing and offer data using AI, and compares it with historical values. Base