This workflow follows the Chainllm → Anthropic Chat 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 →
{
"name": "reddit-market-brief",
"nodes": [
{
"parameters": {},
"id": "manual-trigger",
"name": "Run manually",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
-416,
352
]
},
{
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 7
}
]
}
},
"id": "schedule-trigger",
"name": "Daily 07:00",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
-416,
160
]
},
{
"parameters": {
"workflowId": {
"__rl": true,
"value": "knObnnQbnIHP9DAy",
"mode": "list",
"cachedResultName": "reddit-scraper"
},
"workflowInputs": {
"mappingMode": "defineBelow",
"value": {
"targetURL": "https://old.reddit.com/r/wallstreetbets/top.json?t=day&limit=20"
},
"matchingColumns": [],
"schema": [
{
"id": "targetURL",
"displayName": "targetURL",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": true
},
"options": {}
},
"id": "f1e2d3c4-b5a6-4788-9c0d-11a2b3c4d5e6",
"name": "Scrape r/wallstreetbets (browserless)",
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1.3,
"position": [
-176,
64
],
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 3000
},
{
"parameters": {
"jsCode": "// Posts arrive as individual Split Out items from the RedditScraper sub-workflow.\n// Each item.json is a Reddit child: { kind, data: { ...post } }.\nconst clean = (s) => String(s || '').replace(/\\s+/g, ' ').trim();\nconst posts = items.map(it => it.json && it.json.data).filter(d => d && d.title);\nconst blocks = posts.map((d, i) => {\n const score = d.score ?? 0;\n const comments = d.num_comments ?? 0;\n const ratio = d.upvote_ratio != null ? Math.round(Number(d.upvote_ratio) * 100) + '%' : 'n/a';\n const flair = d.link_flair_text ? ` | flair: ${d.link_flair_text}` : '';\n const author = d.author || 'unknown';\n let body = clean(d.selftext);\n if (body.length > 600) body = body.slice(0, 600) + '\u2026';\n const url = d.permalink ? `https://www.reddit.com${d.permalink}` : (d.url || '');\n return `${i + 1}. ${clean(d.title)}\\n score ${score} | ${comments} comments | ${ratio} upvoted | u/${author}${flair}\\n body: ${body || '(link/image post, no text)'}\\n link: ${url}`;\n});\nconst today = new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });\nconst redditData = blocks.length ? blocks.join('\\n\\n') : 'No posts available.';\nreturn [{ json: { redditData, postCount: posts.length, today } }];"
},
"id": "parse-posts",
"name": "Parse posts",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
64,
64
]
},
{
"parameters": {
"promptType": "define",
"text": "=You are a sharp markets analyst writing a daily brief for a Discord channel, based on today's top {{ $json.postCount }} posts from r/wallstreetbets over the last 24 hours. Each post below includes its title, score, comment count, upvote ratio, author, body text, and link.\n\nWrite a clear, well-structured brief in Discord markdown. Use EXACTLY these sections, each with short punchy bullets. No preamble, no closing summary.\n\n**\ud83e\udded Market Sentiment**\n- 2-3 lines: overall mood (bullish / bearish / mixed), how strong the conviction is, and what is driving it.\n\n**\ud83d\udd25 Hot Tickers**\n- Up to 6 tickers getting the most attention. Format each as: $TICKER \u2014 4-8 word reason or direction.\n\n**\ud83e\udde0 Notable DD & Discussions**\n- Up to 4 posts that contain genuine analysis, DD, or high-quality debate. Summarize each in 1-2 lines: the thesis and the angle.\n\n**\ud83d\udca1 Ideas Being Floated**\n- Up to 4 concrete trade ideas or theses the community is suggesting.\n\n**\ud83d\udcf0 Catalysts / News**\n- Up to 4 events, earnings, or macro themes surfacing in the posts.\n\nRules: be specific and concrete, always write tickers as $TICKER, and reference the actual post content. No generic filler. If the data is thin or off-topic for markets, say so briefly in the relevant section. Finish with this exact line on its own, in italics:\n_Sourced from r/wallstreetbets top posts \u2022 community chatter, not financial advice._\n\nPosts:\n{{ $json.redditData }}",
"batching": {}
},
"id": "llm-chain",
"name": "Market analysis (LLM)",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"typeVersion": 1.9,
"position": [
304,
64
]
},
{
"parameters": {
"model": {
"__rl": true,
"mode": "id",
"value": "claude-opus-4-8"
},
"options": {}
},
"id": "anthropic-model",
"name": "Anthropic Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"typeVersion": 1.5,
"position": [
304,
272
]
},
{
"parameters": {
"jsCode": "const j = items[0] ? items[0].json : {};\nlet text = j.text ?? j.response ?? j.output ?? '';\ntext = String(text).trim();\nconst today = new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });\nconst full = `**\ud83d\udcca r/wallstreetbets \u2014 AI Market Brief \u2014 ${today}**\\n\\n` + text;\nfunction smartChunk(t, maxLen = 1900) {\n const lines = t.split('\\n');\n const chunks = [];\n let cur = '';\n for (const line of lines) {\n const test = cur + (cur ? '\\n' : '') + line;\n if (test.length > maxLen && cur) { chunks.push(cur); cur = line; }\n else { cur = test; }\n }\n if (cur) chunks.push(cur);\n return chunks.length ? chunks : ['(empty)'];\n}\nconst chunks = smartChunk(full);\nreturn chunks.map((content, i) => ({ json: { content: content.trimEnd() + '\\n', part: i + 1, total: chunks.length } }));"
},
"id": "format-discord",
"name": "Format for Discord",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
560,
64
]
},
{
"parameters": {
"authentication": "webhook",
"content": "={{$json.content}}",
"options": {
"flags": [
"SUPPRESS_EMBEDS"
]
}
},
"id": "discord-send",
"name": "Send to Discord",
"type": "n8n-nodes-base.discord",
"typeVersion": 2,
"position": [
800,
64
]
},
{
"parameters": {
"amount": 60
},
"id": "0b1c2d3e-4f5a-4b6c-8d7e-9f0a1b2c3d4e",
"name": "Wait 60s",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
-176,
304
]
},
{
"parameters": {
"workflowId": {
"__rl": true,
"value": "knObnnQbnIHP9DAy",
"mode": "list",
"cachedResultName": "reddit-scraper"
},
"workflowInputs": {
"mappingMode": "defineBelow",
"value": {
"targetURL": "https://old.reddit.com/r/pennystocks/top.json?t=day&limit=20"
},
"matchingColumns": [],
"schema": [
{
"id": "targetURL",
"displayName": "targetURL",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": true
},
"options": {}
},
"id": "a9b8c7d6-e5f4-4312-8a1b-2c3d4e5f6a7b",
"name": "Scrape r/pennystocks (browserless)",
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1.3,
"position": [
-176,
464
],
"retryOnFail": true,
"maxTries": 3,
"waitBetweenTries": 3000
},
{
"parameters": {
"jsCode": "// Posts arrive as individual Split Out items from the RedditScraper sub-workflow.\n// Each item.json is a Reddit child: { kind, data: { ...post } }.\nconst clean = (s) => String(s || '').replace(/\\s+/g, ' ').trim();\nconst posts = items.map(it => it.json && it.json.data).filter(d => d && d.title);\nconst blocks = posts.map((d, i) => {\n const score = d.score ?? 0;\n const comments = d.num_comments ?? 0;\n const ratio = d.upvote_ratio != null ? Math.round(Number(d.upvote_ratio) * 100) + '%' : 'n/a';\n const flair = d.link_flair_text ? ` | flair: ${d.link_flair_text}` : '';\n const author = d.author || 'unknown';\n let body = clean(d.selftext);\n if (body.length > 600) body = body.slice(0, 600) + '\u2026';\n const url = d.permalink ? `https://www.reddit.com${d.permalink}` : (d.url || '');\n return `${i + 1}. ${clean(d.title)}\\n score ${score} | ${comments} comments | ${ratio} upvoted | u/${author}${flair}\\n body: ${body || '(link/image post, no text)'}\\n link: ${url}`;\n});\nconst today = new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });\nconst redditData = blocks.length ? blocks.join('\\n\\n') : 'No posts available.';\nreturn [{ json: { redditData, postCount: posts.length, today } }];"
},
"id": "8dd2da56-aa06-443d-96f7-5244a46aa09a",
"name": "Parse posts (pennystocks)",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
64,
464
]
},
{
"parameters": {
"promptType": "define",
"text": "=You are a sharp small-cap analyst writing a daily brief for a Discord channel, based on today's top {{ $json.postCount }} posts from r/pennystocks over the last 24 hours. Each post below includes its title, score, comment count, upvote ratio, author, body text, and link.\n\nWrite a clear, well-structured brief in Discord markdown. Use EXACTLY these sections, each with short punchy bullets. No preamble, no closing summary.\n\n**\ud83e\udded Market Sentiment**\n- 2-3 lines: overall mood (bullish / bearish / mixed) toward penny & micro-cap names.\n\n**\ud83d\udd25 Hot Tickers**\n- Up to 6 tickers getting the most attention. Format each as: $TICKER \u2014 4-8 word reason or direction.\n\n**\ud83e\udde0 Notable DD & Discussions**\n- Up to 4 posts that contain genuine analysis, DD, or high-quality debate.\n\n**\ud83d\udca1 Ideas Being Floated**\n- Up to 4 concrete trade ideas or theses the community is suggesting.\n\n**\u26a0\ufe0f Risk & Pump Watch**\n- Up to 4 red flags: possible pump-and-dumps, dilution, low-float squeezes, or hype with no substance.\n\n**\ud83d\udcf0 Catalysts / News**\n- Up to 4 events, earnings, FDA/PR, or macro themes surfacing in the posts.\n\nRules: be specific and concrete, always write tickers as $TICKER, and reference the actual post content. No generic filler. If the data is thin or off-topic for markets, say so briefly in the relevant section. Finish with this exact line on its own, in italics:\n_Sourced from r/pennystocks top posts \u2022 community chatter, not financial advice._\n\nPosts:\n{{ $json.redditData }}",
"batching": {}
},
"id": "e93197cf-10c5-478f-bc5b-37eafb0ee701",
"name": "Market analysis (pennystocks)",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"typeVersion": 1.9,
"position": [
288,
464
]
},
{
"parameters": {
"jsCode": "const j = items[0] ? items[0].json : {};\nlet text = j.text ?? j.response ?? j.output ?? '';\ntext = String(text).trim();\nconst today = new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });\nconst full = `**\ud83e\ude99 r/pennystocks \u2014 AI Penny Stock Brief \u2014 ${today}**\\n\\n` + text;\nfunction smartChunk(t, maxLen = 1900) {\n const lines = t.split('\\n');\n const chunks = [];\n let cur = '';\n for (const line of lines) {\n const test = cur + (cur ? '\\n' : '') + line;\n if (test.length > maxLen && cur) { chunks.push(cur); cur = line; }\n else { cur = test; }\n }\n if (cur) chunks.push(cur);\n return chunks.length ? chunks : ['(empty)'];\n}\nconst chunks = smartChunk(full);\nreturn chunks.map((content, i) => ({ json: { content: content.trimEnd() + '\\n', part: i + 1, total: chunks.length } }));"
},
"id": "383ca65a-622e-4524-b296-0009adbcce42",
"name": "Format for Discord (pennystocks)",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
560,
464
]
},
{
"parameters": {
"authentication": "webhook",
"content": "={{$json.content}}",
"options": {
"flags": [
"SUPPRESS_EMBEDS"
]
}
},
"id": "dbafca9a-5c3a-4cb8-b246-fb3c16c69274",
"name": "Send to Discord (pennystocks)",
"type": "n8n-nodes-base.discord",
"typeVersion": 2,
"position": [
800,
464
]
}
],
"connections": {
"Run manually": {
"main": [
[
{
"node": "Scrape r/wallstreetbets (browserless)",
"type": "main",
"index": 0
}
]
]
},
"Daily 07:00": {
"main": [
[
{
"node": "Scrape r/wallstreetbets (browserless)",
"type": "main",
"index": 0
}
]
]
},
"Scrape r/wallstreetbets (browserless)": {
"main": [
[
{
"node": "Parse posts",
"type": "main",
"index": 0
},
{
"node": "Wait 60s",
"type": "main",
"index": 0
}
]
]
},
"Wait 60s": {
"main": [
[
{
"node": "Scrape r/pennystocks (browserless)",
"type": "main",
"index": 0
}
]
]
},
"Scrape r/pennystocks (browserless)": {
"main": [
[
{
"node": "Parse posts (pennystocks)",
"type": "main",
"index": 0
}
]
]
},
"Parse posts": {
"main": [
[
{
"node": "Market analysis (LLM)",
"type": "main",
"index": 0
}
]
]
},
"Anthropic Chat Model": {
"ai_languageModel": [
[
{
"node": "Market analysis (LLM)",
"type": "ai_languageModel",
"index": 0
},
{
"node": "Market analysis (pennystocks)",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Market analysis (LLM)": {
"main": [
[
{
"node": "Format for Discord",
"type": "main",
"index": 0
}
]
]
},
"Format for Discord": {
"main": [
[
{
"node": "Send to Discord",
"type": "main",
"index": 0
}
]
]
},
"Parse posts (pennystocks)": {
"main": [
[
{
"node": "Market analysis (pennystocks)",
"type": "main",
"index": 0
}
]
]
},
"Market analysis (pennystocks)": {
"main": [
[
{
"node": "Format for Discord (pennystocks)",
"type": "main",
"index": 0
}
]
]
},
"Format for Discord (pennystocks)": {
"main": [
[
{
"node": "Send to Discord (pennystocks)",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {
"executionOrder": "v1",
"binaryMode": "separate"
},
"versionId": "f8bce5ad-67ad-4071-a758-dc2e980c8228",
"nodeGroups": [],
"id": "fAN9c6ZoZRD8LRAL",
"tags": []
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
reddit-market-brief. Uses chainLlm, lmChatAnthropic, discord. Event-driven trigger; 14 nodes.
Source: https://github.com/maker-lab-9000/n8n/blob/main/reddit-market-brief/reddit-market-brief.json — 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.
Episode 11: AI shorts factory app. Uses httpRequest, googleSheets, lmChatOpenAi, lmChatOllama. Event-driven trigger; 96 nodes.
This workflow automates Invoice & Payment Tracking (with Approvals) across Notion and Slack. Ingest — You drop invoices/receipts (PDF/IMG/JSON) into the flow. Extract — OCR + parsing pulls out key fie
Content - Newsletter Agent. Uses formTrigger, chainLlm, outputParserStructured, httpRequest. Event-driven trigger; 91 nodes.
A Telegram bot that converts natural-language work descriptions into detailed cost estimates using AI parsing, vector search, and the open-source DDC CWICR database with 55,000+ construction work item
Content - Newsletter Agent. Uses formTrigger, chainLlm, outputParserStructured, httpRequest. Event-driven trigger; 87 nodes.