使用GPT-4o、Google Sheets和邮件的自动品牌提及追踪器
中级
这是一个AI, Marketing领域的自动化工作流,包含 14 个节点。主要使用 Code, EmailSend, HttpRequest, GoogleSheets, ScheduleTrigger 等节点,结合人工智能技术实现智能自动化。 使用GPT-4o、Google Sheets和邮件的自动品牌提及追踪器
前置要求
- •可能需要目标 API 的认证凭证
- •Google Sheets API 凭证
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"meta": {
"instanceId": "45be95bf90d9b3ae2fe5e2695ab0d09c072dff6b4645327103a14d107f342c30",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "a3e98b7d-e020-402b-848f-c47025a37ed7",
"name": "每日触发器",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-380,
-80
],
"parameters": {
"rule": {
"interval": [
{}
]
}
},
"typeVersion": 1.1
},
{
"id": "645199f4-192f-407b-b842-8f3d9c85a12a",
"name": "设置查询",
"type": "n8n-nodes-base.code",
"position": [
-160,
-80
],
"parameters": {
"jsCode": "// Configuration - Update these values\nconst brandName = \"YourBrandName\"; // TODO: Replace with your actual brand name\n\n// TODO: Replace these example queries with ones relevant to YOUR brand and industry.\n// Aim for a mix of query types to get comprehensive insights.\nconst queries = [\n // --- General Brand Awareness & Perception ---\n \"What is [YourBrandName]?\",\n \"Tell me about [YourBrandName]'s main products/services.\",\n \"What are the benefits of using [YourBrandName]?\",\n \"How does [YourBrandName] compare to other solutions in the [YourIndustry] market?\",\n \"What do people say about [YourBrandName]?\",\n\n // --- Problem/Solution Fit (User trying to solve a problem YourBrandName addresses) ---\n \"How can I solve [Problem YourBrandName Solves]?\",\n \"What are the best tools for [Task YourBrandName Helps With]?\",\n \"I'm looking for a way to [Achieve Goal YourBrandName Facilitates], any suggestions?\",\n\n // --- Feature-Specific or Use-Case Queries ---\n \"Does [YourBrandName] offer [Specific Feature]?\",\n \"How can I use [YourBrandName] for [Specific Use Case]?\",\n\n // --- Competitor Comparison (Direct & Indirect) ---\n // Replace [Competitor A/B/C] with actual competitor names relevant to you.\n \"What are alternatives to [Competitor A]?\",\n \"Compare [YourBrandName] and [Competitor B].\",\n \"Is [YourBrandName] better than [Competitor C] for [Specific Need]?\",\n\n // --- Industry or Category Questions (Where YourBrandName should ideally be mentioned) ---\n \"What are the leading companies in the [YourIndustry] sector?\",\n \"Recommend a good [Product/Service Category YourBrandName Belongs To].\",\n\n // --- Negative or Challenging Queries (To see how AI handles them) ---\n \"What are some downsides of using [YourBrandName]?\",\n \"Are there any common complaints about [YourBrandName]?\",\n\n // --- Buying Intent / Recommendation Seeking ---\n \"Should I choose [YourBrandName] for [Specific Purpose]?\",\n \"What's the best [Product/Service Category] for someone who needs [Specific Requirement]?\",\n\n // --- Add more queries specific to your brand, product features, target audience pain points, and competitive landscape ---\n // Example: \"How does [YourBrandName] handle [Unique Selling Proposition]?\"\n // Example: \"What are the pricing options for [YourBrandName]?\"\n];\n\n// Create output items\nconst items = [];\nfor (let i = 0; i < queries.length; i++) {\n items.push({\n json: {\n brandName: brandName,\n query: queries[i],\n queryIndex: i + 1,\n timestamp: new Date().toISOString(),\n date: new Date().toISOString().split('T')[0]\n }\n });\n}\n\nreturn items;"
},
"typeVersion": 2
},
{
"id": "f56df036-8e1e-46d8-81b1-fc96d6107c7f",
"name": "查询 ChatGPT (HTTP)",
"type": "n8n-nodes-base.httpRequest",
"position": [
60,
-80
],
"parameters": {
"url": "https://api.openai.com/v1/chat/completions",
"method": "POST",
"options": {
"response": {
"response": {
"neverError": true,
"fullResponse": true
}
}
},
"jsonBody": "={\n \"model\": \"chatgpt-4o-latest\",\n \"messages\": [\n {\n \"role\": \"user\", \n \"content\": \"{{ $json.query }}\"\n }\n ],\n \"max_tokens\": 1000,\n \"temperature\": 0.7\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"nodeCredentialType": "openAiApi"
},
"credentials": {
"openAiApi": {
"id": "t921mWykUSe9acQO",
"name": "OpenAi account"
}
},
"typeVersion": 4.2
},
{
"id": "0aa04ced-7fb9-4763-98a9-01efaf0b1a8d",
"name": "处理响应",
"type": "n8n-nodes-base.code",
"position": [
280,
-80
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Process the response and check for brand mentions\nconst httpResponse = $json; // This is the HTTP response\nconst originalQueries = $('Setup Queries').all(); // Get all original queries\n\n// Find the matching original query for this response\n// Since we're processing items one by one, we need to match by index\nconst currentIndex = $itemIndex; // Current item index\nconst originalData = originalQueries[currentIndex]?.json;\n\n// Get brand name from original data\nconst brandName = originalData?.brandName?.toLowerCase() || 'unknown';\n\nlet response = '';\nlet brandMentioned = 'No';\nlet error = null;\n\n// Check if there was an error\nif (httpResponse.statusCode && httpResponse.statusCode !== 200) {\n response = `HTTP Error: ${httpResponse.statusCode} - ${httpResponse.statusMessage || 'Request failed'}`;\n brandMentioned = 'Error';\n error = `HTTP ${httpResponse.statusCode}`;\n} else if (httpResponse.body && httpResponse.body.choices && httpResponse.body.choices[0]) {\n response = httpResponse.body.choices[0].message.content;\n // Check for brand mention (case insensitive)\n if (brandName && brandName !== 'unknown' && response.toLowerCase().includes(brandName)) {\n brandMentioned = 'Yes';\n }\n} else if (httpResponse.body && httpResponse.body.error) {\n response = `API Error: ${httpResponse.body.error.message}`;\n brandMentioned = 'Error';\n error = httpResponse.body.error.message;\n} else {\n response = 'No valid response received';\n brandMentioned = 'Error';\n error = 'Invalid response structure';\n}\n\n// Return combined data\nreturn {\n json: {\n timestamp: originalData?.timestamp || new Date().toISOString(),\n date: originalData?.date || new Date().toISOString().split('T')[0],\n query: originalData?.query || 'Unknown query',\n queryIndex: originalData?.queryIndex || currentIndex + 1,\n brandName: originalData?.brandName || 'Unknown brand',\n response: response.substring(0, 500), // Limit response length\n brandMentioned: brandMentioned,\n error: error\n }\n};"
},
"typeVersion": 2
},
{
"id": "5734b4c6-731b-4384-b86b-6732501015d6",
"name": "保存到 Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
500,
-80
],
"parameters": {
"columns": {
"value": {
"Date": "={{ $json.date }}",
"Error": "={{ $json.error }}",
"Query": "={{ $json.query }}",
"Response": "={{ $json.response }}",
"Timestamp": "={{ $json.timestamp }}",
"Brand_Name": "={{ $json.brandName }}",
"Query_Index": "={{ $json.queryIndex }}",
"Brand_Mentioned": "={{ $json.brandMentioned }}"
},
"schema": [
{
"id": "Timestamp",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Date",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Query",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Query",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Query_Index",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Query_Index",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Brand_Name",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Brand_Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Response",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Response",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Brand_Mentioned",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Brand_Mentioned",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Error",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Error",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_GOOGLE_SHEET_ID"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "k9rHOUQ8uoo854zo",
"name": "Google Sheets account"
}
},
"typeVersion": 4.4
},
{
"id": "e0878bda-3f73-4ba4-9845-ca472109e566",
"name": "生成邮件报告",
"type": "n8n-nodes-base.code",
"position": [
720,
-80
],
"parameters": {
"jsCode": "// Generate email summary with competitor detection\nconst allItems = $input.all();\n\n// Get the processed data from Process Response node\nconst processedData = $('Process Response').all();\nconst dataToUse = processedData.length > 0 ? processedData : allItems;\n\n// Define competitors to look for (add/modify as needed)\nconst competitors = [\n 'honey',\n 'rakuten',\n 'ebates',\n 'capital one shopping',\n 'wikibuy',\n 'retailmenot',\n 'couponfollow',\n 'groupon',\n 'slickdeals',\n 'cashback',\n 'ibotta',\n 'dosh',\n 'drop',\n 'pei',\n 'checkout 51',\n 'swagbucks',\n 'topcashback',\n 'mr. rebates',\n 'befrugal',\n 'extrabux'\n];\n\n// Function to find competitors mentioned in response\nfunction findCompetitors(response) {\n if (!response || typeof response !== 'string') return [];\n \n const responseText = response.toLowerCase();\n const foundCompetitors = [];\n \n competitors.forEach(competitor => {\n if (responseText.includes(competitor.toLowerCase())) {\n // Capitalize first letter of each word for display\n const displayName = competitor.split(' ')\n .map(word => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n foundCompetitors.push(displayName);\n }\n });\n \n return foundCompetitors;\n}\n\nconst totalQueries = dataToUse.length;\nconst mentions = dataToUse.filter(item => item.json.brandMentioned === 'Yes').length;\nconst errors = dataToUse.filter(item => item.json.brandMentioned === 'Error').length;\nconst brandName = dataToUse[0]?.json.brandName || 'Unknown';\nconst date = dataToUse[0]?.json.date || new Date().toISOString().split('T')[0];\n\n// Count total competitor mentions\nlet totalCompetitorMentions = 0;\nconst competitorCounts = {};\n\n// Create HTML table\nlet tableRows = '';\ndataToUse.forEach((item, index) => {\n const bgColor = item.json.brandMentioned === 'Yes' ? '#d4edda' : \n item.json.brandMentioned === 'Error' ? '#f8d7da' : '#fff';\n \n // Find competitors in this response\n const competitorsFound = findCompetitors(item.json.response);\n const competitorsDisplay = competitorsFound.length > 0 ? \n competitorsFound.join(', ') : \n 'None';\n \n // Count competitors for summary\n competitorsFound.forEach(comp => {\n competitorCounts[comp] = (competitorCounts[comp] || 0) + 1;\n totalCompetitorMentions++;\n });\n \n tableRows += `\n <tr style=\"background-color: ${bgColor};\">\n <td>${item.json.queryIndex || index + 1}</td>\n <td>${item.json.query || 'Unknown query'}</td>\n <td><strong>${item.json.brandMentioned || 'Unknown'}</strong></td>\n <td>${competitorsDisplay}</td>\n </tr>\n `;\n});\n\n// Create competitor summary\nlet competitorSummary = '';\nif (Object.keys(competitorCounts).length > 0) {\n competitorSummary = '<h3>Competitor Mentions Summary:</h3><ul>';\n Object.entries(competitorCounts)\n .sort((a, b) => b[1] - a[1]) // Sort by count descending\n .forEach(([competitor, count]) => {\n competitorSummary += `<li><strong>${competitor}</strong>: ${count} mentions</li>`;\n });\n competitorSummary += '</ul>';\n} else {\n competitorSummary = '<p><em>No competitors mentioned in any responses.</em></p>';\n}\n\nconst subject = mentions > 0 ? \n `🎯 Brand Mentioned! ${brandName} found in ${mentions}/${totalQueries} queries` :\n `📊 Daily Report: ${brandName} - No mentions found`;\n\nconst htmlContent = `\n<h2>Brand Mention Monitor Report</h2>\n<p><strong>Brand:</strong> ${brandName}</p>\n<p><strong>Date:</strong> ${date}</p>\n<p><strong>Summary:</strong></p>\n<ul>\n <li>Total Queries: ${totalQueries}</li>\n <li>Brand Mentions: ${mentions}</li>\n <li>Competitor Mentions: ${totalCompetitorMentions}</li>\n <li>Errors: ${errors}</li>\n <li>Success Rate: ${Math.round(((totalQueries - errors) / totalQueries) * 100)}%</li>\n</ul>\n\n${competitorSummary}\n\n<table border=\"1\" style=\"border-collapse: collapse; width: 100%;\">\n <thead>\n <tr style=\"background-color: #f8f9fa;\">\n <th>Query #</th>\n <th>Query</th>\n <th>Brand Mentioned</th>\n <th>Competitors Mentioned</th>\n </tr>\n </thead>\n <tbody>\n ${tableRows}\n </tbody>\n</table>\n\n<p><em>Full details saved to Google Sheets</em></p>\n`;\n\nreturn {\n json: {\n subject: subject,\n htmlContent: htmlContent,\n summary: {\n totalQueries,\n mentions,\n errors,\n brandName,\n date,\n competitorMentions: totalCompetitorMentions,\n competitorBreakdown: competitorCounts\n }\n }\n};\n"
},
"executeOnce": true,
"typeVersion": 2
},
{
"id": "7a27b9c0-7786-4f72-8aae-8f07887364a7",
"name": "发送电子邮件",
"type": "n8n-nodes-base.emailSend",
"position": [
940,
-80
],
"webhookId": "14d26982-a3f0-4621-92f1-0c9e00d6c627",
"parameters": {
"html": "={{ $json.htmlContent }}",
"options": {},
"subject": "={{ $json.subject }}",
"toEmail": "recipient@example.com",
"fromEmail": "sender@example.com"
},
"credentials": {
"smtp": {
"id": "ugdxCdIOAuolzgAf",
"name": "SMTP account"
}
},
"typeVersion": 2.1
},
{
"id": "98246a8a-892e-495a-942a-a65cf778aa6e",
"name": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
-400,
-240
],
"parameters": {
"width": 160,
"height": 140,
"content": "选择您的时间范围。您希望自动化触发器多久运行一次?"
},
"typeVersion": 1
},
{
"id": "d33aef2f-0d61-4bcf-be98-415f74b3a6f3",
"name": "便签1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-180,
-240
],
"parameters": {
"width": 150,
"height": 140,
"content": "在 JavaScript 中设置您的品牌名称 + 添加您想要跟踪的查询"
},
"typeVersion": 1
},
{
"id": "757ae3e5-7559-41e5-955a-6d00a1df51d1",
"name": "便签2",
"type": "n8n-nodes-base.stickyNote",
"position": [
40,
-240
],
"parameters": {
"width": 160,
"height": 140,
"content": "将查询发送到 ChatGPT。我推荐使用 'chatgpt-4o-latest' 模型。您需要添加您的 API 密钥。"
},
"typeVersion": 1
},
{
"id": "7e954307-67f0-4dfd-88fc-9ec318ab8b9e",
"name": "便签3",
"type": "n8n-nodes-base.stickyNote",
"position": [
260,
-240
],
"parameters": {
"width": 150,
"height": 140,
"content": "此 JavaScript 节点分析从 ChatGPT 收到的每个响应。"
},
"typeVersion": 1
},
{
"id": "36c271c6-42cd-4a60-98bf-50ef2583c7c6",
"name": "便签说明4",
"type": "n8n-nodes-base.stickyNote",
"position": [
460,
-240
],
"parameters": {
"width": 170,
"height": 140,
"content": "连接您的 Google Sheets。别忘了在您的 Google Cloud 项目中启用 Google Sheets 和 Google Drive API。"
},
"typeVersion": 1
},
{
"id": "2e86ab49-b359-49b7-a1de-11eab4eb39e8",
"name": "便签说明5",
"type": "n8n-nodes-base.stickyNote",
"position": [
680,
-240
],
"parameters": {
"width": 160,
"height": 140,
"content": "此节点将所有原始数据转换为格式良好的电子邮件。无需更改任何内容。"
},
"typeVersion": 1
},
{
"id": "68bcb8bb-9d73-4e75-91ff-e04cc9fb1eb0",
"name": "便签 6",
"type": "n8n-nodes-base.stickyNote",
"position": [
920,
-240
],
"parameters": {
"width": 160,
"height": 140,
"content": "最后!替换占位符电子邮件并连接您的电子邮件。使用 Gmail?保留 smtp.gmail.com 作为主机。"
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"Daily Trigger": {
"main": [
[
{
"node": "Setup Queries",
"type": "main",
"index": 0
}
]
]
},
"Setup Queries": {
"main": [
[
{
"node": "Query ChatGPT (HTTP)",
"type": "main",
"index": 0
}
]
]
},
"Process Response": {
"main": [
[
{
"node": "Save to Google Sheets",
"type": "main",
"index": 0
}
]
]
},
"Query ChatGPT (HTTP)": {
"main": [
[
{
"node": "Process Response",
"type": "main",
"index": 0
}
]
]
},
"Generate Email Report": {
"main": [
[
{
"node": "Send Email",
"type": "main",
"index": 0
}
]
]
},
"Save to Google Sheets": {
"main": [
[
{
"node": "Generate Email Report",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
中级 - 人工智能, 营销
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
BrightData每周对比
使用Bright Data、GPT-4.1和Google Workspace的自动化网站变更监控
If
Set
Code
+15
35 节点Daniel Shashko
人工智能
新闻通讯管理 (n8n + Bolt.new)
职位通讯自动化系统 (N8N, Bolt.new, RapidAPI, Mails.so & ChatGPT)
If
Code
Gmail
+12
43 节点Joseph
人工智能
使用Bright Data、Google Sheets和Gmail追踪Google搜索排名
使用Bright Data、Google Sheets和Gmail追踪Google搜索排名
Code
Gmail
Http Request
+5
11 节点Daniel Shashko
营销
基于AI、Bright Data、Sheets和Slack的联盟竞争对手追踪与分析
使用AI、Bright Data、Sheets和Slack进行联盟竞争对手追踪与分析
If
Set
Code
+6
23 节点Daniel Shashko
市场调研
竞争价格监控与警报(Bright Data、Sheets 和 Slack)
使用 Bright Data、Sheets 和 Slack 进行竞争价格监控与警报
If
Set
Code
+9
29 节点Daniel Shashko
市场调研
CrunchBase 投资者数据
自动化投资者情报:CrunchBase到Google Sheets数据采集器
Code
Http Request
Google Sheets
+2
8 节点Yaron Been
财务
工作流信息
难度等级
中级
节点数量14
分类2
节点类型6
作者
Daniel Shashko
@tomaxAI automation specialist and a marketing enthusiast. More than 6 years of experience in SEO/GEO. Senior SEO at Bright Data.
外部链接
在 n8n.io 查看 →
分享此工作流