This workflow corresponds to n8n.io template #14015 — 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 →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "c8fef4bd-317f-4c63-9edb-26cc4a8bbbd3",
"name": "Weekly Competitor Sentiment Scan",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-2032,
64
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": [
1
],
"triggerAtHour": 8
}
]
}
},
"typeVersion": 1.2
},
{
"id": "9ec4c1a6-b046-445a-a726-30bd31d8b5fe",
"name": "Read Competitor Brands Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-1776,
64
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "id",
"value": "competitor_brands"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_SPREADSHEET_ID"
}
},
"typeVersion": 4.7
},
{
"id": "fc47064a-8496-4a85-a1ef-7f13b2d80439",
"name": "Scrape Reddit Posts",
"type": "n8n-nodes-base.httpRequest",
"position": [
-1504,
64
],
"parameters": {
"url": "=https://api.brightdata.com/datasets/v3/scrape?dataset_id=gd_md75myxy14rihbjksa&format=json",
"method": "POST",
"options": {
"timeout": 60000
},
"jsonBody": "={{ JSON.stringify({ input: [{ url: $json.url }] }) }}",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"typeVersion": 4.2
},
{
"id": "e7093216-09c8-4b89-800d-48219b9b43b6",
"name": "Validate BD Response",
"type": "n8n-nodes-base.code",
"position": [
-1248,
64
],
"parameters": {
"jsCode": "const input = $input.first().json;\n\n// Handle array response (synchronous success)\nif (Array.isArray(input)) {\n if (input.length === 0) {\n return [{ json: { error: 'Bright Data returned empty results', status: 'no_data' } }];\n }\n return input.map(item => ({ json: { ...item, status: 'ok' } }));\n}\n\n// Handle object response\nif (input.snapshot_id) {\n return [{ json: { error: 'Async response - snapshot not ready', snapshot_id: input.snapshot_id, status: 'async_pending' } }];\n}\n\nif (input.error || input.message) {\n return [{ json: { error: input.error || input.message, status: 'api_error' } }];\n}\n\n// Pass through valid single-object response\nreturn [{ json: { ...input, status: 'ok' } }];"
},
"typeVersion": 2
},
{
"id": "85c369ef-458e-47fa-9520-169e1a99ee5a",
"name": "Analyze Competitor Sentiment",
"type": "@n8n/n8n-nodes-langchain.agent",
"onError": "continueErrorOutput",
"position": [
-992,
64
],
"parameters": {
"text": "=Analyze Reddit sentiment about this competitor. Brand: {{ $json.brand_name }}, Industry: {{ $json.industry }}\n\n{{ JSON.stringify($json) }}",
"options": {
"systemMessage": "You are a competitive intelligence analyst specializing in social media sentiment.\nYou receive scraped Reddit post data discussing a competitor brand.\n\nYour job is to analyze the sentiment distribution and identify competitive opportunities.\n\nAnalyze the Reddit discussion and produce:\n- sentiment_distribution: object with three keys:\n - positive_pct: float 0.0-1.0, fraction of discussion that is positive.\n - neutral_pct: float 0.0-1.0, fraction that is neutral.\n - negative_pct: float 0.0-1.0, fraction that is negative.\n These three values must sum to 1.0.\n- overall_sentiment: string, one of 'positive', 'neutral', or 'negative'.\n Based on whichever percentage is highest in the distribution.\n- negative_ratio: float 0.0-1.0, the fraction of negative sentiment. Same as negative_pct.\n- top_complaints: array of strings, the most common complaints about this competitor.\n Be specific and actionable. Examples: 'slow customer support response times',\n 'pricing increased without added features', 'frequent downtime reported'.\n- top_praises: array of strings, what users genuinely like about the competitor.\n These represent strengths you need to match or exceed.\n- vulnerability_areas: array of strings, specific areas where the competitor is weak\n and where you could differentiate. Focus on recurring pain points with high emotional intensity.\n- competitive_opportunity_score: integer 0-100, how exploitable the competitor's weaknesses are.\n - 80-100: Major vulnerability. Widespread complaints about core functionality. Easy to exploit.\n - 60-80: Significant weakness. Multiple pain points with moderate user frustration.\n - 40-60: Some openings. Scattered complaints but competitor is generally well-regarded.\n - 20-40: Minor gaps. Few complaints, mostly minor issues.\n - 0-20: Fortress. Competitor is beloved with minimal criticism.\n\nOutput a JSON object with all fields listed above.\n\nScoring rubric for competitive_opportunity_score:\n- Start at 50 (baseline).\n- Add 10 for each major recurring complaint (3+ mentions or high emotional intensity).\n- Add 5 for each minor complaint.\n- Subtract 10 for each strong praise area that would be hard to compete with.\n- Subtract 5 for general positive sentiment above 60%.\n- Cap at 0-100.\n\nCRITICAL OUTPUT RULES:\n- Return ONLY a raw JSON object. Nothing else.\n- No markdown. No code fences. No explanations before or after.\n\nSELF-EVALUATION (mandatory):\nInclude an \"eval\" object in your response with:\n- confidence: float 0.0-1.0, your confidence in the analysis quality\n- reasoning: 1 sentence explaining your confidence level\n- data_quality: \"high\", \"medium\", or \"low\" based on input completeness\n- evidence_count: integer, number of data points you based the analysis on"
},
"promptType": "define"
},
"typeVersion": 3
},
{
"id": "71bc964d-b052-4003-b89a-ffbd3f942fd3",
"name": "GPT-5.4 Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-992,
304
],
"parameters": {
"model": "gpt-5.4",
"options": {}
},
"typeVersion": 1
},
{
"id": "8d8d546f-562e-452e-aa77-453a50b781de",
"name": "Parse AI Output",
"type": "n8n-nodes-base.code",
"position": [
-736,
64
],
"parameters": {
"jsCode": "const raw = $input.first().json.output || $input.first().json.text || '';\nconst clean = raw.replace(/```json\\n?/g, '').replace(/```\\n?/g, '').trim();\n\nlet parsed;\ntry {\n parsed = JSON.parse(clean);\n} catch (e) {\n parsed = {\n error: 'Failed to parse AI response',\n parse_error: e.message,\n raw_preview: raw.substring(0, 200)\n };\n}\nconst original = $(\"Read Competitor Brands Sheet\").first().json;\n\nreturn [{ json: { ...original, ...parsed, processed_at: new Date().toISOString() } }];"
},
"typeVersion": 2
},
{
"id": "736f9865-07cd-4625-b34e-8c34b4488648",
"name": "IF Confidence >= 0.7",
"type": "n8n-nodes-base.if",
"onError": "continueErrorOutput",
"position": [
-208,
64
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "a6a45894-669c-4579-ab65-fb1b84922ad3",
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "={{ $json.eval.confidence }}",
"rightValue": 0.7
}
]
}
},
"typeVersion": 2.2
},
{
"id": "cf47b62d-3152-4a3b-90a7-ee2d1f41c3ff",
"name": "Email Opportunity Alert",
"type": "n8n-nodes-base.gmail",
"position": [
320,
-224
],
"parameters": {
"sendTo": "=strategy@company.com",
"message": "=Competitive vulnerability discovered on Reddit.\n\nBrand: {{ $json.brand_name }}\nIndustry: {{ $json.industry }}\nOpportunity Score: {{ $json.competitive_opportunity_score }}/100\nOverall Sentiment: {{ $json.overall_sentiment }}\nNegative Ratio: {{ $json.negative_ratio }}\n\nTop Complaints:\n{{ $json.top_complaints.join('\\n') }}\n\nVulnerability Areas:\n{{ $json.vulnerability_areas.join('\\n') }}\n\nTop Praises (strengths to match):\n{{ $json.top_praises.join('\\n') }}",
"options": {},
"subject": "=Competitive vulnerability: {{ $json.brand_name }} (Opportunity: {{ $json.competitive_opportunity_score }})",
"emailType": "text"
},
"typeVersion": 2.1
},
{
"id": "95a47ce3-a09f-40ba-ad43-670f448cd715",
"name": "Append High Opportunity Brands",
"type": "n8n-nodes-base.googleSheets",
"position": [
320,
-80
],
"parameters": {
"columns": {
"value": {},
"schema": [],
"mappingMode": "autoMapInputData",
"matchingColumns": []
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "high_opportunity_brands"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_SPREADSHEET_ID"
}
},
"typeVersion": 4.7
},
{
"id": "d3b56303-4883-4a98-9006-e0ae1fbaedf0",
"name": "Append Competitor Sentiment",
"type": "n8n-nodes-base.googleSheets",
"position": [
320,
144
],
"parameters": {
"columns": {
"value": {},
"schema": [],
"mappingMode": "autoMapInputData",
"matchingColumns": []
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "competitor_sentiment"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_SPREADSHEET_ID"
}
},
"typeVersion": 4.7
},
{
"id": "45a310d2-aba8-450a-8afb-0ba2efb77945",
"name": "Append Low Confidence",
"type": "n8n-nodes-base.googleSheets",
"position": [
64,
144
],
"parameters": {
"columns": {
"value": {},
"schema": [],
"mappingMode": "autoMapInputData",
"matchingColumns": []
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "low_confidence_sentiment"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_SPREADSHEET_ID"
}
},
"typeVersion": 4.7
},
{
"id": "a94b00a1-88a2-4533-84e6-d6169cfa0aff",
"name": "Calculate Vulnerability Index",
"type": "n8n-nodes-base.code",
"position": [
-464,
64
],
"parameters": {
"jsCode": "const item = $input.first().json;\nconst negRatio = item.negative_ratio || 0;\nconst vulnAreas = item.vulnerability_areas || [];\nconst topComplaints = item.top_complaints || [];\n// Composite vulnerability score\nconst ratioScore = negRatio * 40;\nconst areaScore = Math.min(vulnAreas.length * 10, 30);\nconst complaintScore = Math.min(topComplaints.length * 6, 30);\nconst vulnerabilityIndex = Math.round(ratioScore + areaScore + complaintScore);\nconst exploitability = vulnerabilityIndex >= 70 ? 'high' : vulnerabilityIndex >= 40 ? 'medium' : 'low';\nreturn [{ json: { ...item, vulnerability_index: vulnerabilityIndex,\n exploitability: exploitability, attack_vectors: vulnAreas.slice(0, 3) } }];"
},
"typeVersion": 2
},
{
"id": "878713b2-0cbc-4313-99e4-4d2b07c5556e",
"name": "Route by Score Level",
"type": "n8n-nodes-base.switch",
"position": [
64,
-80
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "High",
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "1a139f90-25f8-419e-a1bc-c9a26e347c20",
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "{{ $json.competitive_opportunity_score }}",
"rightValue": 70
}
]
},
"renameOutput": true
},
{
"outputKey": "Medium",
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "740a834d-9e36-453a-b945-3497debf4c62",
"operator": {
"type": "number",
"operation": "gte"
},
"leftValue": "{{ $json.competitive_opportunity_score }}",
"rightValue": 42
}
]
},
"renameOutput": true
}
]
},
"options": {
"fallbackOutput": "extra"
}
},
"typeVersion": 3.2
},
{
"id": "ab9d356c-9fe8-41de-b99b-06489937f184",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2656,
-400
],
"parameters": {
"width": 560,
"height": 720,
"content": "### How it works\n\nThis workflow tracks Reddit sentiment about competitor brands on a weekly schedule. It reads brand URLs from a Google Sheet, scrapes Reddit posts through the Bright Data Reddit Posts API, and feeds the data to GPT-5.4 for sentiment analysis.\n\nThe AI calculates sentiment distribution (positive, neutral, negative percentages), identifies top complaints, praises, and vulnerability areas, and assigns a competitive opportunity score from 0-100. A separate code node computes a composite vulnerability index based on negative sentiment ratio, vulnerability areas, and complaint count.\n\nResults pass through a confidence gate (>= 0.7) to filter unreliable AI outputs. A three-way switch then routes by opportunity score: high-opportunity brands (>= 70) trigger a Gmail alert and go to 'high_opportunity_brands', while medium and low scores write to 'competitor_sentiment'. Low-confidence results land in 'low_confidence_sentiment' for review.\n\n### Setup\n\n1. Create a Google Sheet with a tab named 'competitor_brands' and a 'url' column containing Reddit post or thread URLs about each competitor\n2. Add your Bright Data API key as an HTTP Header Auth credential (Bearer token)\n3. Add your OpenAI API key\n4. Connect Google Sheets via OAuth\n5. Connect Gmail via OAuth for alerts\n6. Set the alert recipient email in the 'Email Opportunity Alert' node\n\nCost: ~$0.01-0.03 per post (Bright Data) + ~$0.005 per analysis (GPT-5.4)"
},
"typeVersion": 1
},
{
"id": "6a27fa9d-2631-4b77-9529-46f58fdf40a0",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2064,
-96
],
"parameters": {
"color": 7,
"width": 484,
"height": 392,
"content": "## 1. Data Input\n\nTriggers weekly on Monday at 8 AM. Reads competitor brand URLs from the 'competitor_brands' sheet."
},
"typeVersion": 1
},
{
"id": "d2691e91-5d20-4924-8869-7e16d015f640",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1552,
-64
],
"parameters": {
"color": 7,
"width": 1004,
"height": 516,
"content": "## 2. Scrape & Analyze\n\nScrapes Reddit via Bright Data. GPT-5.4 evaluates sentiment distribution and competitive vulnerabilities. Vulnerability index calculated from negative ratio, areas, and complaints."
},
"typeVersion": 1
},
{
"id": "40667cb0-2f8f-4986-8be6-92f306a3dc6b",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-256,
-384
],
"parameters": {
"color": 7,
"width": 992,
"height": 808,
"content": "## 3. Score Routing & Output\n\nConfidence gate filters unreliable AI output. Three-way switch routes by opportunity score to sheets and Gmail alerts."
},
"typeVersion": 1
}
],
"connections": {
"GPT-5.4 Model": {
"ai_languageModel": [
[
{
"node": "Analyze Competitor Sentiment",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Parse AI Output": {
"main": [
[
{
"node": "Calculate Vulnerability Index",
"type": "main",
"index": 0
}
]
]
},
"Scrape Reddit Posts": {
"main": [
[
{
"node": "Validate BD Response",
"type": "main",
"index": 0
}
]
]
},
"IF Confidence >= 0.7": {
"main": [
[
{
"node": "Route by Score Level",
"type": "main",
"index": 0
}
],
[
{
"node": "Append Low Confidence",
"type": "main",
"index": 0
}
]
]
},
"Route by Score Level": {
"main": [
[
{
"node": "Email Opportunity Alert",
"type": "main",
"index": 0
},
{
"node": "Append High Opportunity Brands",
"type": "main",
"index": 0
}
],
[
{
"node": "Append Competitor Sentiment",
"type": "main",
"index": 0
}
],
[
{
"node": "Append Competitor Sentiment",
"type": "main",
"index": 0
}
]
]
},
"Validate BD Response": {
"main": [
[
{
"node": "Analyze Competitor Sentiment",
"type": "main",
"index": 0
}
]
]
},
"Analyze Competitor Sentiment": {
"main": [
[
{
"node": "Parse AI Output",
"type": "main",
"index": 0
}
]
]
},
"Read Competitor Brands Sheet": {
"main": [
[
{
"node": "Scrape Reddit Posts",
"type": "main",
"index": 0
}
]
]
},
"Calculate Vulnerability Index": {
"main": [
[
{
"node": "IF Confidence >= 0.7",
"type": "main",
"index": 0
}
]
]
},
"Weekly Competitor Sentiment Scan": {
"main": [
[
{
"node": "Read Competitor Brands Sheet",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Analyze Reddit sentiment around competitor brands using Bright Data URL-based scraping and GPT-5.4.
Source: https://n8n.io/workflows/14015/ — 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.
This n8n automation workflow automates the creation, scripting, production, and posting of YouTube videos. It leverages AI (OpenAI), image generation (PIAPI), video rendering (Shotstack), and platform
Created by: Peyton Leveillee Last updated: October 2025
The Multi-Model Agency Content Engine is a high-performance editorial system designed for agencies. It solves the "blank page" problem by alternating between real-world social proof and strategic expe
This workflow automates the creation, rendering, approval, and posting of TikTok-style POV (Point of View) videos to Instagram, with cross-posting to Facebook and YouTube. It eliminates manual video p
SEO Blog Article Generation Workflow. Uses outputParserStructured, httpRequest, agent, lmChatOpenAi. Scheduled trigger; 56 nodes.